Autify のしくみ

[Autify Recorder]:https://help.autify.com/docs/ja/autify-recorder
[Autify AI]:https://help.autify.com/docs/ja/autify-maintainance-ai
[WebDriver]:https://www.w3.org/TR/webdriver/
[Element Click]:https://w3c.github.io/webdriver/#element-click

# はじめに

:::note warn
公式ドキュメントを調べたり、サポートの方に聞いたりした情報でまとめてはいますが、コード等を見れてはいない為正確でない情報もあります。もし誤った情報を書いておりましたらご指摘下さい。
:::

Autify でテストがエラーになったけど、原因が分からない！ということありますよね。

明確にエラー (500 とか) が発生していると、そんなに解析に苦労はないのですが、例えば「ボタンをクリックしたけど画面が進まなかったり」が発生すると

* Autify がボタン押せてないのかな
* この瞬間 disabled だったりしたのかな
* ボタンは押せたけど、サーバー応答がないのかな

テスト対象サービス側でログを確認するのが筋かと思いますが、まず初手では「Autify の操作がどこまで確実に行われたか？」を知りたくなりますね。

Autify はなんとビデオ録画をしてくれるので、これで大部分は分かりますが、どうしても画面に現れない部分は解明が難しくなります。

<img width="400" alt="Pasted_Image_2024_06_11_10_59.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60131/aeaa1be7-86cd-0dfb-5e3c-53691c7468cf.png">

そこで本記事では、Autify の公式ドキュメントの内容やサポートに問い合わせて分かった仕組みをまとめてみたいと思います。

# 概要

Autify は [WebDriver] を用いることで、ブラウザを介したサービスの自動操作を実現しています。

テストシナリオを作るプロセスでは [Autify Recorder] が、ブラウザ上でレンダリングされたサービスの DOM 木構造を解析・記録します。

テスト実行プロセスでは [Autify Recorder] によって記録された DOM 木構造情報を元に、操作（クリックなど）すべき HTML 要素を [Autify AI] が発見し、[WebDriver] API を介してブラウザ操作を実現します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60131/11067325-2c5f-1f13-c0a5-9e5b6dae6ee1.png)

:::note warn
もしかしたら、Recorder プロセスでは [WebDriver] は使っていないかも... (未確認)
:::

# 詳細

## Autify Recorder

Autify では [Autify Recorder] を使って、ブラウザ操作をするだけでテストシナリオを作成できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60131/be173485-9568-6839-007f-adebba31f193.png)

このプロセスでは、各ステップにおいて **ブラウザ操作をする直前の画面全体の DOM 木構造を記憶する** ということをしています。

* Element 間の親子関係。操作対象の Element だけでなく DOM 木構造全体を記録している
* Element そのものの特徴
    * id
    * class
    * text node 値

https://help.autify.com/docs/ja/autify-maintainance-ai

:::note
SikuliX 等の自動化ツールとは異なり、Autify は画像一致比較をしているのではありません。あくまで DOM 木構造の一致（類似度）をメインに見ているようです。
:::

## Autify テスト実行

### Flowchart

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60131/67bb8796-26a9-315e-d140-df7e3506af75.png)

### 1. DOM 木構造を比較する

Autify はまず始めに、過去に記録しておいた DOM 木構造と、現在実行中のテストのそれが一致するかを検証します。

![Pasted_Image_2024_06_11_11_50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60131/e463e93c-6ce8-c480-cf38-a23046177fef.png)

:::note warn
この画面の見た目上、画像一致検査をしている気分になるが、実はそうではないです。
:::

みなさんが開発しているサービスに変更を加えた場合（特にUX面の）、この木構造一致はしなくなります。

その場合は即座にエラー `要素が見つからない` となるのではなく、後述する [Autify AI] による類似検索が行われます。

#### Autify はローディングを待てる

一般的に E2E テストには、画面が期待する状態になるまでの **待ち時間** が存在します。

Autify ではこのフェーズが待ち時間にあたり、期待する DOM 木構造が現れるまで一定時間を待ってくれます。

:::note warn
なので、sleep が必要になることは基本的にありません。sleep はなぜそれが必要か？ちゃんと説明できる場合にのみ使うべきです。
:::

例えば、ローディング中は、画面全域に `<div>` 要素 (fixed, z-index > 1) をかぶせて操作出来ないようにする〜、ことはわりと良くあるケースだと思います。

一見すると *「操作対象のボタンが画面に現れた時点で、Autify がクリックしたけど Loading 中で押せない」* という事象が発生しそうなものですが、実際には Autify は前述の通り DOM 木構造全体を見ているので、Loading 表示 `<div>` がある状態を「木構造が一致していない」とみなして消えるのを待ってくれます。

https://help.autify.com/docs/ja/sleep-step

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60131/cf87498a-41f9-5efa-4cf4-2e15c0d4faa2.png)

### 2. AI・機械学習を用いて最も類似度の高い要素を選択する

前プロセスの [1. DOM 木構造を比較する](#1.DOM木構造を比較する) で完全一致が見込めない場合、Autify は次に AI・機械学習を用いた類似検査を実施します。

https://help.autify.com/docs/ja/autify-maintainance-ai

現在テスト実行中の DOM 構造木から、Element を一覧してみるわけです。そして見つけたい操作対象の Element との類似度順に並べ替えます。そして一番類似度の高かった物を選択するのだと思われます。

:::note
この場合も対象の Element の特徴だけでなく、近隣の Element との関係性も含めた類似度を算出しています。
:::

<img width="300" alt="image.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60131/65b28185-e768-ba1f-0cb2-b7efd1293233.png">

最終的に選択した要素の類似度が、Autify の定める閾値を上回っていた場合に次の操作に進み、そうでない場合はエラー `要素が見つからない` となります。

ここのプロセスで主に以下２パターンの Autify テストの失敗が発生することが多いですね。

1. 要素が見つからないエラーになる
1. 誤った要素が選択されてブラウザ操作が行われた結果、その後のテスト Step も期待しない動作になる

### 3. WebDriver API でブラウザ操作を実行

前述のプロセスで無事に要素が発見できると、いよいよ自動ブラウザ操作が行われます。

Autify はブラウザの操作は [WebDriver] API を介して行っています。例えばリンクやボタンのクリック操作等は以下の [WebDriver] API を利用しているそうです。

https://w3c.github.io/webdriver/#element-click

この [Element Click] 操作では (JavaScript API での直接的な Click event 発火とは異なり)、実際にブラウザ操作を行った場合と動作に差異が発生しないよう考慮されています。

* クリック対象の要素が、別の要素に隠れている場合 (e.g. z-index) はエラーになる
* クリック対象の要素が、viewport 内にない場合はエラーになる

![c124b678-7fe9-6b3c-be1e-4dde88f6ad92.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/60131/16ca1947-b69e-b872-7bd3-5e5c8c3dbfdc.png)

また、クリックなどのブラウザ操作に失敗した際は、一度でエラーになるのではなく間隔をあけて何度か再試行をします。

# おしまい

最後まで見てくれてありがとうございます😆

改めてですが、コードを見れていない等、調査にあたってできる範囲に限りがありましたので、この記事は一部正確でない情報を含んでいるかもしれません。ご了承下さい🙇‍♂️