Zenn
👌

Maestroを用いたE2EテストでApp Checkを突破する方法

2025/03/28に公開
1

はじめに

Firebase App Checkは不正なクライアントが Firebase リソースにアクセスすることを防ぐための仕組みです。

iOS Simulator のような開発環境は不正なクライアントと見做されてしまうため、特別にデバッグトークンを App Check に登録する必要があります。
このデバッグトークンはデバイス毎に異なり、またアプリをインストールする度に新たに生成されます。

この新たに生成されるという挙動が Maestro でテストを実行する際に問題になります。

Maestro での問題

Maestro のように対象のアプリを自動操作して E2E テストを実行する際、Firebase リソースにアクセスするために App Check のデバッグトークンが必要になります。
しかし前述したようにデバッグトークンは毎回新たに生成されるため、テストのたびに手動で登録する必要が出てきます。

App Check の公式の方法として、Environment Variables の FIRAAppCheckDebugToken に任意の値を入れることで、任意のデバッグトークンを利用することはできます。

https://firebase.google.com/docs/app-check/ios/debug-provider?#ci
https://github.com/firebase/firebase-ios-sdk/blob/11.10.0/FirebaseAppCheck/Sources/Public/FirebaseAppCheck/FIRAppCheckDebugProvider.h#L73-L80
https://github.com/firebase/firebase-ios-sdk/issues/8851#issuecomment-952365817

しかし、この方法はあくまでxcodebuild testなど Xcode からアプリを実行する時にだけ有効になるものであり、既にインストールされたアプリを操作する Maestro では適用されません。

つまりなんとかして iOS Simulator の環境変数のFIRAAppCheckDebugTokenに値を入れる必要があります。

解決方法

実はSIMCTL_CHILD_というプレフィックスの環境変数は iOS Simulator に渡すことができます。
xcrun simctl bootの説明にも書かれています。

xcrun simctl boot
Boot a device or device pair.
Usage: simctl boot <device> [--arch=<arch>] [--disabledJob=<job>] [--enabledJob=<job>]

	--arch=<arch>           Specify the architecture to use when booting the simulator (eg: 'arm64' or 'x86_64')
	--disabledJob=<job>     Disables the given launchd job. Multiple jobs can be disabled by passing multiple flags.
	--enabledJob=<job>      Enables the given launchd job when it would normally be disabled.
	                        Multiple jobs can be enabled by passing multiple flags.


If you want to set environment variables in the resulting environment, set them in the calling environment with a SIMCTL_CHILD_ prefix.

その仕様を基にして以下のスクリプトを作成しました。
ポイントは SIMCTL_CHILD_FIRAAppCheckDebugTokenという環境変数を設定してから、iOS Simulator を起動することです。

# iOS Simulatorに渡したいFIRAAppCheckDebugTokenにプレフィックスを追加してexport
# ハードコードしていますが、実際は`.env`などから参照してコミットしないようにしましょう
export SIMCTL_CHILD_FIRAAppCheckDebugToken="17A9AC77-BE74-4DCA-8628-981D39E80785"

# テストを実行するiOS Simulatorの名前
# 事前にSimulatorは作成しておいてください。起動しておく必要はありません。
TEST_DEVICE_NAME="E2E Test"

# アプリをビルドする
# 今回はFlutterですが、別のフレームワークでも同じだと思います
APP_PATH="build/ios/iphonesimulator/Runner.app"
rm -rf "$APP_PATH"
fvm flutter build ios --debug --simulator --flavor stg

# シミュレータを起動する
# 既に起動している場合は再起動
TEST_DEVICE_UDID=$(xcrun simctl list devices --json | jq -r ".devices[][] | select(.name == \"$TEST_DEVICE_NAME\") | .udid")
xcrun simctl shutdown "$TEST_DEVICE_UDID" || true
xcrun simctl boot "$TEST_DEVICE_UDID"

# アプリをインストール
xcrun simctl install "$TEST_DEVICE_UDID" "$APP_PATH"

# Maestroを実行
maestro test .maestro/test.yml

# テスト用のiOS Simulatorをシャットダウン
xcrun simctl shutdown "$TEST_DEVICE_UDID" || true

参考

https://github.com/invertase/react-native-firebase/discussions/6184#discussioncomment-4365178

結果

最後のチャットっぽい画面に到達するためには Firebase Authentication で匿名認証が成功している必要があるので、無事にデバッグトークンで App Check を突破できていることがわかります。

https://youtu.be/9QF-ndrvSOw

https://github.com/KoheiKanagu/blooms/pull/277

GitHubで編集を提案
1

Discussion

ログインするとコメントできます