フロントエンド・テストツール比較 Selenium #02テスト編

## はじめに
[株式会社クリエイス](http://creaith.jp/)社員の[モトキ](https://qiita.com/pickles)です。
[前回](https://qiita.com/creaith/items/c138c0417470a17cc4b4)の環境構築の続きです。
今回はPuppeteerチームと同じシナリオ・テストページを使って自動化テストを実施していきます。

## 登場人物
### Selenium班(この記事の筆者)  
* [モトキ](https://qiita.com/pickles)、[志村](https://qiita.com/naoto1222)  

### 対するPuppeteer班
* [上田](https://qiita.com/uedashuhei)、[曽宮](https://qiita.com/ryosomiya)   
[フロントエンド・テストツール比較 Puppeteer #02テスト編](https://qiita.com/creaith/private/cde0cbf56c88021b534d)

## 前提条件
前回の記事に加えて、以下を追加します。

|使用する技術|バージョン番号|
|---|---|
|java version|1.8.0_151|
ちなみに**Java10だと動きませんでした**(Java9は未確認)

## Seleniumのアップデート
[前回の記事](https://qiita.com/creaith/items/c138c0417470a17cc4b4)で作った環境を使おうとしたら、エラーが。
**WebDriverを更新しろ** とのことで、以下を実施

```shell:WebDriverの更新
# /path/to/selenium/node_modules/.binにPath通していたら、短く書けます
$ cd /path/to/selenium/node_modules/.bin
$ node_modules/.bin/selenium-standalone install
```

## 実施する操作手順
[検証用のソース](https://github.com/naoto1222/tech-blog)
React-Reduxで作成されたSPAのテスト用ページです。
git clone後READMEに書かれた手順にしたがって起動してください。
起動環境はSeleniumに合わせてあるので問題ないはずです。
閲覧者にテスト自動実行でアタック食らったら泣けるので、webに公開はしてません(笑)

### 1.ログイン画面の操作
|<img src="https://qiita-image-store.s3.amazonaws.com/0/240629/6fffb4e0-3506-7e3a-f4f2-e45cb1aa2f8e.png" width="50%">|
|---|
|テストページを開く|
|タイトルのアサーション、キャプチャ|
|入力フォームにonfocus、背景色変更後にキャプチャ|
|IDとパスワードを入力せず、ログインボタンをクリック|
|エラーモーダルをキャプチャ|
|エラーモーダルの閉じるボタンをクリック|
|IDとパスワードを入力、キャプチャ|
|ボタンにホバーしてキャプチャ  → 実施できず(理由は後述)|
|ログインボタンをクリック|

### 2.ログイン後の一覧画面の操作
|<img src="https://qiita-image-store.s3.amazonaws.com/0/240629/7e762957-b175-4eb1-efb4-ae7553356c05.png" width="50%">|
|---|
|ログイン後の一覧画面に遷移して、ID/パスワードのアサーションとキャプチャ|
|リストで以下のキーワードを登録してキャプチャ(入力したものが、画面にリンクとして反映される)  <br>`javascript`, `ruby`, `scala`|
|リストをDnD[^1]を入れ替えてキャプチャ → 実施できず(理由は後述)|

### 3.別タブの操作
|(画像なし)|
|---|
|別タブを開くリンクをクリックする|
|(別タブの操作)タイトルをアサーション・キャプチャ|
|(別タブの操作)タブを閉じる|
|元のタブでキャプチャする|

### 4.ブラウザバック・フォワードの操作
|(画像なし)|
|---|
|リストの任意の項目(同タブリンク)をクリックする|
|タイトルをアサーションして、キャプチャ|
|一覧画面に戻る、進むを行い、それぞれでキャプチャする|


## テストコード
今回、テストケースを囲う関数 `it()` はキャプチャごとに指定します。

```javascript:test/spec/test.js
const assert = require('assert')
const url = 'http://***/' // テストするURL
const id = 'takeda'
const passwd = 'shinji'
let newTab;

describe('access to React Test', () => {
  it('01', () => {
    // TOPにアクセス
    browser.url(url)
    const title = browser.getTitle()
    assert.equal(title, 'React Test')
    browser.saveScreenshot('capture/01_home_first.png')
  })

  it('02', () => {
    browser.click('#id_input')
    browser.saveScreenshot('capture/02_home_focused.png')
  })

  it('03', () => {
    // 空のままクリックでモーダル表示
    // ログインボタンの押下
    browser.click('#login_button')
    browser.saveScreenshot('capture/03_login_failed.png')
  })

  it('04', () => {
    browser.click('#close_button')

    // IDの入力と確認
    browser.setValue('#id_input', id)
    const checkId = browser.$('#id_input').getValue()
    assert.equal(checkId, id) // true

    // Passwordの入力と確認
    browser.setValue('#pass_input', passwd)
    const checkPasswd = browser.$('#pass_input').getValue()
    assert.equal(checkPasswd, passwd) // true

    // 1ページ目のスクリーンショット
    browser.saveScreenshot('capture/04_home_input.png')
  })

  it('05', () => {
    // Hoverに使うmoveToが将来Deprecatedになるらしく警告出てるので、今回はホバースキップ
    browser.saveScreenshot('capture/05_home_hover.png')
  })

  it('11', () => {
    // ログインボタンの押下
    browser.click('#login_button')
    browser.waitForExist('#text_input')

    // 画面遷移後の項目アサーション
    const checkIdAssert = browser.$('#id_label').getText().indexOf(id)
    assert(checkIdAssert)
    const checkPasswdAssert = browser.$('#pass_label').getText().indexOf(passwd)
    assert(checkPasswdAssert)

    // 2ページ目のスクリーンショット
    browser.saveScreenshot('capture/11_list_first.png')
  })

  it('12', () => {
    ['javascript', 'ruby', 'scala'].forEach(value => {
      browser.setValue('#text_input', value)
      browser.click('#text_input + button')
    })

    // 2ページ目(追加後)のスクリーンショット
    browser.saveScreenshot('capture/12_list_addlist.png')
  })

  it('13', () => {
    // 04と同じ理由(moveTo系がダメなの)でスキップ
    browser.saveScreenshot('capture/13_list_dnd.png')
  })

  it('21', () => {
    // リンククリック
    browser.click('#blank_link')

    // 現在開いてるタブIDを取得
    const currentTab = browser.getCurrentTabId()
    browser.getTabIds().forEach(value => {
      if (currentTab != value) {
        this.newTab = value
        browser.switchTab(value)
      }
    })

    // 画面遷移後のアサーション
    const title = browser.getTitle()
    assert.equal(title, 'Yahoo! JAPAN')
    browser.saveScreenshot('capture/21_tab_first.png')
  })

  it('22', () => {
    // タブを閉じる
    browser.close(newTab)
    browser.saveScreenshot('capture/22_tab_return.png')
  })

  it('31', () => {
    // リストのリンクをクリック
    browser.click('#list_label1 > h3:nth-child(1) > a:nth-child(1)')
    const title = browser.getTitle()
    assert.equal(title, 'React Test')
    browser.saveScreenshot('capture/31_list_link.png')
  })

  it('32', () => {
    // 戻る・進む
    browser.back()
    browser.saveScreenshot('capture/32_list_link_back.png')
  })

  it('33', () => {
    browser.forward()
    browser.saveScreenshot('capture/33_list_link_forward.png')
  })
})

```


## テストの実施
[前回](https://qiita.com/creaith/items/c138c0417470a17cc4b4)と同じです。

### Selenium立ち上げ(別プロセスのシェルで実行)
seleniumを立ち上げます。
テストが終わった後に`Ctrl-C`で終了します。

```zsh
$ cd /path/to/selenium
$ node_modules/.bin/selenium-standalone start
```

## テストケースの実行

```zsh
$ node_modules/.bin/wdio wdio.conf.js
```

全テストケースが終了し、キャプチャが取れていることを確認します。

## 問題点
* WebDriverIOのマウス操作関連`moveTo()`が非推奨になるらしく、警告が出てしまいます。  

```
WARNING: the "moveTo" command will be deprecated soon. If you have further questions, reach out in the WebdriverIO Gitter support channel (https://gitter.im/webdriverio/webdriverio).
Note: This command is not part of the W3C WebDriver spec and won't be supported in future versions of the driver. It is recommended to use the actions command to emulate pointer events.

(You can disable this warning by setting `"deprecationWarnings": false` in your WebdriverIO config)
```
WebDriverIOのDnDやホバーのテストが出来ません。
**しかも代替え機能がない模様。**  
**テストケースもFが付いてしまう**(失敗になる)ので、これらのテストケースはスキップしました。
(configで非推奨にオフに出来ることを実施後に知りました)

## Puppeteerとの比較結果
[Puppeteer問題点はこちら](https://qiita.com/creaith/private/cde0cbf56c88021b534d#%E7%B5%90%E6%9E%9C)
上記のリンクの問題点に加えてテストケースの進捗が見えません。自動操作だけが目的なのかな。

テストコードや準備はPuppeteerよりも多いですが、
Selenium+WebDriverIOはエビデンスやエラー時のキャプチャが出るので、現場でフロントエンドテストツールとして採用し易いのではないでしょうか。
Seleniumの方が情報量多いですし

[^1]: ドラッグアンドドロップの略