【Cypress】~7選~ CypressでE2Eテストするときはまずこれ読んどけって話

この記事は[Ateam Hikkoshi Samurai Inc. & Ateam Connect Inc.（エイチーム引越し侍、エイチームコネクト） Advent Calendar 2019](https://qiita.com/advent-calendar/2019/hikkoshi) 24日目の記事です。

本日はエイチーム引越し侍中途入社3年目、自称爆速Webエンジニアの加藤が担当します！

みなさんE2Eテスト書いてますか？？
引越し侍では10年以上続くレガシーシステムにテストが充実していないというカオスな現場があります。

とりあえずこのプロジェクトでリリースしたらここのCVチェックをしようという
力技で確認し続ける日々…

くそぅ！新規サービスではテストを書いているのに！
レガシーシステムにはテストも入れられないのか！

# E2Eテスト導入への障壁
一度うちのエンジニアの神様がE2Eを導入しかけたんですが、
ABテストとかに対応するのめんどくさいとのことでなかなか拡充していかなかったんですよね
その姿を見た僕は「めんどくさいんだろうなぁ」と指をくわえて見てましたが、
中途3年目、気づけば社内エンジニア社歴はTOP7に、神セブンってやつですよ。
しかも僕より上の人たちはマネージメントだったり日々の業務に追われて中々動き出せなさそう。

# 思い立つ
このテスト文化がなじんできた今声を大にして言うしかない！

# 唐突な目次
ほぼこれで行ける
js 呼び出せない…
ラベル貼っている要素へのアクセス
ビデオ録画やめる
jsエラーに敏感
IP問題
フロントエンジニアとの協力体制が必要

とりあえず書いてみた

# ほぼこれでいける
```javascript:*.spec.js
cy.visit(url) // urlにアクセス
cy.get('セレクタ') // html上の要素を取得
cy.get('セレクタ').click() // 要素をクリック
cy.get('セレクタ').type('文字列') // 要素に文字列を挿入(テキストボックスとか)
cy.get('セレクタ').select('文字列') // セレクトボックスの中身を選択(valueでもテキスト部でもどちらでも指定可)
cy.wait(msec) // 指定したミリ秒待つ
cy.go('back') // ブラウザバック
cy.go('forward') // 進む
```

まだ始めたばっかでわかんないけどこれで大体いけんじゃね？
※これもいるよ！ってコメントで教えてもらったら随時追加していきます！

# js呼び出せない
Cypress入れようと思った時にNode.jsなんだからそのページで使っているjsとかまで使えんじゃね？
便利ー！と思ってたんですけど呼び出せない…そんな関数ないよってシンプルに怒られます。
まだ読み込み終わってないんかなとwaitしてもダメ。
だれかやれる方法あったらコメントで教えてください。
速攻で記事修正します。

# ラベル貼っている要素へのアクセス
なんかラベルを張られている要素にアクセスしようとすると怒られる模様

```html

CypressError: Timed out retrying: cy.type() failed because this element:

<input type="text" name="request[current_zip_code]" value="" id="request_current_zip_code">

is being covered by another element:

<label for="request_current_zip_code">例）1500001</label>
```
そんなときはforceを入れる

```javascript

cy.select('文字列', {force: true})
cy.type('文字列', {force: true})
```

# ビデオ録画やめる
なんかテストのたびに動画撮ってる
こっちは勉強中なんだよ！さっさと何回も回したいんだよ！と思ったら
cypress.jsonに下記を追加

```json:cypress.json
 "video": false
```

# jsエラーに敏感
1例ですが、formタグに使っていなく、宣言自体も読み込まれなくなった関数がありまして、
ボタンにonclick属性で指定されている関数でsubmitしている感じだったんですが、
chromeだと遷移できるのに、Cypressちゃんはエラーで停止しました。

```html
# 使っていないsubmitFuncまで発火しエラーにある
<form name="form1" enctype="multipart/form-data" method="get" action="/request/base"  onsubmit="submitFunc(this)">

# onclick
<a onClick="submitForm(document.form1); return false;">
```

# IP問題
弊社ではテストのために、社内IPからのアクセスの時にはテストデータとする処理があります。
本番でテストするなら上記の方法以外でテストデータとする処理を何かしらいれないとなぁ…

# フロントエンジニアとの協力体制が必要

```html
<a class="btn-entry" onClick="submitForm(document.form1); return false;">
```

このリンクをクリックしたいけどclassで指定したくない名前だな…
id追加してとりあえず対応するけど、このid使ってなくね？消しちゃえってなるとやだし、
わかりやすいタグつけたほうがいいだろうなぁ

```html
<a id="cypress_submit_button_1 " class="btn-entry" onClick="submitForm(document.form1); return false;">
```

こんな感じだとわかるかなぁ
要相談

# とりあえず書いてみた

```javascript
describe('PC 一括CV', () => {
  context('正常な依頼', () => {
    it('正常にCVできること',() => {
      const samurai_top = 'https://hikkoshizamurai.jp.test.hoge.com/'
      const user = {
        currentZipCode: '1010051',
        currentStreetName: '2-11',
        currentBuildingType: 'マンション',
        newZipCode: '1010051',
        lastName: '加藤' + Math.random().toString(32).substring(7),
        firstName: '太郎',
        lastNameKana: 'カトウ',
        firstNameKana: 'タロウ',
        tel: '090' + Math.floor(Math.random() * 100000000), // 重複データにならないようにランダム文字列生成
        email: 'kato.shogo+' + Math.random().toString(32).substring(7) + '@a-tm.co.jp' // 重複データにならないようにランダム文字列生成
      }
      cy.log("トップにアクセスします")
      cy.visit(samurai_top)
      cy.log("フォームに遷移します")
      cy.get('#mainForm-move-entry')
        .click()

      // base
      cy.log("住所情報を入力します")
      cy.get('#request_current_zip_code')
        .type(user.currentZipCode, {force: true})
      cy.get('#request_current_street_name')
        .type(user.currentStreetName, {force: true})
      cy.get('#request_current_building_type')
        .select(user.currentBuildingType, {force: true})
      cy.get('#request_new_zip_code')
        .type(user.newZipCode, {force: true})
      cy.wait(2000)
      cy.get('input[name="submit"]')
        .click()

      // personal
      cy.log("個人情報を入力します")
      cy.get('#request_user_name_last_name')
        .type(user.lastName, {force: true})
      cy.get('#request_user_name_first_name')
        .type(user.firstName, {force: true})
      cy.get('#request_user_name_kana_last_name_kana')
        .type(user.lastNameKana, {force: true})
      cy.get('#request_user_name_kana_first_name_kana')
        .type(user.firstNameKana, {force: true})
      cy.get('#request_whole_tel_no')
        .type(user.tel, {force: true})
      cy.get('#request_email_address')
        .type(user.email, {force: true})
      cy.get('#request_advertise_type_2')
        .click()

      // packages
      cy.log("荷物情報を入力します")
      cy.get('input[name="submit"]')
        .click()

      // confirm
      cy.log("確認画面です")
      cy.get('input[name="submit"]')
        .click()
    })
  })
})
```

CVできたぜ

いかがでしたでしょうか。
CypressでE2Eテスト書く時の初動になれればと思います。

[Ateam Hikkoshi Samurai Inc. & Ateam Connect Inc.（エイチーム引越し侍、エイチームコネクト） Advent Calendar 2019](https://qiita.com/advent-calendar/2019/hikkoshi)
明日は@zwirky が年末にバグバッシュを技術開発部のメンバー全員でやったことを記事にしてくれます！
お楽しみに！

# 追伸
株式会社エイチーム引越し侍では、一緒にサイト改善をしてくれるWebエンジニアを募集しています。エイチームグループのエンジニアとして働きたい！という方は是非、以下のリンクから応募してください。
皆様からのご応募、お待ちしております！！

> [エイチームグループ採用サイト（Web開発エンジニア職）](http://hikkoshi.a-tm.co.jp/recruit/request.php?ea=ktqiita_cypress)