GameWith Developer Blog

GameWith のエンジニア、デザイナーが技術について日々発信していきます。

Autifyの結果画面にフィルタ機能を付与するChrome拡張を作ってみた #GameWith #TechWith #Autify

この記事は GameWith アドベントカレンダー2022 23日目の記事です。

サービス開発部のdanaです。
5日目の記事に続いてAutifyを利用している上で工夫した話第2弾で、 今回はAutify用にChrome拡張機能を作成した話になります。

GameWithではAutifyを利用しています

autify.com

改めてのご紹介となりますが、Autifyは画面操作を録画してテストを作成し、AIを用いたテスト実行を行ってくれる便利なサービスです。
詳細は前回の記事をご覧ください。

tech.gamewith.co.jp

テスト実行時間が気になる

テスト完了後に通知が来るため気にする必要が無いのが良い点なのですが、最適化したくなってしまうのはエンジニアだからでしょうか。
簡単な内容にも関わらず時間がかかっているステップが存在していたりすると改善したくなってしまいます。

何故遅い?

Autifyの中の人ではないので詳細の原因は不明ですが、似た要素が複数同じ画面にある場合に遅くなっているようです。
また、メリハリがないページでも時間がかかってしまうように感じました。

改善方法

基本的にはCSSセレクターを設定することで1秒未満に改善する事が多いです。
また、前回の記事の例でも出したセレクタを具体的に設定できないパターンはJSでチェックするように変更したりしています。
時間のかかるセレクタを指定できないステップはたびたび誤った要素でテストして精度低下を招いていたため、JSチェックは安定性の面でも有用です。

対象を絞り込みたい

改善手順としてはどのステップが遅いのか確認するためにテスト結果画面で30秒を超えるステップを探し改善。
続いて10秒を超えるステップの改善のようにメリットが大きいステップから修正していきます。
しかし、何度も実施していると探すのが面倒だなって思うようになってきます。
ということで、Chrome拡張機能を作成してみました。

作成したChrome拡張

github.com

この拡張機能はAutifyのテスト結果画面にフィルタを追加して、指定秒数以上となるステップのみ表示できるようにします。
※お見せできない要素が数多くあるため、内容をマスクしています。

Chrome拡張機能の作り方

静的埋め込み拡張のサンプルです。
詳細はドキュメントをご確認ください。

developer.chrome.com

最小構成で開発する

必要なファイルは manifest.json 及び 実行するためのJSやCSSファイルです。
今回であればJSファイル1つ、CSSファイル1つです。

  • name
    • 拡張機能の名前を設定します(拡張機能一覧画面で表示されます)
  • description
    • 拡張機能の説明を設定します(拡張機能一覧画面で表示されます)
  • version
    • 任意の値を設定してください
    • 1.0.0 でも 0.0.1でもOKです
      • バージョンアップを行う際、ここの値を増加させる必要があります
  • manifest_version
    • 3を指定します。
    • v2で作成された拡張機能が非推奨になると告知されています
      • 以前は2023/01で非推奨となる予定だったそうですが、延期されているようです。
  • content_scripts
    • 読み込みを行うページ指定や、読み込むファイルの指定などを行えます
    • 特定ページだけ実施したい場合はmatchesに対してURLを記載します
      • ワイルドカード指定が可能です
    • JSを読み込みたい場合はjsを定義し、ファイル名を記載します
    • CSSを読み込みたい場合はcssを定義し、ファイル名を記載します

今回の拡張機能の場合は以下のようになります。

{
    "name": "Autify Result Filter",
    "description": "Autify Result Filter",
    "version": "1.0.0",
    "manifest_version": 3,
    "content_scripts": [{
        "matches" : [
            "https://app.autify.com/projects/*/results/*/capabilities/*/scenarios/*"
        ],
        "css": [
            "css.css"
        ]
        "js": [
            "content.js"
        ]
    }]
  }

拡張機能の内容

この拡張機能で行っている内容は大まかに3点です

  • 要素を追加できる状態か確認する
  • input要素とテキスト要素をJSで追加する
  • 追加されたinput要素の数値が変動したときにフィルタする

要素を追加できる状態か確認する

Autifyの結果画面は動的に描画されるページですので、追加先要素が存在するかチェックが必要です。
親要素が存在したら作成した要素を追加し、存在しなければ待つ関数を実行します。
今回は500ms毎に要素の確認を行い、10回見つからなかったら諦めるようにしています。

    const appendElemByTargetElem = (retryCount = 0) => {
        const elem = document.getElementsByClassName("result-meta-list")[0];
        if (!elem) {
            if (retryCount > 10) {
                console.log("要素が見つかりませんでした");
                return;
            }
            setTimeout(() => {
                appendElemByTargetElem(retryCount + 1);
            }, 500);
            return;
        }
        appendElem();
    };
    appendElemByTargetElem();

input要素とテキスト要素をJSで追加する

VanillaJSなので愚直にDOMを作成して必要な要素を設定し追加します。

        const input = document.createElement("input");
        input.setAttribute("type", "number");
        input.setAttribute("name", "filter");
        input.setAttribute("id", "result-fillter-input");
        input.setAttribute("value", 0);
        input.onchange = filterResult;

追加されたinput要素の数値が変動したときにフィルタする

非標示となる要素に自分で作成したd-noneクラス名を付与します。
今回であれば入力された数値未満の秒数のステップに付与しています。
対象の絞り込み方は前回の記事でご紹介した手法を用います。

また、フィルタ関数が呼ばれるたびにd-noneクラスがついている要素からd-noneクラスを削除し、改めて設定し直します。

    const filterResult = () => {
        const sec = document.getElementById("result-fillter-input").value;
        if (Number.isInteger(sec)) { return; }
        Array.from(document.getElementsByClassName("d-none"))
            .forEach(v => v.classList.remove("d-none"));
        Array.from(document.getElementsByClassName("scenario-step"))
            .filter(v => (Number)(v.getElementsByClassName("scenario-step-time")[0].innerText.replace("秒", "")) < sec)
            .forEach(v => v.classList.add("d-none"));
    };

cssファイルの中身

今回は要素を非標示にしたいだけなので1つだけCSSクラスを定義しました。
他のページなどで利用したい場合に、同じクラス名で被ることがある可能性がありますので、先頭にユニークな文字列を追加するのも有効かもしれませんね。

d-none {
    display: none;
}

動作確認

Chromeの拡張機能設定を開き、右上にあるデベロッパーモードをONにします。
その後パッケージ化されていない拡張機能を読み込むを選択し、srcディレクトリを指定します。

※manifest.jsonが存在するフォルダを指定すればOKです

正しく追加すれば画像のように拡張機能一覧に追加されます。

追加後にAutifyテスト結果ページにアクセスすると、拡張機能で作成した要素が追加され利用できるようになっているはずです!

まとめ

作業効率化も兼ねて最新のChrome拡張機能の作成を試してみました。
シンプルな拡張機能なのでサクッと30分程度で動くところまで作ることができ、その分作業に専念できるようになったので良かったです。
欲を言えばAutify開発の方がこの記事を見て、機能として組み込んでくれたら嬉しいなと思います。