画面操作するテストを楽したくなったので、E2Eテストに手を出してみた

こんにちは、[@barm](https://qiita.com/barm)です。

私は現在、All About NewsのPHP, Laravelアップグレードの対応を行っています。
PHPは7.0から8.0まで、Laravel5.5から8.xまで上げており、複数回に分けてリリースを行っているので、開発中・リリース前の動作確認で同じような操作のテストを何回もしています。

本記事では、ユーザーの操作をコードで表現できるE2Eテストを書いて、少しでも楽ができないか模索していこうと思います。

# 使用するツール

今回はCypressというテストランナーを使ってテストをしていこうと思います。
JavaScriptでテストを書くことが可能で、CLI・GUI両方でテストの実行結果を確認できます。
今回は公式ページを参考に実際の業務で自動化したいと考えているテストを書いていき、GUIでテストの結果を確認していこうと思います。

https://www.cypress.io/

# Cypressの準備

nodeがインストールされている状態で、下記コマンドを実行するとcypressがインストールされます。

```
npm install cypress
```

ブラウザとコマンドラインの両方でテストを実行できますが、今回はブラウザで実行しています

```
npx cypress open
```

下のような画像が出たら準備完了です。

![スクリーンショット 2022-11-25 10.39.43.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984890/abeb5dc6-8608-cbdb-149d-0a6049ac7ff2.png)

テストコードはお好みのエディタで編集可能です。

# 実際にテストしてみた

## フロントエンドのページを表示してみる

まずはAll About Newsのトップページを表示してみます。

```
describe('visit All About News', () => {
  it('home', () => {
    cy.visit('http://dev.news.allabout.co.jp:55003/')
  })
})
```

テストランナーに戻って作成したテストファイルを実行してみます。
テストを実行すると下のような画面になり、ページが表示されます。

![スクリーンショット 2022-12-03 10.18.24（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984890/a5307fc1-9b6f-e49d-ae05-40485856cff6.png)


ちなみに適当なURLを入れるとエラーになります。

```
describe('visit All About', () => {
  it('passes', () => {
    cy.visit('https://sonzaisinai.co.jp/')
  })
})
```

![スクリーンショット 2022-11-25 10.58.44（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984890/065d4312-11b1-3789-4752-be204bd1db07.png)

## 複数ページにアクセスしてみる

複数ページにアクセスするときは以下のように書けます。

```
describe('visit All About News', () => {
  it('home', () => {
    cy.visit('http://localhost:8880')
  })
  it('category', () => {
    cy.visit('http://localhost:8880/category')
  })
})
```

テストを実行してみると…

![スクリーンショット 2022-11-28 21.11.29（2）.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984890/25e1cd96-4b72-db18-b66f-f922343b35c5.png)

上の画像のように2番目にアクセスしたページが画面には表示されます。
実行したテストの名称は左のカラムに出ていて、テストが成功していると緑のチェックマークが付きます。

## ページ内に特定の要素があるかどうか確かめてみる

次にページ内に特定の要素があるかどうかを確かめるテストを書いてみます。
今回はトップページの一番上にある見出しの記事部分の要素が存在するかどうかのテストを書いてみます。

```:見出し部分があるかどうかを見る
describe('visit All About News', () => {
  it('home', () => {
    cy.visit('http://localhost:8880')
    cy.get('div[class=hot-article]')
  })
})
```

テストを実行すると以下の画像のようになります。
画像のように `cy.get` で指定した要素があればハイライトできます。

![スクリーンショット 2022-12-01 9.54.34.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2984890/0512f7e7-d83e-de1b-688b-610c51ab1a07.png)


## 記事入稿システムにアクセスして、記事を保存してみる

All About Newsへの記事の入稿は社内独自のシステムを使っています。
記事の入稿を操作も自動テストできるかやってみようと思います。

社内システムになるので画像をあげられないのですが、画面を想像していただけると助かります。

```
describe('save article', () => {
    it('save article', () => {
        // 入稿システムにログイン
        cy.visit('http://localhost:8080')
        cy.get('input[name=pc_email]').type('hoge@example.com')
        cy.get('input[name=password]').type('password')
        cy.get('input[value=ログイン]').click()
        // 記事編集ページに移動
        cy.contains('記事').click()
        cy.contains('オリジナル記事').click()
        cy.get('input[value=新規作成]').click()
        // 記事編集&保存
        cy.get('input[id=title]').type('タイトル')
        cy.get('iframe').then(($iframe) => {
            const $body = $iframe.contents().find('html')
            cy.wrap($body).find('body').type('テキスト')
        })
        cy.contains('保存').click()
    })
})
```

先ほどと同様に `cy.get` で入力欄を取得します。
そして取得した後に `.type('文字列')` とつなげることで、取得したDOMが入力欄であれば文字列を入力できます。
そして、メールアドレスとパスワードを入力したらログインボタンを押さなければならないですが、これも取得した要素に対して `.click()` とつなげることで取得した要素をクリックするという動きを再現できます。
クリックするボタンについては `cy.contains` で入力するボタンに書かれているテキストを指定して取得しています。

本文の入力ついてはCKEditorを使用しています。
CKEditorの取得に少し躓いた、githubにissueが上がっていたのでそれを参考にテストコードを書きました。

https://github.com/cypress-io/cypress/issues/2272

まず最初にiframeの取得をしてその後中にあるDOMを取得するような形で入力欄を取得しています。

# 感想

表示、テキスト入力、クリックが行えるので大体の操作はコードで表現できそうだなと感じました。
毎回行うようなテストはテストコードでコード化しておくことで、開発環境で行うテストにかける時間と操作の回数は減らせると思います。
バグが起こった動作とかをコードにして残しておくと、リリース前のテストケースを作るのに活用できそうだなとほんのり考えています。

# 終わりに

cypressを使ってE2Eテストをやってみました。
今回例に挙げたもの以外にもテストしたいケースはあると思うので、自社のサービスに照らし合わせながらどんなテストが書けるかは実験していきたいと思います。