Next.jsで作ったアプリのテストをT-DASHで自動化してみた

# はじめに

この記事は、Qiita Engineer Festa 2023 「[コマンドライン実行機能が実装される「T-DASH」を使って、CI/CD連携をしてみよう！](https://qiita.com/official-events/7fec21cc6f0e98587570)」に参加するために作成した記事です

# 概要

テストのやり方はプロダクトによって様々です
しっかりやるとそれなりにメンテナンスコストがかかるので悩むところかと思います

今回は手軽に導入できてすぐに運用可能な自動テストツール「T-DASH」を使ってみます
T-DASHを使ってどれだけ簡単にテストを自動化できるのかを紹介します！

## やりたい事

以下の3つをT-DASHでやっていこうと思います！

- E2Eテスト
    パターン別でフォーム申請できる事をテストする
    
- スナップショットテスト
    レスポンシブでUIが崩れていないかをテストする
    ブラウザ別でも同じUIになっているかをテストする
    
- GithubのCI/CD連携
    GithubとT-DASHを連携して、プルリクエスト作成時にテストが実行ができる事を確認する
    

# アプリの準備

T-DASHのテスト用にNext.jsで簡単なアプリを作成しました！
その名も「PS5くださいフォーム」…！笑
※イベントの景品がPS5の為

こちらのアプリに対してT-DASHでテストを作ります

https://github.com/git-gen/ps5-kudasai-form

![アプリスクショ.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/3843aaf5-3343-355a-0ff9-f41a905ba34c.png)
アプリは以下の様な仕様となっています

- 入力・確認・完了の3画面構成のフォーム
- 全ての項目に入力がない場合は画面を移れず、エラーメッセージを表示する
- 入力画面・確認画面は簡単なレスポンシブ対応をしている
- 全てのブラウザで同じUI表示になるようにしている（リセットスタイルの適用）

![アプリgif.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/f7f46e41-8065-7b2e-6455-87ae3faeb6db.gif)

# T-DASHのセットアップ

まずはT-DASHのインストール・初期設定をします
今回はMacへの導入方法を記載しますが、Windowsの場合でも公式にマニュアルがあるので、
それを見れば簡単にインストールできるかと思います

1. **T-DASHをダウンロードする**
    T-DASHのトライアル申し込みページから利用申請を行います
    [トライアルお申し込み](https://service.valtes.co.jp/t-dash/request)
    申請後に指示に従って進めるとT-DASHのダウンロードリンクに行き着くので、
    そこからダウンロードする事ができます
    ![セットアップ1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/61889246-72b1-dd33-b0d5-f1dba565fdf8.png)
    
2. **T-DASHのインストール（Mac）**
    同封されているPDFマニュアルに詳しくは記載されているのでそれに従えばいいです
    ダウンロードしたファイルの`t-dash_*.dmg`、`tdashcap-*.dmg`の二つをインストールすれば終わりです
    
3. **Pythonのインストール**
    インストールしたT-DASHが`localhost:8686`で立ち上がります
    動作環境としてPythonがインストールされている必要があるので、
    別途インストールしてパスを入力します
    ![セットアップ2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/d7d362a8-33a0-2075-0bfa-997b642b6c7d.png)
    Pythonの設定が終わるとホームディレクトリのT-DASHフォルダにファイルが生成されます
    T-DASH内でプロジェクトを作成してもこのフォルダ内に生成されるようです
    ![セットアップ3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/169647b3-aebc-941b-b53e-4d4fb942c1f4.png)
    
4. **サンプルプロジェクトでテスト**
    T-DASHにはデフォルトでサンプルアプリが入っていて、
    一通りのテスト内容が全部登録されていますので実行するとテストの様子がすぐに見れます
    （勝手にブラウザが立ち上がって色々自動で操作されるテストが始まります）
    ![セットアップ4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/452056af-de14-80a2-4dc1-38ae02ae71c2.png)
    ちなみにサンプルアプリの内容はこんな感じ
    Storybookとかを使っているプロジェクトであれば、
    このサンプルアプリと同じように簡単にコンポーネントテストもできそうですね！
    ![セットアップ5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/ea036cfe-8e8f-5073-aa29-ba7c9d7b4cb3.png)
    

これでT-DASHのセットアップは終わりです！
申請から20分もあればテストを試すことができちゃいます！

# T-DASHのテスト

用意したアプリに対してT-DASHでテストを作ります
公式でマニュアルが用意されているのでこれに沿って進めます

https://service.valtes.co.jp/t-dash/function/tutorial/testexecution_vol_001

まずはすごく単純に「アプリを開いてボタンを押す」というテストを作ってみます！

1. **プロジェクトを作成する**
    新しくプロジェクトを作成します
    ![テスト1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/11650f47-aa16-e98d-ffc3-69cd65f69837.png)
    作成したプロジェクトを開くと以下のようなページが開きます
    サイドバーの項目ごとの機能はざっくりこんな感じです
    
    - ダッシュボード
        テストの実施状況を確認する事ができ、
        全体での成功率などをグラフで表示する事もできます
        
    - テストスイート
        テストスイートはテストケースをまとめたものを指します
        ここにテストのシナリオを作って1つのテストスイートとして管理します
        
    - テストラン
        テストスイートをまとめて実行する事ができます
        また、外部連携を行う場合はテストランを作る必要があります
        
    - 画面定義
        テストするアプリをURL毎に管理する事ができます
        画面毎にどの要素が特定のUIになるかを設定できます
        
    - 動作定義
        「画面のURLをブラウザで開く」「テキストを入力する」などの、
        テストスイートで使用するテストに使用する「操作」を管理できます
        
    
    ![テスト2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/d4c9eef8-3a2b-5941-01f3-6931b1207397.png)
    
2. **テストスイートを作成**
    
    次にテストスイートを作成します
    
    テストスイートを作成すると以下のような画面になるので、
    テストケースを作成からテストシナリオを追加していきます
    ![テスト3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/912a9f49-bb41-ed84-e130-3f45e75e77d6.png)
    テストスイートの作成は、
    直感的にわかりやすい仕様なので説明は不要かと思います
    
    以下の内容でテストスイートを作ってみました！
    
    アプリを開く
    ↓
    フォームの「名前」に入力
    ↓
    フォームの「内容確定ボタン」を押下
    ↓
    入力内容が足りていないので「エラーメッセージ」が表示される
    
    ![テスト4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/8809199d-b955-d03e-2a8d-ff7a4c4909d7.png)
    
3. **画面定義を作成**
    最後に画面定義を作成します
    画面定義に移動するとテストスイートで定義した「フォーム」が追加されているので、
    それを選択してその画面が表示される「URL」を入力して画面キャプチャを押下します
    ![テスト5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/ddcbca21-016f-f458-cade-d87b6b6e2c95.png)
    画面キャプチャツールが起動するので、
    このツールでどの要素がどのUIに当てはまるのかを紐づけます
    ![テスト6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/6136da60-12af-050d-f8b3-202ea2aaa100.png)
    
4. テストを実行する
    これでテストスイートが完成です！
    テストスイートに戻ってテストを実行してみました！
    ![ボタンを押すテスト.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/dab8329f-d7fd-d35f-f766-7ffb84040d2a.gif)
    

## 機能テスト

アプリのテストをしっかり作ってみます
先ほど作成したテストと同じ様にテストスイートを作成するだけです！

- 作成したテストスイート
    フォーム入力
    ↓
    フォーム入力失敗
    ↓
    フォーム入力
    ↓
    フォーム内容確認
    ↓
    フォーム再入力
    ↓
    フォーム内容確認
    ↓
    フォーム申請完了

![機能テスト1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/3dbb0d07-6f0c-0e7f-56eb-02bf4bf1de80.png)
実行した結果がこちら！
![機能テスト.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/4ef60b7a-ecd4-0a09-f2f0-3e31251342dc.gif)

## スナップショットテスト

スナップショットテストとは名前の通り、
想定している画面のスナップショットを予め用意しておいて、
テストでレンダリングされた画面と想定しているスナップショット画像を比較するテストです

T-DASHでも「画像比較検証」という方法で同じような事ができるので、
これを使って以下のテストをしてみようと思います！

- レスポンシブでUIが想定通りの動きをしているかのテスト
- ブラウザ毎でUIに違いがないかのテスト

まずは想定している画面のスナップショット「期待画像」を準備します
入力画面と確認画面の2つを用意しました

|入力画面の期待画像|確認画面の期待画像|
|---|---|
|![screenshot_form.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/3c18660a-45a8-50ec-de27-c6dd2d3ae7ca.png)|![screenshot_confirm.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/4c1df077-0c71-37bf-5408-7797e49f48a5.png)|

次に「画像比較検証」のテストスイートを作成します
使う操作は3つで以下の様に使用します

- [ブラウザ制御]現在のブラウザサイズを変更する
    - メディアクエリーで画面UIが変化するサイズまで画面サイズを調節する
- [画像認識操作]現在の画面と機体画像を比較する
    - 期待画像とレンダリングされた画面の差分をチェックする
- [画像認識操作]比較した画像の一致率が指定%以上であることを検証する
    - 期待画像とレンダリングされた画面の一致度を測定する

今回は予め期待画像をローカルに用意していますが、
テストスイートの中でスナップショットを用意する事も可能です
![スナップ1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/a2bcca03-caea-915f-3731-91954d109e7a.png)
テストスイートを実行すると「テストレポートを開く」から、
テスト結果の詳細を確認する事ができます
![スナップ2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/9cd57d39-702e-9cf5-2039-910544eba61f.png)
こちらで表示されている画像は、
左から「レンダリング結果」「期待画像」「検証差分」となります
検証差分は画面全体が黒くマスクされていて、
白くなっている部分だけが差分となります

|入力画面の画像検証結果|確認画面の画像検証結果|
|---|---|
|![スナップ3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/186cc160-c105-a76f-10ed-67994dbcc5a1.png)|![スナップ4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/e587b038-fee1-6b42-bfd7-c7c785bee2eb.png)|

ブラウザ別で確認する方法はテストランを作る事で可能です
環境毎にテストランを作成したら
![スナップ5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/c44d1299-088b-b4c2-350b-69f41da1f4b9.png)
テストランで実行するテストスイートを紐付けて
![スナップ6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/9f339ebc-dbea-1989-a790-b08a9e85f1bf.png)
ブラウザ毎で同じ様にテストランを作成する事で、
簡単にブラウザ事でのテストを作る事が可能です

![スナップ7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/2038ed20-777f-4c4b-179d-568bf398004b.png)

## GithubのCI/CD連携

T-DASHとGithub Actionsを連携させて、PR作成時に自動テストをさせてみます
連携方法は公式でマニュアルが用意されているのでこれに沿って進めます

https://service.valtes.co.jp/t-dash/function/tutorial/commandline_vol_004

まず初めにリポジトリですが、
リポジトリフォルダ内にsyncファイルというT-DASHのプロジェクトからエクスポートしたファイルを置かなくてはいけない為、
プライベートリポジトリを使用します

こちらのリポジトリをコピーしてPrivateリポジトリを作っておきます

https://github.com/git-gen/ps5-kudasai-form

次にT-DASHからsyncファイルをエクスポートして、
作成したリポジトリにpushします
![CI1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/92770ed1-b2aa-7b1c-4330-23e34a7424dd.png)
さらにQUINTEEマイページからコマンドラインツールをダウンロードして、
ダウンロードしたファイルの中の「tdashbeta」というファイルもリポジトリにpushします
（QUINTEEマイページは最初にT-DASHをダウンロードしたページ）
![CI2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/84890377-5c68-5ed6-10cb-d3682d263247.png)
そして最後に`.github/workflows`に任意の名前でymlファイルを追加する
内容はマニュアルに載っていたものとほぼ同じ

```yaml
name: T-DASH

# ワークフローのトリガーは以下を参照して変更してください
# このチュートリアルでは手動実行するトリガーとしています
# https://docs.github.com/ja/actions/using-workflows/events-that-trigger-workflows
on:
  workflow_dispatch:

env:
  TDASH_ROOT_PATH: "$HOME/AppData/Local/Programs/T-DASH"
  TDASH_CMD_EXE_PATH: "$HOME/AppData/Local/Programs/T-DASH/tdash.exe"
  TDASH_BETA_ZIP_PATH: "/tdashbeta/tdashbeta.zip.001"
  TDASH_BETA_EXE_NAME: "tdashbeta.exe"
  ZIP_INSTALLER_URL: "https://www.7-zip.org/a/7z2300-x64.exe"
  ZIP_INSTALL_EXE_PATH: "7zip/7z2300-x64.exe"
  ZIP_EXE_PATH: "C:/Program Files/7-Zip/7z.exe"
  REPORT_PATH: "C:/Users/runneradmin/AppData/Local/Programs/T-DASH/projects/commandlinetestrun/reports"

jobs:
  build:
    runs-on: windows-latest

    steps:
    - name: Checkout
      uses: actions/checkout@v3.5.2

    - name: Setup Chrome (Test browser)
      uses: browser-actions/setup-chrome@v1.2.0
      with:
        chrome-version: latest

    - name: 7-zip install
      run: |
        New-Item -Path "7zip" -ItemType Directory
        Invoke-WebRequest -Uri "${{ env.ZIP_INSTALLER_URL }}" -OutFile "${{ env.ZIP_INSTALL_EXE_PATH }}"
        Start-Process -FilePath "${{ env.ZIP_INSTALL_EXE_PATH }}" -ArgumentList "/S" -NoNewWindow -Wait

    - name: T-DASH cmd decompress
      run: |
        cmd /c "${{ env.ZIP_EXE_PATH }}" x -o${{ github.workspace }} "${{ github.workspace }}${{ env.TDASH_BETA_ZIP_PATH }}"

    - name: make root dir
      run: |
        # T-DASHルートディレクトリがない場合は作成
        if (-not (Test-Path -Path ${{ env.TDASH_ROOT_PATH }})) {
          New-Item -Path ${{ env.TDASH_ROOT_PATH }} -ItemType Directory
        }

    - name: T-DASH cmd copy
      run: |
        $sourcePath = '${{ github.workspace }}/${{ env.TDASH_BETA_EXE_NAME }}'
        # 実行ファイルが存在する場合は削除
        if (Test-Path ${{ env.TDASH_CMD_EXE_PATH }}) {
            Remove-Item ${{ env.TDASH_CMD_EXE_PATH }} -Force
        }
        Move-Item $sourcePath ${{ env.TDASH_CMD_EXE_PATH }}

    - name: Run initial setup
      run: |
        # T-DASHの実行環境はexeを実行したフォルダに作成されるためカレントディレクトリを移動する
        cd ${{ env.TDASH_ROOT_PATH }}
        # T-DASHの実行環境構築
        Start-Process -FilePath ${{ env.TDASH_CMD_EXE_PATH }} -ArgumentList "setup","--silent" -NoNewWindow -Wait

    - name: Run the application
      run: |
        # リポジトリ管理しているテストを実行するsyncフォルダパス
        $sourcePath = '${{ github.workspace }}\sync'
        # コマンドライン実行するテスト実行環境のsyncフォルダパス
        $destinationPath = '${{ env.TDASH_ROOT_PATH }}\projects\commandlinetestrun\sync'
        # 共有フォルダが既に存在する場合は一度フォルダごと削除する
        if (Test-Path $destinationPath) {
            Remove-Item $destinationPath -Recurse -Force
        }
        # リポジトリのsyncをコマンドライン実行テスト環境のsyncへコピー
        Copy-Item $sourcePath "${{ env.TDASH_ROOT_PATH }}\projects\commandlinetestrun\" -Recurse -Force
        cd ${{ env.TDASH_ROOT_PATH }}
        # テスト実行
        Start-Process -FilePath ${{ env.TDASH_CMD_EXE_PATH }} -ArgumentList "testrun","ホテルテストラン","--background" -NoNewWindow -Wait

    - name: Save results to artifacts
      uses: actions/upload-artifact@v3.1.2
      with:
        name: results
        path: ${{ env.REPORT_PATH }}
```

![CI3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/e7a4ca48-8944-8bbd-1483-ef3c8dfc139a.png)
全部pushしたら、Github > ActionsからT-DASHのworkflowを実行
![CI4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/20956b42-e6f4-72dd-f530-5c28c8d2813d.png)
テストが完了すると、Artifactsに実行結果のファイルが吐き出されるので、
そのファイル（html）から実行結果を確認する事ができます
![CI5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/478226/41aee250-11cf-033b-9bda-7412f372fc45.png)

# T-DASHを使って思った事

## 良かったところ

- とにかく導入が簡単
    「T-DASHのテスト」でも書いたように、
    導入が簡単で申請から20分程度でテストを試す事ができました！
    
- 操作方法が直感的にわかりやすい
    主に「テストスイート」「画面定義」の操作は、
    マニュアルを見ずとも理解できるくらい直感的にわかりやすかったです！
    
- テストの実行結果がわかりやすい
テストスイートでの実行レポートはとてもわかりやすく、
これなら大量にテスト項目を用意しても管理しやすそうだと思いました
エラーが発生した場合のエラーメッセージもわかりやすかったです！
    
- マニュアルが豊富で利用者に優しい
    公式でのマニュアルがかなり豊富で使い方がわからないという事はありませんでした
    マニュアル以外にもデフォルトで入っているサンプルアプリも結構参考になりました！
    

## 改善されると良いなと思ったところ

- テストの並列実行ができない
    大きなサービスで運用した場合ではテスト時間が結構かかるのではと思いました、
    テストランではテストスイートを並列実行できても良いのかなと思いました
    
- Github連携がまだあまり実用的ではない
    CI連携がまだベータ版というのもあるので、これから使いやすくなる事を期待したいです
    
- テストのスケジュール実行ができない
    スケジュール実行できると完全な自動テストになるので、あったら良いなと思いました
    
- モバイルアプリ対応
    現状Webメインにないっているので、モバイルアプリの対応も期待しています
    こちらは公式の開発ストーリーによると実装予定となっていました！