強力なエンドツーエンドテストフレームワークであるCypressの包括的なガイド。インストール、テストの作成、デバッグ、CI/CD統合、およびベストプラクティスについて説明します。
Cypress: Webアプリケーションのための究極のエンドツーエンドテストガイド
今日の急速に進化するWeb開発の状況において、Webアプリケーションの品質と信頼性を確保することは最も重要です。エンドツーエンド(E2E)テストは、アプリケーションのすべてのコンポーネントがユーザーの視点からシームレスに連携して動作することを確認する上で重要な役割を果たします。Cypressは、開発者にとって使いやすいエクスペリエンス、強力な機能、および優れたパフォーマンスを提供する、主要なE2Eテストフレームワークとして登場しました。この包括的なガイドでは、Cypressを使い始め、Webアプリケーションを効果的にテストするために知っておくべきことをすべて説明します。
Cypressとは?
Cypressは、現代のWeb向けに構築された次世代のフロントエンドテストツールです。ブラウザでテストを実行する従来のテストフレームワークとは異なり、Cypressはブラウザ内で直接動作し、アプリケーションの動作に対する比類のない制御と可視性を提供します。高速で信頼性が高く、使いやすいように設計されており、世界中の開発者やQAエンジニアの間で人気のある選択肢となっています。CypressはJavaScriptで記述されており、ブラウザ内で実行されるため、非常にパフォーマンスが高く、アプリケーションの内部への比類のないアクセスを提供します。
Cypressを使用する主な利点
- 開発者にとって使いやすい: Cypressは、クリーンで直感的なAPIを提供し、テストの作成とデバッグを容易にします。
- タイムトラベル: Cypressは、各テストコマンド中にアプリケーションの状態のスナップショットを取得し、時間を遡って、任意の時点で何が起こったかを正確に確認できます。
- リアルタイムリロード: テストに変更を加えると、Cypressは自動的にリロードし、即座にフィードバックを提供します。
- 自動待機: Cypressは、アクションを実行する前に、要素が表示または操作可能になるまで自動的に待機するため、明示的な待機は不要です。
- ネットワーク制御: Cypressを使用すると、ネットワークリクエストとレスポンスをスタブできるため、さまざまなシナリオをシミュレートし、アプリケーションのエラー処理をテストできます。
- デバッグ可能性: Cypressは、強力なデバッガーや詳細なエラーメッセージなど、優れたデバッグツールを提供します。
- クロスブラウザテスト: Cypressは、Chrome、Firefox、Edge、Electronなどの複数のブラウザをサポートします。
- ヘッドレステスト: CI/CD環境での高速実行のために、ヘッドレスモードでテストを実行します。
- 組み込みアサーション: Cypressは、アプリケーションの期待される動作を検証するための豊富な組み込みアサーションセットを提供します。
インストールとセットアップ
Cypressの開始は簡単です。インストール方法は次のとおりです。
- 前提条件: システムにNode.jsとnpm(Node Package Manager)がインストールされていることを確認します。これらは、公式のNode.js Webサイトからダウンロードできます。
- Cypressのインストール: ターミナルまたはコマンドプロンプトを開き、プロジェクトディレクトリに移動して、次のコマンドを実行します。
- Cypressを開く: インストールが完了したら、次を実行してCypress Test Runnerを開くことができます。
npm install cypress --save-dev
npx cypress open
このコマンドはCypress Test Runnerを起動し、テストの実行とデバッグのためのグラフィカルインターフェイスを提供します。
最初のCypressテストの作成
Webサイトのホームページが正しく読み込まれることを確認するための簡単なテストを作成しましょう。プロジェクトの`cypress/e2e`ディレクトリに`example.cy.js`という名前の新しいファイルを作成します。
// cypress/e2e/example.cy.js
describe('My First Test', () => {
it('Visits the Kitchen Sink', () => {
cy.visit('https://example.cypress.io')
cy.contains('type').click()
cy.url().should('include', '/commands/actions')
cy.get('.action-email')
.type('fake@email.com')
.should('have.value', 'fake@email.com')
})
})
このテストを分解してみましょう。
- `describe()`: テストスイートを定義します。これは、関連するテストのコレクションです。
- `it()`: テストスイート内の個々のテストケースを定義します。
- `cy.visit()`: 指定されたURLに移動します。
- `cy.contains()`: 指定されたテキストを含む要素を検索します。
- `.click()`: 選択された要素をクリックします。
- `cy.url()`: ページの現在のURLを取得します。
- `.should()`: アプリケーションの状態についてアサーションを行います。
- `cy.get()`: CSSセレクターを使用して要素を選択します。
- `.type()`: 選択された要素にテキストを入力します。
- `.should('have.value', 'fake@email.com')`: 要素の値が「fake@email.com」と等しいことを表明します。
このテストをCypress Test Runnerで実行して、動作を確認してください。ブラウザがCypress Kitchen Sink Webサイトに移動し、「type」リンクをクリックして、URLを確認する必要があります。
Cypressコマンド
Cypressは、アプリケーションと対話するための幅広いコマンドを提供します。最も一般的に使用されるコマンドを次に示します。
- `cy.visit(url)`: 指定されたURLに移動します。
- `cy.get(selector)`: CSSセレクターを使用して要素を選択します。
- `cy.contains(content)`: 指定されたテキストを含む要素を選択します。
- `cy.click()`: 選択された要素をクリックします。
- `cy.type(text)`: 選択された要素にテキストを入力します。
- `cy.clear()`: 入力またはテキストエリア要素の内容をクリアします。
- `cy.submit()`: フォームを送信します。
- `cy.check()`: チェックボックスまたはラジオボタンをオンにします。
- `cy.uncheck()`: チェックボックスをオフにします。
- `cy.select(value)`: ドロップダウンからオプションを選択します。
- `cy.scrollTo(position)`: ページを指定された位置までスクロールします。
- `cy.trigger(event)`: 選択された要素でDOMイベントをトリガーします。
- `cy.request(url, options)`: 指定されたURLにHTTPリクエストを行います。
- `cy.intercept(route, handler)`: 指定されたルートに一致するHTTPリクエストをインターセプトします。
- `cy.wait(time)`: 指定された時間待機します。
- `cy.reload()`: 現在のページをリロードします。
- `cy.go(direction)`: ブラウザの履歴で前または次のページに移動します。
- `cy.url()`: ページの現在のURLを取得します。
- `cy.title()`: ページのタイトルを取得します。
- `cy.window()`: ウィンドウオブジェクトを取得します。
- `cy.document()`: ドキュメントオブジェクトを取得します。
- `cy.viewport(width, height)`: ビューポートのサイズを設定します。
これらは、Cypressで使用できる多くのコマンドのほんの一部です。コマンドとそのオプションの完全なリストについては、Cypressドキュメントを参照してください。
Cypressのアサーション
アサーションは、アプリケーションの期待される動作を検証するために使用されます。Cypressは、要素の状態、URL、タイトルなどを確認するために使用できる豊富な組み込みアサーションセットを提供します。アサーションは、`.should()`メソッドを使用してCypressコマンドの後にチェーンされます。
一般的なアサーションの例を次に示します。
- `.should('be.visible')`: 要素が表示されることをアサートします。
- `.should('not.be.visible')`: 要素が表示されないことをアサートします。
- `.should('be.enabled')`: 要素が有効になっていることをアサートします。
- `.should('be.disabled')`: 要素が無効になっていることをアサートします。
- `.should('have.text', 'expected text')`: 要素に指定されたテキストが含まれていることをアサートします。
- `.should('contain', 'expected text')`: 要素に指定されたテキストが含まれていることをアサートします。
- `.should('have.value', 'expected value')`: 要素に指定された値が含まれていることをアサートします。
- `.should('have.class', 'expected class')`: 要素に指定されたクラスが含まれていることをアサートします。
- `.should('have.attr', 'attribute name', 'expected value')`: 要素に指定された属性と値が含まれていることをアサートします。
- `.should('have.css', 'css property', 'expected value')`: 要素に指定されたCSSプロパティと値が含まれていることをアサートします。
- `.should('have.length', expected length)`: 要素に指定された長さ(リスト内の要素数など)があることをアサートします。
特定のニーズに合わせてカスタムアサーションを作成することもできます。
Cypressテストを作成するためのベストプラクティス
ベストプラクティスに従うと、より保守性、信頼性、効率性の高いCypressテストを作成できます。いくつかの推奨事項を次に示します。
- 明確で簡潔なテストを作成する: 各テストは、特定の機能またはシナリオに焦点を当てる必要があります。理解および保守が困難な過度に複雑なテストを作成することは避けてください。
- 意味のあるテスト名を使用する: テスト対象を明確に示す記述的な名前をテストに付けます。
- 値をハードコーディングしない: 時間の経過とともに変更される可能性のある値を格納するには、変数または構成ファイルを使用します。
- カスタムコマンドを使用する: 再利用可能なロジックをカプセル化し、テストを読みやすくするために、カスタムコマンドを作成します。
- テストを分離する: 各テストは、他のテストから独立している必要があります。以前のテストからのアプリケーションの状態に依存することは避けてください。
- テスト後にクリーンアップする: 後続のテストがクリーンな状態から開始されるように、各テスト後にアプリケーションの状態をリセットします。
- データ属性を使用する: テストで要素を選択するには、データ属性(例:`data-testid`)を使用します。データ属性はCSSクラスやIDよりも変更される可能性が低いため、テストはUIの変更に対してより回復力があります。
- 明示的な待機を避ける: Cypressは、要素が表示または操作可能になるまで自動的に待機します。明示的な待機(例:`cy.wait()`)は、どうしても必要な場合を除き、使用しないでください。
- ユーザフローをテストする: 個々のコンポーネントではなく、ユーザフローのテストに焦点を当てます。これにより、アプリケーションがユーザの視点から正しく動作することが保証されます。
- テストを定期的に実行する: CypressテストをCI/CDパイプラインに統合し、開発プロセスの早い段階でバグをキャッチするために定期的に実行します。
高度なCypressテクニック
スタブとモック
Cypressを使用すると、ネットワークリクエストとレスポンスをスタブできるため、さまざまなシナリオをシミュレートし、アプリケーションのエラー処理をテストできます。これは、外部APIまたはサービスに依存する機能をテストする場合に特に役立ちます。
ネットワークリクエストをスタブするには、`cy.intercept()`コマンドを使用できます。たとえば、次のコードは、`/api/users`へのGETリクエストをスタブし、モックレスポンスを返します。
cy.intercept('GET', '/api/users', {
statusCode: 200,
body: [
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Doe' }
]
}).as('getUsers')
次に、`cy.wait('@getUsers')`を使用してインターセプトされたリクエストを待機し、アプリケーションがモックレスポンスを正しく処理することを確認できます。
ローカルストレージとCookieの操作
Cypressは、ローカルストレージとCookieを操作するためのコマンドを提供します。これらのコマンドを使用して、テストでローカルストレージとCookieを設定、取得、およびクリアできます。
ローカルストレージアイテムを設定するには、`cy.window()`コマンドを使用してwindowオブジェクトにアクセスし、`localStorage.setItem()`メソッドを使用します。例えば:
cy.window().then((win) => {
win.localStorage.setItem('myKey', 'myValue')
})
ローカルストレージアイテムを取得するには、`cy.window()`コマンドを使用して、`localStorage.getItem()`メソッドを使用します。例えば:
cy.window().then((win) => {
const value = win.localStorage.getItem('myKey')
expect(value).to.equal('myValue')
})
Cookieを設定するには、`cy.setCookie()`コマンドを使用できます。例えば:
cy.setCookie('myCookie', 'myCookieValue')
Cookieを取得するには、`cy.getCookie()`コマンドを使用できます。例えば:
cy.getCookie('myCookie').should('have.property', 'value', 'myCookieValue')
ファイルアップロードの処理
Cypressは、テストでのファイルアップロードを簡素化する`cypress-file-upload`というプラグインを提供します。プラグインをインストールするには、次のコマンドを実行します。
npm install -D cypress-file-upload
次に、次の行を`cypress/support/commands.js`ファイルに追加します。
import 'cypress-file-upload';
次に、`cy.uploadFile()`コマンドを使用してファイルをアップロードできます。例えば:
cy.get('input[type="file"]').attachFile('example.txt')
IFrameの操作
IFrameのテストは難しい場合がありますが、CypressはIFrameを操作する方法を提供します。`cy.frameLoaded()`コマンドを使用してIFrameのロードを待機し、`cy.iframe()`コマンドを使用してIFrameのdocumentオブジェクトを取得できます。
cy.frameLoaded('#myIframe')
cy.iframe('#myIframe').find('button').click()
Cypressと継続的インテグレーション/継続的デプロイメント(CI/CD)
アプリケーションの品質を確保するには、CypressをCI/CDパイプラインに統合することが不可欠です。CI/CD環境でCypressテストをヘッドレスモードで実行できます。方法は次のとおりです。
- Cypressのインストール: Cypressがプロジェクトの依存関係としてインストールされていることを確認します。
- CI/CDの構成: 各ビルド後にCypressテストを実行するようにCI/CDパイプラインを構成します。
- Cypressをヘッドレスで実行する: `cypress run`コマンドを使用して、Cypressテストをヘッドレスモードで実行します。
CI/CD構成の例(GitHub Actionsを使用):
name: Cypress Tests
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
cypress-run:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: 16
- name: Install dependencies
run: npm install
- name: Cypress run
uses: cypress-io/github-action@v5
with:
start: npm start
wait-on: 'http://localhost:3000'
この構成は、コードが`main`ブランチにプッシュされるか、`main`ブランチに対してプルリクエストが作成されるたびにCypressテストを実行します。`cypress-io/github-action`アクションは、GitHub ActionsでのCypressテストの実行プロセスを簡素化します。
Cypressテストのデバッグ
Cypressは、テストの問題を特定して修正するのに役立つ優れたデバッグツールを提供します。Cypressテストをデバッグするためのヒントを次に示します。
- Cypress Test Runnerを使用する: Cypress Test Runnerは、テストを実行およびデバッグするための視覚的なインターフェイスを提供します。テストを一度に1つのコマンドずつステップ実行したり、アプリケーションの状態を検査したり、詳細なエラーメッセージを表示したりできます。
- `cy.pause()`コマンドを使用する: `cy.pause()`コマンドは、テストの実行を一時停止し、ブラウザの開発者ツールでアプリケーションの状態を検査できるようにします。
- `cy.debug()`コマンドを使用する: `cy.debug()`コマンドは、選択された要素をコンソールに出力し、そのプロパティと属性を検査できるようにします。
- ブラウザの開発者ツールを使用する: ブラウザの開発者ツールは、DOM、ネットワークリクエスト、コンソールログなど、アプリケーションに関する豊富な情報を提供します。
- エラーメッセージを注意深く読む: Cypressは、エラーの原因を特定するのに役立つ詳細なエラーメッセージを提供します。エラーメッセージとスタックトレースに注意してください。
Cypressと他のテストフレームワーク
Cypressは強力なエンドツーエンドテストフレームワークですが、他の一般的なオプションと比較してどのように機能するかを理解することが重要です。簡単な概要を次に示します。
- Selenium: Seleniumは、広く使用されている自動化テストフレームワークです。柔軟性があり、複数の言語をサポートしていますが、セットアップと保守が複雑になる可能性があります。Cypressは、特にJavaScriptベースのアプリケーションの場合、よりシンプルで開発者にとって使いやすいエクスペリエンスを提供します。
- Puppeteer: Puppeteerは、ヘッドレスChromeまたはChromiumを制御するための高レベルAPIを提供するNodeライブラリです。スクレイピングやブラウザタスクの自動化に優れていますが、エンドツーエンドテストの場合、Cypressと比較してより多くの手動構成が必要になる場合があります。
- Playwright: Playwrightは、Microsoftが開発した別のクロスブラウザ自動化フレームワークです。Puppeteerと類似点がありますが、より幅広いブラウザサポートを提供します。Cypressには、独自のタイムトラベルデバッガーと、より統合されたテストエクスペリエンスがあります。
フレームワークの選択は、プロジェクトの特定のニーズと要件によって異なります。Cypressは、高速で信頼性が高く、開発者にとって使いやすいエンドツーエンドテストを必要とする最新のWebアプリケーションに最適です。
Cypressの実際の使用例
Cypressを使用してさまざまな種類のWebアプリケーションをテストする方法の実際の例をいくつか見てみましょう。
Eコマースアプリケーションのテスト
Cypressを使用して、Eコマースアプリケーションのさまざまなユーザフローをテストできます。例:
- 製品の検索
- カートへの製品の追加
- チェックアウトと注文
- アカウント設定の管理
ユーザーが正常に製品をカートに追加できることを確認するCypressテストの例を次に示します。
it('カートに製品を追加する', () => {
cy.visit('/products')
cy.get('.product-card').first().find('button').click()
cy.get('.cart-count').should('have.text', '1')
})
ソーシャルメディアアプリケーションのテスト
Cypressを使用して、ソーシャルメディアアプリケーションでのユーザーインタラクションをテストできます。例:
- 新しい投稿の作成
- 投稿へのいいね
- 投稿へのコメント
- 他のユーザーのフォロー
ユーザーが新しい投稿を正常に作成できることを確認するCypressテストの例を次に示します。
it('新しい投稿を作成する', () => {
cy.visit('/profile')
cy.get('#new-post-textarea').type('Hello, world!')
cy.get('#submit-post-button').click()
cy.get('.post').first().should('contain', 'Hello, world!')
})
銀行アプリケーションのテスト
銀行アプリケーションの場合、Cypressを使用して、次のような重要な機能をテストできます。
- 安全なログイン
- 口座残高の確認
- 送金
- 受益者の管理
送金を確認するテストは、次のようになります(セキュリティのために適切なスタブを使用)。
it('送金を正常に行う', () => {
cy.visit('/transfer')
cy.get('#recipient-account').type('1234567890')
cy.get('#amount').type('100')
cy.intercept('POST', '/api/transfer', { statusCode: 200, body: { success: true } }).as('transfer')
cy.get('#transfer-button').click()
cy.wait('@transfer')
cy.get('.success-message').should('be.visible')
})
結論
Cypressは、Webアプリケーションの品質と信頼性を確保するのに役立つ、強力で用途の広いエンドツーエンドテストフレームワークです。開発者にとって使いやすいAPI、強力な機能、および優れたパフォーマンスにより、世界中の開発者やQAエンジニアの間で人気のある選択肢となっています。このガイドで概説されているベストプラクティスに従うことで、開発プロセスの早い段階でバグをキャッチし、高品質のソフトウェアをユーザーに提供するのに役立つ効果的なCypressテストを作成できます。
Webアプリケーションが進化し続けるにつれて、エンドツーエンドテストの重要性はますます高まります。Cypressを採用し、開発ワークフローに統合することで、より堅牢で信頼性が高く、ユーザーフレンドリーなWebエクスペリエンスを構築できます。