JavaScript のテストを書いてみる入門

全く JavaScript のテストを書いたことがなかったので、書いてみましたら。RSpec みたいでとてもフレンドリーでした。

mocha で Unit テストして、nightmare で E2E テストしてみたいと思います。

----

# サンプルアプリをまずは用意します。

ボタンをクリックしていって、3の倍数のときは... FizzBuzz です。

![fizzbuzz.gif](https://qiita-image-store.s3.amazonaws.com/0/45822/fa2fea74-af53-e07a-2cfb-9e1ff84f9d4d.gif)

----
# ソース

メインのコードは以下です。 div の `id` はテストで使います。

```jsx:src/index.js
import React from 'react'
import ReactDOM from 'react-dom'
import FizzBuzzApp from './FizzBuzzApp'

ReactDOM.render(
  <FizzBuzzApp />,
  document.getElementById('root')
```

```jsx:src/FizzBuzzApp.js
import React, { Component } from 'react'

export default class FizzBuzzApp extends Component {
  constructor(props) {
    super(props)
    this.state = {count: 0}
  }
  countUp() {
    this.setState({count: this.state.count + 1})
  }
  convertFizzBuzz(int) {
    if (int == 0) {
      return 'Click button'
    } else if ((int % 3 == 0) && (int % 5 == 0)) {
      return 'FizzBuzz'
    } else if (int % 3 == 0) {
      return 'Fizz'
    } else if (int % 5 == 0) {
      return 'Buzz'
    } else {
      return String(int)
    }
  }
  render() {
    return (
      <div>
        <h1>FizzBuzz</h1>
        <button id="button" onClick={() => this.countUp()}>Button</button>
        <div id="result" >{this.convertFizzBuzz(this.state.count)}</div>
      </div>
    )
  }
}
```
---

# 雛形はこちらを使っています

React の小さいアプリをつくるための starter-kit

https://github.com/mochizukikotaro/react-starter-kit/



---

# まずは Unit テスト

---

# mocha インストール

```
$ nmp i mocha -D
```

---

# eslint の調整

ぼくはこれを設定しないで、atom の eslint で怒られたりしていました。`it` がないぞーとか `describe` がないぞーとかです。

```json:.eslintrc.json
{
  "env": {
    "mocha": true
  }
}
```


---

# はじめてのテスト

ファイル名はなんでも大丈夫です。

```js:test/index.js
import assert from 'assert'

describe('addition', () => {
  it('1+1=2', () => {
    assert.equal(1+1, 2)
  })
});
```

rspec とそっくりですね！

---

# はじめてのテストを実行してみる

ES2015 で書いてますので、ちょっとオプションを渡して叩きます。

```
$ mocha --compilers js:babel-register test/index.js
```

<img width="536" alt="スクリーンショット 2018-04-16 21.03.29.png" src="https://qiita-image-store.s3.amazonaws.com/0/45822/fbe467f1-6da8-5a3b-b7bb-32249b1f9061.png">


----

# つぎにメソッドのテストをする

こんな風にかけます。3 つの `it` がありまして、よく見ると後ろの 2 つは失敗しそうです。

```js:test/FizzBuzzApp.js
import assert from 'assert'
import FizzBuzzApp from '../src/FizzBuzzApp'

describe('FizzBuzzApp', () => {
  const fizzBuzzApp = new FizzBuzzApp()
  describe('convertFizzBuzz', () => {

    it('return Fizz when count is 3', () => {
      assert.equal(fizzBuzzApp.convertFizzBuzz(3), 'Fizz')
    })

    it('return Fizz when count is 4', () => {
      assert.equal(fizzBuzzApp.convertFizzBuzz(4), 'Fizz')
    })

    it('return Fizz when count is 5', () => {
      assert.equal(fizzBuzzApp.convertFizzBuzz(5), 'Fizz')
    })

  });
});
```

そもそもアプリケーションでファイルを分割していて、 `export` しているので、テストが書きやすくなっている気がします。

---

# 実行してみる。

`mocha --compilers js:babel-register test/FizzBuzzApp.js`

無事 ２ つは失敗してくれました。

![スクリーンショット 2018-04-16 21.14.29.png](https://qiita-image-store.s3.amazonaws.com/0/45822/bebda9c6-1f2e-7800-54be-51bec2b4378c.png)

（あとは、適当に直しましょう。

---

# つぎに E2E テスト

---

# nightmare をインストール

```
$ npm i nightmare -D
```

---

# E2E テストを書いてみる

アクセスしたら「Click button」と表示されてることをテストしてみます。

```js:test/e2e.js
import Nightmare from 'nightmare'
import assert from 'assert'

describe('FizzBuzzApp E2E', () => {
  const nightmare = Nightmare({show: false})
  const URL = 'http://localhost:8080'

  it('アクセスしたら「Click button」と表示されていること', (done) => {
    nightmare
      .goto(URL)
      .evaluate(() => {
        return document.getElementById('result').innerText
      })
      .then((text) => {
        assert.equal(text, 'Click button')
        done()
      })
  })
})
```

---

# 実行

別タブで `npm start` しておいて。

```
$ mocha --compilers js:babel-register --timeout 3000  test/e2e.js
```

---
# 1 回クリックしたら「1」と表示されることを確認

```js:test/e2e.js_抜粋
it('1 回クリックしたら 1 と表示されること', (done) => {
  nightmare
    .goto(URL)
    .click('#button')
    .evaluate(() => {
      return document.getElementById('result').innerText
    })
    .then((text) => {
      assert.equal(text, '1')
      done()
    })
})
```

---
# 15 回クリックしたら「FizzBuzz」と表示されることを確認

```js:test/e2e.js_抜粋
  it('15 回クリックしたら FizzBuzz と表示されること', (done) => {
    nightmare
      .goto(URL)
      .click('#button')
      .click('#button')
      .click('#button')
      .click('#button')
      .click('#button')
      .click('#button')
      .click('#button')
      .click('#button')
      .click('#button')
      .click('#button')
      .click('#button')
      .click('#button')
      .click('#button')
      .click('#button')
      .click('#button')
      .evaluate(() => {
        return document.getElementById('result').innerText
      })
      .then((text) => {
        assert.equal(text, 'FizzBuzz')
        done()
      })
  })

```

何度も click してる...

---

# 15 回...

```js:test/e2e.js_抜粋
it('15 回クリックしたら FizzBuzz と表示されること', (done) => {
  let page = nightmare.goto(URL)
  for(let i=0; i<15; i++) {
    page = page.click('#button')
  }
  page.evaluate(() => {
      return document.getElementById('result').innerText
    })
    .then((text) => {
      assert.equal(text, 'FizzBuzz')
      done()
    })
})
```

<img width="781" alt="スクリーンショット 2018-04-17 11.58.10.png" src="https://qiita-image-store.s3.amazonaws.com/0/45822/0243aae5-853e-ee67-7c7b-6c7a7fcd8ef2.png">

---

以上、ありがとうございました。