iOS の UI テストに Maestro を試してみる


# はじめに

UI 向けのテストツールはいくつかありますが、`Maestro` は後発？のツールです。
`DroidKaigi` の勉強会を発端？に SNS でも少し話題になっていたので、チームで試して見ました。

https://speakerdeck.com/kgmyshin/uitesutohamoumaestrodeiinokamosirenaihua

こちらは試してみた系の記事も出回っているので、重複した内容もあると思いますがお付き合いくださいmm
（半分は自分のメモようみたいな感じです、あしからず）


## Maestro とは？

UI テストを従来のもの（`XCUITest`）より簡単に書けるツールです。
具体的には指定された yml 形式で書くだけです。

https://maestro.mobile.dev/

タイトルは `iOS` ですが、`Android` もテスト可能です。
（フレームワークとしては `Flutter`, `React Native` も対応している）

さらにオープンソースになっており、無償で使うことができるのも面白い点です。

https://github.com/mobile-dev-inc/maestro

何か使い勝手で気になることがあれば、自分で PR を出しましょうw

# 試してみる

## - 導入

### 1. Maestro のインストール

以下のコマンドで実行してダウンロードします。

```
$ curl -Ls "https://get.maestro.mobile.dev" | bash
```

or

```
$ curl -Ls "https://get.maestro.mobile.dev" | zsh
```

### 2. パスのセット

maestro コマンドが使えるようにパスを通します。

```
$ export PATH="$PATH":"$HOME/.maestro/bin"
```

その後ターミナルを再起動しましょう。

```
$ maestro
```

と入力して、こんな感じの画面が出れば OK です。

![maestro コマンド](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/324fc216-078e-3ec5-eb1a-7306ef7fa4b8.png)


### 3. Facebook IDB のインストール

`Facebook IDB` は iOS の自動化を助けるためのツールです。
（なので Android で maestro を使う場合は不要）

https://github.com/facebook/idb

こちらを内部的に使用しているようなのでインストールします。
公式に沿って `Homebrew` で入れていますが、なんでも良いかと思います。


```
$ brew tap facebook/fb
$ brew install facebook/fb/idb-companion
```

### 4. Java のインストール

以下のサイトからダウンロードして、インストールしましょう。
（既にある場合は不要）

https://www.java.com/en/download/

![Screenshot 2023-12-22 at 20.45.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/7712f1eb-f3ef-aeb8-7d4b-46b2a3d951ce.png)

準備はここまで完了です。

## - サンプルの実行

自身のアプリに試しても良いですが、サンプルアプリとその設定をまずは動かす方が手軽です。
今回はそれを前提に行います。

### 1. シミュレータの起動

シミュレータがいないと**失敗する**ので、なんでも良いの立ち上げておきましょう。
（立ち上がっている端末でテストが実行される）

コマンドからは以下

```
$ open -a Simulator
```

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/7c5d30b7-4263-5bee-d199-ee8c3fd9a67a.png" width=200>

### 2. サンプルのダウンロード

以下のコマンドから落としてきます。

```
$ maestro download-samples
```

失敗する場合は、直に URL からダウンロードしましょう。→ **[Download Link](https://storage.googleapis.com/mobile.dev/samples/samples.zip)**

落としてきたら解凍しましょう。

```
$ cd ./samples
$ unzip sample.zip
```

### 3. サンプルのインストール

`Wikipedia.app` というのが用意されているので、シミュレータにインストールします。

```
$ xcrun simctl install Booted Wikipedia.app
```

このようにアプリがインストールされていれば OK です。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/12c0dfe9-248c-75c2-6971-ccced9ab337a.png" width=300>

### 4. テストの実行

あらかじめ用意された `ios-flow.yaml` があるので、それを実行するだけです。

```
$ maestro test ios-flow.yaml
```

こんな感じで実行されます。
（以下はサンプルから `yaml` を少し書き換えています）

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/1390c1c7-5278-b12b-28a3-c76b0399ca4f.png">

このようにターミナル上で、成功・失敗がアイコンで表示されます。

## - 自身のアプリで実行

### 1. 設定ファイルの作成

サンプルアプリからコピーしてくるのが早いです。
`Maestro` を使いたいアプリの ID を、`yaml` に設定してください。

【example】

```test.yaml
appId: bundle.id.xxx.yyy.zzz <- ここ
---
- launchApp
.
.
```

`yaml` 名はなんでも良いですが、管理しやすいような名前にしておくと良いです。

サンプルの `yaml` は、シンプルなものしかありません。より複雑な処理がみたい場合は、サンプルアプリ内にあるディレクトリに、別の `yaml` があるので探してみてください。

### 2. アプリのインストールと実行

ここからはサンプルと同じ流れです。

シミュレータにアプリがないと実行できないので、ビルドしてインストールしておきましょう。
先ほどと同じように、作成した`yaml` を実行するだけです。

```
$ maestro test test.yaml
```

### コマンドに関して

全てのコマンドを掲載しておきます。（2023.12）
必要に応じて公式リファレンスをみてください。

https://maestro.mobile.dev/api-reference/commands

以下、ざっくり勝手に分類しました。


【システム系】
`launchApp`：アプリの起動
`stopApp`：アプリの終了
`clearState`：アプリのデータをリセット
`addMedia`：デバイスに画像を追加
`setLocation`：ロケーションを設置（緯度・経度）
`travel`：ユーザーの動きをセット（緯度・経度とその移動）
`startRecording`：画面収録の開始
`stopRecording`：画面収録の終了
`takeScreenshot`：スクリーンショットをとる
`evalScript`：JSの実行（yaml 内に直接記述する）
`runScript`：JSの実行（ファイルの参照）
`runFlow`： 別 yaml を実行する

【動作系】
`tapOn`：ボタンタップ
`doubleTapOn`：ダブルタップ
`inputText`：値の入力
`eraseText`：入力の削除（フォーカスが当たっている前提）
`copyTextFrom`：テキストをコピー
`pasteText`：テキストを貼り付け
`hideKeyboard`：キーボードを隠す
`pressKey`：アプリ外の物理的な操作を行う（ホーム、ロック、ボリュームなど）
`openLink`：URLを開く（Androidはオプションあり）
`repeat`：操作を繰り返す
`scroll`：スクロールする
`scrollUntilVisible`：表示されるまでスクロールする
`swipe`：スワイプする


【テスト系】
`assertVisible`：表示の確認
`assertNotVisible`：非表示の確認
`assertTrue`：値が True or 空 の確認
`extendedWaitUntil`：表示されるまで待つ
`waitForAnimationToEnd`：アニメーションが終わるまで待つ

【iOSのみ】
`clearKeychain`：キーチェーンのクリア

【Androidのみ】
`back`：前の画面に戻る（Android のみ）

今回はコマンドのみですが、他にも多くのオプションなどがあるので、それを駆使してフローを組みましょう。

## - 開発のTips

### Maestro Studio を使う

アプリ起動中に `Maestro Studio` を使えば、`yaml` を書く手助けをしてくれます。
以下を実行すると、WEB が立ち上がり操作できます。

```
$ maestro studio
```

立ち上がった WEB には今開いているアプリの画面が出てきます。

![Screenshot 2023-11-13 at 13.34.07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/f69d1800-fcfd-50be-ad11-89f475099d64.png)


例えば、テストで
「この場所をタップしたいな〜」
みたいなことを考えたときに、WEB 上でその`ID`、`座標`などを取得できます。

また、そのまま `yaml` として設定して、順序をつけたりして書き出すこともできる！便利！


### テストの複数実行

#### 方法①

基本的には、同時にいくつかの UI テストを行いたいはずです。

![Screenshot 2023-11-13 at 14.00.29.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/ff80131c-3400-300b-36ba-b599e457d826.png)


その場合は、実行時に `yaml` が複数入っているディレクトリを指定することで全てのテストを実行します。


```
$ maestro test maestro_yaml
```

このように、`yaml` ファイルごとにテスト結果を得ることができます。

![Screenshot 2023-11-13 at 14.07.49.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/15c027c5-82c4-3072-f48f-2d5421f83469.png)

ただし、ディレクトリの `A~Z` 順に実行されてしまうため、命名規則を気をつける必要が出てきます。

そこで、親 `yaml` を作って、こちらで順番を指定する方法もあります。


#### 方法②

`yaml` を分割して、`runFlow` で指定する方法です。

```.yaml
- runFlow: another_flow.yaml
```

テストケースを増やすと、同じようなストーリーが出てくると思います
-> ex 起動してからチュートリアルを突破する

これを別 `yaml` として書き出して呼び出すことができます。

```.yaml
appId: xxx.yyy.zzz
---
- launchApp:
    clearState: true
- runFlow: "flow_tutorial.yaml"
- runFlow: "flow_xxx.yaml"
- runFlow: "flow_yyy.yaml"
```

また、方法①と違い、自分で順番を指定できるのも良い点！

### 失敗時のデバッグ

失敗時にはスクリーンショットが記録されます。
-> ディレクトリ：`~/.maestro/tests/<datetime>/`（Macの場合）


また、出力先は自分で変更できます。

```
$ maestro test --debug-output /path/to/debug/logs
```


## - 課題

### 構造が深い画面でのエラー

必ずではないですが

- `SwiftUI` で View のネストが深い画面
- ViewController を複数重ねるような画面

など `Maestro` 側でヒエラルキーを判断できないことがあります。

【example】

![maestro studio](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/175242/492d4222-1d8e-ae9a-54ac-c289b7b9283b.png)


> Retrieving the hierarchy is taking longer than usual. This might be due to a deep hierarchy in the current view. Please wait a bit

# 終わりに

半分は自分へのメモも兼ねているので、これから記事をもう少しだけアップデートしていくつもりです...🙏

いくつか UI テストのツールや、`XCUITest` を書いたことはありますが、比較的扱いやすいと感じました。個人アプリなどでさくっと導入するにはかなりおすすめです。企業が使う大きいアプリでは、多くの修正が入るため、メンテコストもかかると思います。

画面表示系の動作テストを書くというよりは、

- URL Scheme での遷移
- 状態によって変わる画面遷移

etc.

など、あまり UI の変更には左右されないが、大事な機能をテストとして書くと、有用性が高いかなと感じています。

# 引用

https://qiita.com/Seo-4d696b75/items/dadd62fab4545b7fad58

https://zenn.dev/tellernovel_inc/articles/79c261b52daed8