🎩

Maestro × EAS で始める React Native の E2E テスト

に公開

Maestro とは?

Maestro は、軽量で高速な E2E(End-to-End)テストフレームワークです。React Native / Flutter / iOS / Android などに対応しています。

YAML形式でシンプルにテストフローを記述でき、ユーザーの操作をそのまま再現するようなテストを書くことができます。公式docが分かりやすいという点も魅力の1つに感じました。

https://docs.maestro.dev/

第三者による資料で特に分かりやすいと感じたものを載せておきます。

https://speakerdeck.com/kgmyshin/uitesutohamoumaestrodeiinokamosirenaihua

https://tech.fusic.co.jp/posts/2023-10-29-maestro/

React Native(Expo)に導入する

expoのE2Eテストに関するdocで、Maestroが紹介されています。

https://docs.expo.dev/eas/workflows/reference/e2e-tests/

今回は以下の簡素なポケモン図鑑アプリでMaestroを使ってみます。READMEを読めばどんなアプリかイメージできると思います⭐

https://github.com/rikuyu/pokedex-react-native

まずは、eas.jsonと同じ階層に作った.maestroディレクトリにMastroのテストフローが書かれたymlファイルを配置します。

今回は以下の流れでテストします。

(a) アプリを起動 -> (b) Poke APIからポケモンが取得できていることを確認 -> (c) ピカチュウ(図鑑番号25番)の位置までスクロール -> (d) ピカチュウをタップ -> (e) ブックマークボタンOFFの表示を確認 -> (f) ブックマークボタン押下でローカルDBに保存 -> (g) 戻るボタン押下 -> (h) ブックマークタブに遷移する -> (i) ピカチュウが保存されていることの確認 -> (j) ピカチュウの詳細ページ遷移 -> (k) ブックマークボタンONの表示を確認

これをワークフローに書き起こすと以下になります。

bookmark-pokemon-flow.yml
appId: com.rikuyu.pokedex
---
- launchApp                    # (a)
- assertVisible:               # (b)
    id: "pokemon-1"
- scrollUntilVisible:          # (c)
    direction: DOWN
    timeout: 10000
    element:
      id: "pokemon-25"
- tapOn:                       # (d)
    id: "pokemon-25"
- assertVisible:               # (e)
    id: "bookmark-button-off"
- tapOn:                       # (f)
    id: "bookmark-button-off"
- runFlow:                     # (g)
    when:
      platform: android
    commands:
      - back
- runFlow:                     # (g)
    when:
      platform: ios
    commands:
      - tapOn:
          id: "ios-back-button"
- tapOn:                       # (h)
    id: "bookmark-tab-icon"
- assertVisible:               # (i)
    id: "bookmark-pokemon-25"
- tapOn:                       # (j)
    id: "bookmark-pokemon-25"
- assertVisible:               # (k)
    id: "bookmark-button-on"

Maestroの構文を知らなくても何をしているのか大体わかると思います。Maestro | Commands を見るとどんな操作ができるのか詳細が分かります。

No need to pepper your tests with sleep() calls. Maestro knows that it might take time to load the content (i.e. over the network) and automatically waits for it (but no longer than required).

Meastroのdocにも書いてある通り、非同期処理を待機する処理を記述しなくても良いことがすごく強力に感じます。

ワークフロー中のidはReact Native ComponentにPropsとして渡したtestIDの値です。(Textの場合のtestIDソース react-native Text.d.ts#L190 )今回は、Tamaguiを使っているのですが、TamaguiはReact NativeのPropsもサポートしているのでTamagui製コンポーネントにもtestIDを渡すことができます。

Maestro Studioというものもありますが、筆者は今回使いませんでした。

Maestro をローカルで実行する

プロジェクトのrootディレクトリで以下のコマンドを実行します。(Maestroをインストールしておく必要があります。)

$ maestro test .maestro/bookmark-pokemon-flow.yml

testrecordにすると実行の様子を録画し、mp4で出力してくれます。

$ maestro record .maestro/bookmark-pokemon-flow.yml

以下が実際の動画になります。

https://youtu.be/vb0sP0eAeis

EASで実行する

Expo Application Service を使うには、eas.jsonが必要なのでeas build:configureなどで生成します。

eas.jsonの記入例
eas.json
{
  "build": {
    "e2e-test": {
      "withoutCredentials": true,
      "ios": {
        "simulator": true
      },
      "android": {
        "buildType": "apk" // aabは非対応 で API level 26以上が必要
      }
    }
  }
}

あとはroot/.eas/workflows/にワークフローファイルを作成するだけです。

ymlの記入例
e2e-test-android.yml
name: e2e-test-ios

on:
  pull_request:
    branches: ['*']

jobs:
  build_ios_for_e2e:
    type: build
    params:
      platform: ios
      profile: e2e-test

  maestro_test:
    needs: [build_ios_for_e2e] # build_ios_for_e2eの完了を待機
    type: maestro
    params:
      build_id: ${{ needs.build_ios_for_e2e.outputs.build_id }}
      flow_path: ['.maestro/bookmark-pokemon-flow.yml']

手動実行したい場合は、eas-cliで実行します。

npx eas-cli@latest workflow:run .eas/workflows/e2e-test-ios.yml

Discussion