cypressのチュートリアルの実践

cypressのチュートリアルどこまでできるか

結論から言うと以下ができる

  • scaffoldでサンプルプロジェクトを作る
  • サンプルプロジェクトを実行して自動テストが動くさまをみれる(ローカル実行)
  • サンプルプロジェクトをcypress cloudを利用してレンタル遠くの実行環境で動かせる(リモート実行)
  • サンプルプロジェクトを好みのci使って構築実行できる
    • 今回はcircle ci

参考記事

公式のget start

docs.cypress.io

あとはcypress openしたものをcontinue

scaffold

npx cypress open するとウィザードが出てポチポチしてたらプロジェクトができてておったまげる

しかもこのウィザードからテスト選ぶと画面の変化の様子とコードを照らし合わせながら実行できたりしてあまりにも便利。すごすぎ

cypress.io内のテスト実行用のサイトで動かしてくれるのでいろいろ安心

テストケースが175くらいあってサンプルとしては優秀なんだけど、後述のcypress cloudとかに使うと一気に無償枠の500を消費するから減らしとくといい

いろいろContinueとかしてたらcypress cloudというレンタル実行環境を使わしてくれる。browser stackみたいなもん。学習の範囲なら無償で賄えると思うのでどうせならやってみるといい。ただテストケースは減らしといたほうがいいかも

サンプルを少し見る

いつものと特徴的なコードを見ておきます。

共通beforeEach

describe('example to-do app', () => {
  beforeEach(() => {
    // Cypress starts out with a blank slate for each test
    // so we must tell it to visit our website with the `cy.visit()` command.
    // Since we want to visit the same URL at the start of all our tests,
    // we include it in our beforeEach function so that it runs before each test
    cy.visit('https://example.cypress.io/todo')
  })

テストページを開く一般的な方法。大体想像通りだけど、visitはSelenideのopenやplaywrightのgotoとかと同義だけどちょっと違うように、なんでかみんなここで個性出すから、ちゃんと抑えときたい。

1-getting-started\todo.cy.js

いつもの。CSS Pathでアクセスするgetのやつとshouldclickみたいなよくあるやつ。眺めておきたい

    it('can filter for uncompleted tasks', () => {
      // We'll click on the "active" button in order to
      // display only incomplete items
      cy.contains('Active').click()

      // After filtering, we can assert that there is only the one
      // incomplete item in the list.
      cy.get('.todo-list li')
        .should('have.length', 1)
        .first()
        .should('have.text', 'Walk the dog')

      // For good measure, let's also assert that the task we checked off
      // does not exist on the page.
      cy.contains('Pay electric bill').should('not.exist')
    })

2-advanced-examples\actions.cy.js

clickとか基本的な操作。眺めておきましょ。あと以下のページを覚え解くこと

on.cypress.io

2-advanced-examples\connectors.cy.js

eachみたいな便利系がそろっている。

  it('.each() - iterate over an array of elements', () => {
    // https://on.cypress.io/each
    cy.get('.connectors-each-ul>li')
      .each(($el, index, $list) => {
        console.log($el, index, $list)
      })
  })

example.cypress.io

2-advanced-examples\aliasing.cy.js

Cypressの罠ともいえるポイントを押さえたコード

以下はよくないらしい。Cypressのコマンドは基本非同期で、以下は想定通りに動作しない可能性があるとのこと。

// this won't work the way you think it does
const button = cy.get('button')
const form = cy.get('form')

button.click()

いろいろ試したけど具体的にどういうタイミングでおかしくなるかよくわからない・・・

こうなるとアクセサの再利用どうなるの的な話あって、それの回答になるのがalias機能、Chainable#asメソッド

  it('.as() - alias a DOM element for later use', () => {
    // https://on.cypress.io/as

    // Alias a DOM element for use later
    // We don't have to traverse to the element
    // later in our code, we reference it with @

    cy.get('.as-table').find('tbody>tr')
      .first().find('td').first()
      .find('button').as('firstBtn')

    // when we reference the alias, we place an
    // @ in front of its name
    cy.get('@firstBtn').click()

    cy.get('@firstBtn')
      .should('have.class', 'btn-success')
      .and('contain', 'Changed')
  })

as("@name")でコンテキストに保存してcy.get("@name")で取得する形

コンテキストが共有される範囲や寿命は調べ切ってないけど、Mochaのコンテキストを利用しているらしくそれに準拠してる様子。

ちゃんと調べてないから大きいことは言えないけど、以下のコードで大まかなイメージがつくと思う。

describe('parent', () => {
  beforeEach(() => {
    cy.wrap('one').as('a')
  })

  context('child', () => {
    beforeEach(() => {
      cy.wrap('two').as('b')
    })

    describe('grandchild', () => {
      beforeEach(() => {
        cy.wrap('three').as('c')
      })

      it('can access all aliases as properties', function () {
        expect(this.a).to.eq('one') // true
        expect(this.b).to.eq('two') // true
        expect(this.c).to.eq('three') // true
      })
    })
  })
})

ただaliasした要素はいつのものなのか、aliasした後に要素に変化あったらどうなるのかはよくわからない。使うなら調査。

詳細は以下。読んでおきましょう。

docs.cypress.io

cypress cloud

レンタル実行環境。テスト実行用のPCとブラウザのセットがテスト実行のため、時だけ借りられる。

cypress専用のbrowser stackと考えてよい。デフォルトでfree planが使えて月に500ケース実行の権利がついてくる。余談だけど75$のTeamプランで10000ケースになってテスト結果の保持期間が30日から90日になるらしい。

Cypress専用なだけあってUIがいかしてる。Overciewの情報量が多くて適切

各テストの実行時間といった実行時のメタ情報に加えて、前後の結果やバージョン管理のどのコミットか、さらにはテストコードまで見られるので、Cypressコードの解析まで含めた実行環境としてはかなりのハイクオリティ。録画すれば実行時の動画もみられる様子。すげー

テスト結果分析のダッシュボードとして優秀。だけど実行回数の制限が絶妙にきつい。チュートリアルの実践という意味からそれて実行計画考えると、テストケース小さく作るとすぐ食いつぶすし頻度もデイリーだと17件とかしかできない。プッシュタイミングとかやるとすぐ食いつぶすだろうからマージタイミングとかでやることになるかもだけど個人でわざわざみたいな話になる。アクティブなプロジェクトに対して週末プログラミングのお供で使うくらいがいいのかな。Teamプランだとデイリー340くらい。複数プロジェクトで使うとどうなんだろうという数字。

circle ci

注意点

  • Organization settingのsecurityでサードパーティorbの許可を出す
  • Project SettingでEnvironment Variable にCYPRESS_RECORD_KEYを設定する
  • CypressのScaffoldコード使うならconfig.ymlのnpm startは該当コードないので消しとく

config.ymlはポチポチしてたら出てきたサンプルから自分のアプリ起動用のnpm startを消した形。以下の通り

version: 2.1
# Uses the official Cypress Orb
# https://circleci.com/developer/orbs/orb/cypress-io/cypress
orbs:
  cypress: cypress-io/cypress@3
workflows:
  build:
    jobs:
      - cypress/run:
          # For recording and parallelization to work you must set your CYPRESS_RECORD_KEY
          # in CircleCI → Project Settings → Environment Variables
          # Records in parallel to Cypress Cloud 
          # https://docs.cypress.io/guides/guides/parallelization
          parallelism: 2 # Uses 2 parallel instances
          # Starts web server for E2E tests - replace with your own server invocation
          # https://docs.cypress.io/guides/continuous-integration/introduction#Boot-your-server
          cypress-command: 'npx cypress run --record --parallel'

めんどいからコメント残してるけど要はnpx cypress run セットアップは案内されたorb何も考えず使ってるのでようわからん。変なもんじゃ無さげだし

Cypress Cloudにも結果が乗るけどCircle CI側のクレジットが増えてるし結果流れただけで流石にCircle CI側のインスタンス使ってるはず

Cypress CloudのUsage & BillingみるとAdditionalあるのが心臓に悪いんだけど流石にこれ請求外であってるんだろうか。上の円グラフは増えてないしそう思いたい。怖い

後日見たらしっかり上限突破してました、ダメじゃねえか。Circle CIのクレジット何で減ってんだよ。

You've reached 124% of your test results for this usage period. Parallelization has been disabled and run details will be hidden. To re-enable parallelization and to see new runs, you can upgrade your plan or wait until your usage period resets.

らしくて、どうやら結果詳細は見れないし並列化も無効になるよ。とのこと。請求ない様子で一安心だけどこのプロジェクトは停止だわ。両方の費用消耗するなら流石に効率悪すぎね?連携する意義ある?

Circle CIで実行したときの結果をCypress Cloudのダッシュボードで見るとparallelism: 2が効いててちゃんと2並列で動いてるっぽい。

Circle CI連携のRunのOverviewのTests for reviewは空になった。なんで?地味に画面上部にcircle ci側のworkflowのIDが表示されて、それのWebページへのリンクになっている

頭のほうに箇条書きしたけど、Circle CI側でorb許可やEnvironment ValiableへのCYPRESS_RECORD_KEYの設定は行っておくこと

モダンな開発環境、CIを整えてかっこいいテスト結果確認ダッシュボードまで構築できるんで結構楽しいチュートリアル。学べるものも以下の通り多い。

  • Cypressのサンプルコードの入手方法
  • Cypressによるテストプロジェクトの構築
  • Cypressによるテスト実行
    • ローカル
    • Cypress Cloudによるリモート
  • Circle CIでCypressのテストを実行する方法
    • config.ymlの書き方

が、Cypress Cloud周りが罠

  • Free Planを食いつぶす
    • サンプルケース175ほどに対してFree Plan上限500なんで3回リトライしたらおわる
  • Circle CI連携がほぼ無意味
    • 両方のクレジットを消費する
    • 二重にコストをかけて、結果を両方で見られるだけ

リスクを把握して楽しくチュートリアル