Nightwatch.jsでPageObjectを試しました。

お疲れ様です。@naokiurです。

Selenideを使ってPageObjectをやったことはありましたが、
Vue.jsを使っている兼ね合いで、
`Nightwatch.jsでPageObject`を試しました。

# 環境
* MacBook Pro (Retina 13-inch、Early 2015)
* OS X El Capitan 10.13.6
* node v8.12.0
* npm 6.4.1


# 実施したこと
簡単な、 `入力して内容を表示する`みたいな画面を用意して、
それに対してテストコードを書きました。

上のテキストボックスに値を入れて、
`send`をクリックすると、
下のテキストボックスに反映される、というものです。

![try-coding-nightwatch.gif](https://qiita-image-store.s3.amazonaws.com/0/129313/c26e2b84-60e5-1276-79f1-4281629e4579.gif)


自分で言うのもアレですが、
なんとも陳腐な画面です。


画面とテストコードは以下です。

## テスト対象画面
```TestTarget.vue
<template>
  <div>
    <section>
      <input type="text" name="inputData" v-model="inputData" placeholder="please enter some test!" />
    </section>
    <section>
      <input type="button" value="send" @click="send" />
    </section>
    <section>
      <input type="text" name="resultData" :value="result" />
    </section>
  </div>
</template>

<script>
  export default {
    name: 'testTarget',
    data () {
      return {
        inputData: '',
        result: 'before'
      }
    },
    methods: {
      send: function () {
        this.result = this.inputData
      }
    }
  }
</script>

<style scoped>

</style>

```

## テストコード
```test.js
module.exports = {
  'input test': function (browser) {
    const targetPage = browser.page.testTargetPage()
    
    targetPage.navigate()
      .assert.visible('@inputData')
      .setValue('@inputData', 'test')
      .send()
      .assert.value('@resultData', 'test')
    
    browser.end()
  } 
}

```

```testTargetPage.js
const pageCommands = {
    send: function () {
        return this.waitForElementVisible('@sendButton', 1000)
            .click('@sendButton') 
    }
}

module.exports = {
    commands: [pageCommands],
    url: function () {
        return this.api.globals.devServerURL
    },
    elements: {
        inputData: {
            selector: 'input[name=inputData]'
        },
        sendButton: {
            selector: 'input[type=button]'
        },
        resultData: {
            selector: 'input[name=resultData]'
        }
    }
}
```

```nightwatch.conf.js
require('babel-register')
var config = require('../../config')

module.exports = {
  src_folders: ['test/e2e/specs'],
  output_folder: 'test/e2e/reports',
  custom_assertions_path: ['test/e2e/custom-assertions'],
  page_objects_path: ['test/e2e/pageObjects'],

  selenium: {
    start_process: true,
    server_path: require('selenium-server').path,
    host: '127.0.0.1',
    port: 4444,
    cli_args: {
      'webdriver.chrome.driver': require('chromedriver').path
    }
  },

  test_settings: {
    default: {
      selenium_port: 4444,
      selenium_host: 'localhost',
      silent: true,
      globals: {
        devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port)
      }
    },

    chrome: {
      desiredCapabilities: {
        browserName: 'chrome',
        javascriptEnabled: true,
        acceptSslCerts: true
      }
    },

    firefox: {
      desiredCapabilities: {
        browserName: 'firefox',
        javascriptEnabled: true,
        acceptSslCerts: true
      }
    }
  }
}

```

## ディレクトリ構成
```
project_root
    |- src
        |- page
            |- TestTarget.vue
    |- test
        |- e2e
            |- pageObjects
                |- testTargetPage.js
            |- specs
                |- test.js
            |- nightwatch.conf.js

```

# ハマったところ
* `.assert.visible('@inputData')`が失敗する！
    + `navigate()`を忘れていて、そもそもアクセスしていなかった
* 公式の通りに、`testTargetPage.js`にcommandを書いたけれど、`this.waitForElementVisible is not function`が発生する！
    + https://github.com/nightwatchjs/nightwatch/issues/1629 と同事象でした。ディレクトリ構成がいかんかったです。

# 結果
* PageObjectパターンを反映させることにより、テストコードをたくさん書いたあと、DOMの構成が変わっても、PageObjectだけ書き換えればよくなりました。
* Commandを作成して置くことにより、テストコードがスッキリしました。
    * サンプルの画面だと、シンプルすぎて良さがわかりにくいかもしれませんが、もっと色々やる画面ならば、良さが分かる、と期待しています。

# 参考にさせて頂きました
* http://nightwatchjs.org/
* https://github.com/nightwatchjs/nightwatch/issues/1629