嗚呼素晴らしき, Codecept.js + Puppeteer による E2E の世界

本記事は, [ゆめみ Advent Calendar 2019 その1]() の第12日めの記事になります.

タイトルは私の大好きな [テイルズシリーズの設定](https://w.atwiki.jp/talesofdic/pages/3216.html) と, VOCALOID の曲の一つ [嗚呼素晴らしき、ニャン生](https://w.atwiki.jp/hmiku/pages/17172.html) からです.

先日, テスト自動化カンファレンスに参加(LT登壇)し, 物凄くテスト書きたい欲に駆られまして, せっかくならあまり書いてこなかった E2E テストに再入門しようと思い色々調べてたら, [こちらの記事(ストック済み)](https://qiita.com/tsuemura/items/56ba9942565963858d8f) の存在を思い出し, 参考にしながらやってみた知見を書いてみたいと思います.

※思いっきり二番煎じですが, 鉄の心で書いていきます.

# テストケース

今回は, みんな大好き [NPM](https://npmjs.com) さんのサイトを使わせていただき, 以下のようなテストを実施してみたいと思います.

　1. https://npmjs.com にアクセスしているか？
　2. "Build amazing things" という文言が表示されているか？
　3. "Accept" ボタンをクリックできるか？
　4. "Sign In" リンクをクリックし, サインイン画面に遷移できるか？
　5. 遷移先 URL が "/login" となっているか？
　6. 入力フォームの "username" にユーザー名を入力できるか？
　7. 入力フォームの "password" にパスワードを入力できるか？
　8. サインインできているか？
　9. 入力フォームの "Search packages" に "riotjs" と入力できるか？
　10. "Search" ボタンをクリックし, 検索ができているか？
　11. 検索結果画面の URL が "/search?q=riotjs" となっているか？
　12. "@riotjs" という文言が表示されているか？

勝手に NPM さんを使って良かったのか…？という疑問は残りますが, [API も公開](https://api.npmjs.org) されていますしおそらく大丈夫かと…(一応確認メールは送った)

# テスト環境の用意
```bash
# 必要なライブラリのインストール
$ npm i -g codeceptjs puppeteer

# ディレクトリ作成 & 移動
$ mkdir myTest && cd myTest

# 初期化
$ codeceptjs init

  Welcome to CodeceptJS initialization tool
  It will prepare and configure a test environment for you

Installing to /Users/k_kuwahara/Desktop/programing/tests
? Where are your tests located? ./*_test.js
? What helpers do you want to use? Puppeteer  # (※)
? Where should logs, screenshots, and reports to be stored? ./output
? Would you like to extend the "I" object with custom steps? No  # "I" のままが個人的には好き
? Do you want to choose localization for tests? English (no localization)  # 日本語(ja-JP)もあるよ
Configure helpers...
? [Puppeteer] Base url of site to be tested http://npmjs.com
? [Puppeteer] Show browser window Yes  # リアルタイムで見れるの面白いよ

Config created at /Users/k_kuwahara/Desktop/programing/tests/codecept.conf.js
Directory for temporary output files created at './output'
Intellisense enabled in /Users/k_kuwahara/Desktop/programing/tests/jsconfig.json
TypeScript Definitions provide autocompletion in Visual Studio Code and other IDEs
Definitions were generated in steps.d.ts

 Almost done! Next step:
 Create your first test by executing `npx codeceptjs gt` command
```

ここまで実行すると, 以下のようなファイル・ディレクトリが自動で生成されていると思います.

* `codecept.conf.js` : テストに関する設定周り
* `output/` : テスト結果の出力先ディレクトリ
* `jsconfig.json` : 文字通り JavaScript の設定周り
* `steps.d.ts` : (特に触ることはない)

この中でキーとなるファイルが `codecept.conf.js` です. テスト環境の変更する際も, こちらのファイルの記述を変更していきます.

(※) : ここで感動したのですが, helper(テストフレームワーク) の**選択肢が豊富** で驚きました！

```
  WebDriver
❯ Puppeteer
  TestCafe
  Protractor
  Nightmare
  Appium
```

私が調べた E2E テストフレームワークがだいたい選択肢にあります. `cypress` だけ有りませんでしたが, おそらくこのフレームワークはそれだけで完結するからなんだろうなと思います(私はまだ触ったことがない). 個人的にはこの中ですと [TestCafe](https://devexpress.github.io/testcafe/) がおすすめです！ 各ブラウザでのテストも設定すればコマンド一発で勝手に開いて実行してくれるのは物凄くありがたいです.

また, `Puppeteer` 以外のフレームワークもとても優秀ですので, ご興味あれば実際に触ってみていただければと思います. `Protractor` のみ, [Angular](https://angular.io) 用のフレームワークですのでご注意ください.

# 実際のテストコード

それでは実際にテストを書いていきましょう. 適当に `npm_test.js` というファイルを作成していただき, 以下を追記します.

```js:npm_test.js
Feature('myTest'); // このテスト全体の名前

// 今回はシナリオ名をサボって, 2つのシナリオを分けずに一つで実施
Scenario('sign in and search riotjs modules', (I) => {
  const signInLink = locate('a').withText('Sign In')
  const signInButton = locate('button').withText('Sign In')
  const searchButton = locate('button').withText('Search')

  // ホームページにアクセスし, cookie の通知をクリック
  I.amOnPage('/')
  I.see('Build amazing things')
  I.click('Accept')

  // サインイン
  I.click(signInLink)
  I.amOnPage('/login')
  I.see('Sign In')
  I.fillField('Username', 'kkeeth')
  I.fillField('Password', '****') // 自分のパスワード
  I.click(signInButton)

  // ホーム画面に戻る処理
  I.click('npm')
  I.amOnPage('/')

  // riotjs のモジュールを検索
  I.fillField('Search packages', 'riotjs')
  I.click(searchButton)
  I.amOnPage('/search?q=riotjs')
  I.see('@riotjs')
});
```

私は初めてこのテストの書き方を見てとても感動しました. 各ケースが何をするのかが明確(一つ音文)なのがとても良く気に入りました. また `locate('button').withText('Sign In')` でボタン要素を変数に格納して click メソッドで指定していますが,

* `I.click('Sign In')` 要素のテキストで指定
* `I.click('#hoge')` 要素の CSS スタイルで指定

のように指定することもできますので, 柔軟に書けてこれも嬉しいです. ただしチームで開発する際は, 書き方を統一したほうが良いですね.

テストの実行は,

```bash:実行コマンド
$ codeceptjs run npm_test.js
```

というコマンドで実行できます. 実行すると自動でデフォルトのブラウザが起動しテストが走り始めることを眺められます(これが楽しい).これが邪魔だなーという人は, `codecept.conf.js` を以下の様に変更してください.

```diff:codecept.conf.js
  helpers: {
    Puppeteer: {
      url: 'https://npmjs.com',
-      show: true
+      show: false
    }
  },
```

実行後は `output` というディレクトリに各画面のキャプチャも出力されており, テストのスクショを別途撮る必要もないのでラクチンです😄出力ディレクトリ先を変えたい場合は同様に, `codecept.conf.js` を以下の様に変更してください.

```diff:codecept.conf.js
-  output: './output',
+  output: './hoge',
```

# 感想
まだ使い倒してもいないですし実戦投入もしていないのであれですが, もう E2E テストはこれで良いのでは？と思ってしまった…もちろん他のフレームワークの良い点も知った上で実践では選定したいので, まずはどんどん使っていきます.

それにしても, 今の E2E テストのツールもここまで進化しているのか！というのが正直な感想で, フロントエンドエンジニアとしてはユーザーの操作も含めこれでだいたいカバーできると感じました. スタイリングのテストにつきましては, [reg-suit](https://reg-viz.github.io/reg-suit/) という素晴らしいツールがありますので, 私はこちらをオススメしています.

明日は [@unotovive](https://qiita.com/unotovive) さんです！

ではでは(=ﾟωﾟ)ﾉ