cypressを触ってみた

## cypressとは

今週あたりtwitterで話題になっていたE2Eテストフレームワーク。
これまで private beta だったのが public beta になったとのこと。

この記事でcypressを触ってみながらどういうツールなのか、どういう用途に向くのかというのを明らかにしてみたい。

https://www.cypress.io/

現状をぱっと見た感想では、クロスブラウザテストを必要としないテストレベルに向きそう。
つまり、これまで phantomjs だとか最近だと puppeteer を使って書く開発者がやるようなコンポーネント統合テストあたり。

なお、Seleniumは共通のAPIを定義していおいて、それをブラウザベンザごとに対応してもらうような体制ができているので、クロスブラウザテスティングがすごくやりやすいものなんだけど、（その割にブラウザ間の差異がいまだにでかくて共通的にテストかけなくてつらみがでかいんだが）
まぁそういうの必要ない場合は単なる余計な中間層にしかならないのも事実。

ちなみに、現状 Chrome(Chromium含む） にしか対応していないんだけど、
https://github.com/cypress-io/cypress/issues/310 を見る限りではクロスブラウザ対応する意志はあるっぽい。
ただ、これ全部のブラウザに関してメンテし続けられる体制を作るのはかなりしんどいと予想されるので、話半分に聞いている感じである。

## インストール

```console
$ npm install cypress
```

cypressの特徴としてはAll in Oneなので、これで終わり。
KarmaにするかMochaにするかとか、Test Doubleに何を使うかとかそういうのを考える必要はないので、とっつきやすい。
（まぁそのうち、でもやっぱり、cypressのAssertion微妙だからそこはこれに入れ替えたいよねとかそういう話がでてくるんだろうなとは思うが）

## cypressの起動

cypressのIDEを起動します。

```console
$ npx cypress open
```

起動すると、`example_spec.js`があるのでクリックすると、いきなりGoogle Chromeが立ち上がり、cypressのサイトに対してテストが始まりますw
これみんなで一斉に試すとDDoSになるじゃないかなw

起動したGoogle Chromeにはcypressのextensionが入っていて、こいつがいろんなことをやっているようです。

## cypressのディレクトリ構造

`npx cypress open`すると、`cypress`ディレクトリができます。こんな感じ。

```console
$ tree cypress
cypress
├── fixtures
│   ├── example.json
│   ├── profile.json
│   └── users.json
├── integration
│   └── example_spec.js
├── screenshots
│   └── my-image.png
└── support
    ├── commands.js
    └── index.js

4 directories, 7 files
```

`cypress/integration`の下に`example_spec.js`ができていて、これが先程のcypressのサイトへのテストのようです。

## cypressでテストを書いてみる

まずは、簡単にGoogleのトップページにアクセスすると、タイトルにGoogleと表示されているというテストを書いてみたいと思います。

```js:cypress/integration/google_spec.js`
describe("Google Test", () => {
  it('Shows Google', () => {
    cy.visit('https://www.google.com/')

    cy.title().should("include", "Google")
  })
})
```

というようにMochaとChaiとして書けるようです。
すると、cypress内に`google_spec.js`ができるので、これまた同様にクリックするだけで、chromeが立ち上がり下のようにテストが実行されます。

![01_first_Google_spec.png](https://qiita-image-store.s3.amazonaws.com/0/5664/29414b68-426b-b3ca-d0f8-149f9601d967.png)

ここで、落ちるテストのときはどうなるかなと、"Google"を"Goggle"に書き換えて保存してみます。
すると、自動的にテストが再実行されます。
で、"Goggle"は見つからないので、数秒ほど待ってからテストが失敗しました。

![02_failure_Google_spec.png](https://qiita-image-store.s3.amazonaws.com/0/5664/37968272-b018-be82-3fc4-096044cb5a63.png)

おおお、これは革命的に簡単

## cypressでもっと頑張ったテストを書いてみる

先程のテストでは、さすがにtitleをみるだけと、非同期とか関係ないので、そんな甘いテストとか実際の現場ではほとんどないよといったレベルなので、もっと頑張ってみます。
（まぁ数秒待ってエラーになってくれている時点でいい予感しかしないのですが）

"DeNA SW"という単語で検索して検索候補にでてきた"DeNA SWET"をクリックすると、検索結果に"DeNA Testing Blog"が現れるかというのをテストしてみたいと思います。

先程のテストが通っている状態から、ChromeなのでDev Toolsを立ち上げ、Googleのフォームのcss selectorを調べます。定番ですが、`input[name='q']`で操作できそうです。

まずは、そこに、"DeNA SW"といれて検索してみます。

```js
  it("Shows DeNA SWET for completion of DeNA SW", () => {
    cy.get("input[name='q']").type("DeNA SW")
  })
```

ここまでをいれて保存すると、またもやブラウザが自動的に動き出します。
（DeNAといれただけで、SWETが補完されるように将来的にはしたいですね。。）

めでたく検索候補にDeNA SWETと現れているので、これをどうやって指定しようかと考えるために、DOMを見ようとDev Toolsの要素のDOMを見るボタンをクリックしてみます。

すると、まぁよくあることなのですが、（多分）focusが別にいったためにこういうインタラクティブな要素が思うように動いてくれないことはテストあるあるです。

### 途中の状態の再現をする

しかし、このcypressのすごいところは、操作のたびに（xhrリクエストがあるたびに）DOMのスナップショットをとってくれているということです。

![03_snapshot_Google_spec.png](https://qiita-image-store.s3.amazonaws.com/0/5664/88524656-583d-a7c2-a1ad-4d89b29a2a56.png)


これにより、"DeNA SW"といれた結果の画面が再現することができます。
（なお、xhrの前の状態と後の状態が両方保存されていて、responseの方をクリックしないと、後の状態がとれないのでご注意をください）

無事あらわれていることがわかったので、ひとまず、"dena swet"と小文字で表示されていることをassertionしておきましょう。

```js
cy.contains("dena swet")
```

で、最後にこの要素をクリックして、"DeNA Testing Blog"が表示されるかですが、

```js
  it("clicking DeNA SWET shows DeNA Testing Blog", () => {
    cy.contains("dena swet").click()
    cy.contains("DeNA Testing Blog")
  })
```

`contains()`で要素が絞れているので、`click()`するだけですね。

無事 [DeNA Testing Blog](http://swet.dena.com/) が表示されました。

![04_whole_result_Google_spec.png](https://qiita-image-store.s3.amazonaws.com/0/5664/f467f602-274c-673f-4b48-9e36849a057f.png)


## CLIでの実行

GUIでの威力はわかったのですが、CLIからでも実行したいですよね。

```console
$ npx cypress run -s cypress/integration/google_spec.js 

Started video recording: /Users/okita.kunio/tmp/cypress/cypress/videos/70btq.mp4

  (Tests Starting)


  Google Test
    ✓ Shows Google (4593ms)
    ✓ Shows DeNA SWET for completion of DeNA SW (634ms)
    ✓ clicking DeNA SWET shows DeNA Testing Blog (949ms)


  3 passing (9s)


  (Tests Finished)

  - Tests:           3
  - Passes:          3
  - Failures:        0
  - Pending:         0
  - Duration:        8 seconds
  - Screenshots:     0
  - Video Recorded:  true
  - Cypress Version: 1.0.1


  (Video)

  - Started processing:   Compressing to 32 CRF
  - Finished processing:  /Users/okita.kunio/tmp/cypress/cypress/videos/70btq.mp4 (2 seconds)


  (All Done)
```

このように CLI から実行すると、headlessモードで立ち上がるっぽくて、画面上にブラウザが表示されません。そのかわりに、デフォルトでビデオ録画してくれます。
cypressいたれりつくせり！

## そのほかのcypressの良さそうなところ

今日はまずはじめなので、超絶簡単にテストが書け（デバッグできる）て、実行できるということだけを紹介したのですが、cypressの紹介サイトを見る限り、他にもすごい機能があるようです。気になったものを簡単に紹介します。

* Stub機能（Fixture的な感じ）
 * 特定のパスへのリクエストをスタブできるようです。MITM的な感じなのかな？
* Cypress Dashboard
 * 特にCIでのテスト結果をチームにシェアできるようにみえます
 * 有料プランあり

## まとめ

cypressは実は、すでに3年ほどの開発期間があり、また、private betaでかなりブラッシュアップされているようです。
なので、未だbetaですが、すでにかなりの完成度を誇っていて、
すぐにでも実戦投入できるところまで来ているレベルかもしれません。

また何かわかったことがあれば、今度はDeNA Testing Blogかもしれませんが、記事にしたいと思います。


それでは楽しいテストを！