Cypress E2Eテスト:ゼロから実践的なCI/CDパイプラインまで

Development tutorial - IT technology blog
Development tutorial - IT technology blog

5分で動くデモを作成する

退屈な理論に時間を費やす代わりに、まずは手を動かして即座に結果を確認しましょう。Cypressは非常に習得が容易です。以前のSeleniumのように、従来のUIテスト自動化ツールにありがちな複雑なドライバーのインストールや面倒な設定は必要ありません。

まず、新しいディレクトリを作成し、いくつかの簡単なコマンドでプロジェクトを初期化します。

mkdir cypress-demo && cd cypress-demo
npm init -y
npm install cypress --save-dev

インストールが完了したら、Cypressのコントロールパネルを起動しましょう。

npx cypress open

直感的なウィンドウが表示されます。E2E Testingを選択し、Continueをクリックして、Cypressに必要な設定ファイルを自動生成させます。次に、お好みのブラウザ(ChromeやEdgeなど)を選択し、Start E2E Testingをクリックします。

では、最初のテストファイルを cypress/e2e/first_test.cy.js に作成しましょう。

describe('My First Test', () => {
  it('itfromzero.comにアクセスしてタイトルを確認する', () => {
    cy.visit('https://itfromzero.com')
    cy.contains('Development').should('be.visible')
  })
})

Cypressの画面に戻り、作成したファイルをクリックしてください。ブラウザが自動的に開き、サイトにアクセスして要素を瞬時に検証する様子が確認できます。これで最初のE2Eテストは完了です!

なぜCypressは従来のツールより優れているのか?

私はかつて、5万行を超えるレガシーシステムのリファクタリングに携わったことがあります。その時の教訓は、適切なテストカバレッジがなければ、古いロジックの修正は綱渡りと同じだということです. Seleniumを使用していた頃は、要素の読み込みが間に合わずテストが成功したり失敗したりする「Flaky Test(不安定なテスト)」に頻繁に悩まされていました。

Cypressは、以下の3つの強力な機能でゲームチェンジャーとなりました:

  • Automatic Waiting: 感覚的に time.sleep(5) を入れる必要はもうありません。Cypressは要素が表示されるか、期待される状態になるまで自動的に待機します。
  • Real-time Reloads: テストコードを保存(Ctrl+S)した瞬間に、Cypressが自動で再実行します。デバッグのプロセスが劇的に速くなります。
  • Time Travel: 実行された各コマンドにマウスホバーすると、その時点のUIの状態を確認できます。詳細なビデオ記録を見ているような感覚です。

プロフェッショナルなテスト構成

プロジェクトが数百のテストケースに拡大する場合、ディレクトリ構造を整理することが不可欠です。標準的な構成は以下の通りです:

  • cypress/e2e/: テストシナリオを格納する場所。プロセス全体の心臓部です。
  • cypress/fixtures/: JSONなどの静的データを保存します。例:モックAPI用のユーザー情報や商品リストなど.
  • cypress/support/: Custom Commandsを定義する場所です。100個のファイルでログイン処理を繰り返す代わりに、共通の cy.login() コマンドを1つ書くだけで済みます。

実践シナリオ:ログインフローのテスト

正常系だけでなく、未入力や誤入力のケースもカバーするのが質の高いテストです。

describe('ログイン機能', () => {
  beforeEach(() => {
    cy.visit('/login') // Base URLはcypress.config.jsで一括設定されています
  })

  it('パスワードが空の場合にエラーメッセージを表示する', () => {
    cy.get('input[name="email"]').type('[email protected]')
    cy.get('button[type="submit"]').click()
    cy.get('.error-message').should('contain', 'パスワードを入力してください')
  })

  it('有効なアカウントで正常に遷移する', () => {
    cy.get('input[name="email"]').type('[email protected]')
    cy.get('input[name="password"]').type('password123')
    cy.get('button[type="submit"]').click()
    
    cy.url().should('include', '/dashboard')
    cy.get('h1').should('contain', '管理者様、ようこそ')
  })
})

cy.intercept() によるAPIモック技術

これはテストを100%安定させるための秘密兵器です。バックエンドがメンテナンス中だったり、サードパーティのAPI(決済ゲートウェイなど)のレスポンスが遅い場合があります。Cypressでは、これらのリクエストを「傍受(インターセプト)」し、即座にダミーデータを返すことができます。

it('APIからの記事リストをモックする', () => {
  cy.intercept('GET', '/api/posts', { fixture: 'posts.json' }).as('getPosts')
  
  cy.visit('/blog')
  cy.wait('@getPosts')
  
  cy.get('.post-item').should('have.length', 3)
})

このアプローチにより、サーバーの実際の処理を待つ必要がなくなるため、テストの実行時間を数分から数秒に短縮できます。

GitHub Actionsによる自動化

誤ってバグのあるコードをマージしないように、CypressをCI/CDパイプラインに組み込む必要があります。これにより、プルリクエストが作成されるたびにシステムが自動的にコードをチェックします。

以下は、シンプルな .github/workflows/main.yml 設定ファイルです:

name: E2E Tests
on: [push]
jobs:
  cypress-run:
    runs-on: ubuntu-latest
    steps:
      - name: コードをチェックアウト
        uses: actions/checkout@v4

      - name: Cypressを実行
        uses: cypress-io/github-action@v6
        with:
          build: npm run build
          start: npm start
          wait-on: 'http://localhost:3000'

テストケースが1つでも失敗すると、GitHubに赤マークが表示されデプロイがブロックされます。これにより、本番環境を常に安全に保つことができます。

プロジェクトを破綻させないための実践的な経験則

実際のプロジェクトでCypressを6ヶ月以上運用して得られた、4つの黄金律を紹介します:

  1. data-cyを優先する: CSSクラス( .btn-blue など)で要素を選択するのは避けましょう。リファクタリングで変更されやすいためです。堅牢なテストのために data-cy="submit-button" を使用してください。
  2. cy.wait(秒数)を絶対に避ける: スクリプトを3〜5秒停止させるのは、プロジェクトを遅くする最短ルートです。柔軟なタイムアウト設定や、APIのエイリアス待機を利用しましょう。
  3. 状態を分離する (State Isolation): 各テストケースは独立している必要があります。 beforeEach でデータベースのリセットやクッキーの削除を行い、前のテストケースが次に影響を与えないようにします。
  4. CIリソースを最適化する: サーバー上で実行する際は、常にHeadlessモード(画面なし)を使用してください。これにより、CIシステムのRAMとCPUを大幅に節約できます。

Webアプリケーションを構築しているなら、今すぐ導入を検討してみてください。Cypressは単なるテストツールではありません。開発者がリリース前に枕を高くして眠れるようにするためのソリューションです。

CypressをDockerやNext.jsで設定するのに苦労していませんか?下のコメント欄であなたの悩みを共有してください!

Share: