Cypress スクリーンショットで始める!効果的なE2Eテスト入門

2025-03-21

スクリーンショットの役割と目的

  • 回帰テスト
    以前のバージョンと比較して、UIの変更による予期しない影響がないかを視覚的に確認できます。
  • 視覚的な検証
    特定の要素が正しく表示されているか、デザインが意図通りに実装されているかなどを視覚的に確認できます。
  • テスト結果の記録
    テスト実行後にスクリーンショットを保存することで、テスト結果の証拠として利用できます。これは、レポート作成やチーム内での共有に役立ちます。
  • デバッグ
    テストが失敗した場合、スクリーンショットを見ることで、どの時点で何が起こったのかを視覚的に確認できます。これにより、エラーの原因を特定しやすくなります。

Cypressでのスクリーンショットの取得方法

Cypressでは、cy.screenshot()コマンドを使用してスクリーンショットを撮ることができます。

  • オプション
    • cy.screenshot('ファイル名', { options })のようにオプションを指定することで、スクリーンショットの品質や範囲などを調整できます。
  • 特定の要素のスクリーンショット
    • cy.get('セレクタ').screenshot('ファイル名')のように、特定の要素に対してスクリーンショットを撮ることもできます。これにより、特定の要素のみを拡大して確認できます。
  • ファイル名の指定
    • cy.screenshot('ファイル名')のようにファイル名を指定することで、保存するスクリーンショットの名前を変更できます。
  • 基本的な使い方
    • cy.screenshot()を呼び出すと、テスト実行時の現在の画面のスクリーンショットが自動的に保存されます。
    • 保存されたスクリーンショットは、cypress/screenshotsディレクトリに保存されます。


describe('スクリーンショットのテスト', () => {
  it('スクリーンショットを撮る', () => {
    cy.visit('https://example.com');
    cy.screenshot('example_page'); // ページ全体のスクリーンショット
    cy.get('h1').screenshot('example_heading'); // h1要素のスクリーンショット
    cy.get('body').screenshot('example_body',{clip: {x: 0, y: 0, width: 500, height: 500}}); //body要素の指定範囲のスクリーンショット
  });
});

この例では、example.comにアクセスし、ページ全体のスクリーンショット、h1要素のスクリーンショット、そしてbody要素の指定範囲のスクリーンショットを撮っています。

  • CI/CD環境で実行する場合は、スクリーンショットをアーティファクトとして保存し、テスト結果とともに確認できるように設定しましょう。
  • スクリーンショットのファイル名は、テスト結果を識別しやすいように適切に命名しましょう。
  • スクリーンショットは、テストの実行速度に影響を与える可能性があります。必要な場合にのみ使用するようにしましょう。


一般的なエラーとトラブルシューティング

    • 原因
      • cypress/screenshotsディレクトリが存在しない、または書き込み権限がない。
      • テストが途中で中断された(例えば、cy.pause()を使用している場合など)。
      • CI/CD環境での設定ミス(アーティファクトの保存設定など)。
      • Cypress のバージョンが古い。
    • 解決策
      • cypress/screenshotsディレクトリが存在することを確認し、書き込み権限があることを確認します。
      • テストが正常に完了していることを確認します。
      • CI/CD環境での設定を確認し、スクリーンショットが正しく保存されるように設定します。
      • Cypress を最新バージョンにアップデートします。
  1. スクリーンショットが真っ黒または空白になる

    • 原因
      • ページが完全にロードされる前にスクリーンショットを撮っている。
      • 要素が非表示になっている、または画面外にある。
      • ハードウェアアクセラレーションに関連した問題。
      • iframe内の要素のスクリーンショットを撮ろうとしている。
    • 解決策
      • cy.wait()cy.get('セレクタ').should('be.visible')などを使用して、ページが完全にロードされるのを待ってからスクリーンショットを撮ります。
      • スクリーンショットを撮りたい要素が画面内に表示されていることを確認します。
      • Cypressの設定でハードウェアアクセラレーションを無効にしてみます。
      • iframe内の要素をスクリーンショットする場合、cy.frameLoaded()cy.iframe() を使用してiframe内に入り、その中でスクリーンショットを撮ります。
  2. 特定の要素のスクリーンショットが正しく撮れない

    • 原因
      • セレクタが間違っている。
      • 要素が動的に変化するため、スクリーンショットを撮るタイミングで要素の状態が変わっている。
      • 要素の大きさが0である。
    • 解決策
      • セレクタが正しいことを確認します。DevToolsの要素選択機能を使用してセレクタを確認するのが良いでしょう。
      • 要素の状態が安定するまで待機してからスクリーンショットを撮ります。
      • 要素の大きさが0でないか確認する。
  3. CI/CD環境でスクリーンショットが正しく表示されない

    • 原因
      • スクリーンショットのパスが間違っている。
      • CI/CD環境で必要な依存関係がインストールされていない。
      • ローカル環境とCI/CD環境の画面解像度が違う。
    • 解決策
      • スクリーンショットのパスがCI/CD環境で正しく設定されていることを確認します。
      • CI/CD環境に必要な依存関係をインストールします。
      • Cypressの設定でviewportの大きさを固定する。
  4. スクリーンショットのファイルサイズが大きすぎる

    • 原因
      • 高解像度のスクリーンショットを撮っている。
      • ページに大量の画像や動画が含まれている。
    • 解決策
      • cy.screenshot()のオプションを使用して、スクリーンショットの品質を調整します。
      • 不要な画像や動画を減らす、または圧縮します。
      • スクリーンショットのviewportのサイズを調整する。

トラブルシューティングのヒント

  • テスト実行前に、ローカル環境でスクリーンショットが正しく撮れるか確認する。
  • DevToolsを使用して、要素の状態やネットワークリクエストなどを確認します。


基本的なスクリーンショットの取得

describe('スクリーンショットの基本', () => {
  it('ページ全体のスクリーンショットを撮る', () => {
    cy.visit('https://example.com');
    cy.screenshot(); // デフォルトのファイル名で保存
  });

  it('ファイル名を指定してスクリーンショットを撮る', () => {
    cy.visit('https://example.com');
    cy.screenshot('example_page'); // ファイル名を指定して保存
  });
});
  • cy.screenshot('ファイル名'): 指定したファイル名でスクリーンショットを保存します。
  • cy.screenshot(): 現在のページのスクリーンショットをcypress/screenshotsディレクトリに保存します。ファイル名を指定しない場合は、デフォルトのファイル名が使用されます。

特定の要素のスクリーンショットの取得

describe('特定の要素のスクリーンショット', () => {
  it('特定の要素のスクリーンショットを撮る', () => {
    cy.visit('https://example.com');
    cy.get('h1').screenshot('example_heading'); // h1要素のスクリーンショットを保存
  });
});
  • cy.get('セレクタ').screenshot('ファイル名'): 指定したセレクタに一致する要素のスクリーンショットを保存します。

スクリーンショットのオプション

describe('スクリーンショットのオプション', () => {
  it('スクリーンショットの品質を調整する', () => {
    cy.visit('https://example.com');
    cy.screenshot('example_page_quality', { quality: 50 }); // 品質を50%に設定
  });

  it('スクリーンショットの領域をクリップする', () => {
    cy.visit('https://example.com');
    cy.get('body').screenshot('example_body_clip', {
      clip: { x: 100, y: 100, width: 300, height: 200 }, // 指定した領域をクリップ
    });
  });

  it('フルページスクリーンショットを撮る', () => {
    cy.visit('https://example.com');
    cy.screenshot('fullPage', {
      capture: 'fullPage',
      });
  });

  it('ブラックアウト機能を使う', () => {
    cy.visit('https://example.com');
    cy.screenshot('blackout',{
      blackout: ['h1','p'],
    });
  });

});
  • blackout: ['セレクタ1','セレクタ2']: 指定したセレクタに一致する要素を黒く塗りつぶします。
  • capture: 'fullPage': ページ全体をキャプチャします。
  • clip: スクリーンショットの領域を{ x, y, width, height }オブジェクトで指定します。
  • quality: スクリーンショットの品質を0から100の範囲で指定します。

テストが失敗したときに自動的にスクリーンショットを撮る

describe('テスト失敗時のスクリーンショット', () => {
  it('意図的に失敗するテスト', () => {
    cy.visit('https://example.com');
    cy.get('存在しない要素').should('exist'); // 意図的に失敗させる
  });
});
  • Cypressは、テストが失敗した場合、自動的にスクリーンショットをcypress/screenshotsディレクトリに保存します。
describe('beforeEachとafterEachでのスクリーンショット', () => {
  beforeEach(() => {
    cy.visit('https://example.com');
  });

  afterEach(() => {
    if (Cypress.currentTest.state === 'failed') {
      cy.screenshot(`failed-${Cypress.currentTest.title}`);
    }
  });

  it('テスト1', () => {
    cy.get('h1').should('be.visible');
  });

  it('テスト2(失敗)', () => {
    cy.get('存在しない要素').should('exist');
  });
});
  • この例では、テストが失敗した場合にのみスクリーンショットを撮るようにしています。
  • Cypress.currentTest.state: 現在実行中のテストの状態を取得します。
  • afterEach: 各テストの実行後に実行される処理を記述します。
  • beforeEach: 各テストの実行前に実行される処理を記述します。


視覚的回帰テストツールとの連携


    • Applitools Eyesを使用して、Cypressテスト内で視覚的検証を行うことができます。
    • Percyを使用して、コンポーネントやページの視覚的差異を検出できます。
  • 利点
    • 手動でのスクリーンショット比較に比べて、効率的かつ正確な視覚的検証が可能です。
    • UIのわずかな変更やデザインの崩れなどを自動的に検出できます。
    • チームでの共同作業やCI/CD環境での自動テストに適しています。
  • 説明
    • Cypressと連携可能な視覚的回帰テストツール(Applitools, Percy, Lokiなど)を利用することで、スクリーンショットの比較を自動化し、視覚的な差異を検出できます。
    • これらのツールは、ベースラインとなるスクリーンショットと現在のスクリーンショットを比較し、ピクセル単位での差異やレイアウトのずれなどを検出します。

DOMスナップショットの利用


    • cy.get('body').invoke('prop', 'outerHTML').then((html) => { /* HTMLを保存し、比較する処理 */ });
  • 欠点
    • 視覚的な検証には向いていません。あくまでDOM構造の検証です。
  • 利点
    • スクリーンショットに比べてファイルサイズが小さく、保存や比較が高速です。
    • テキストベースの比較であるため、バージョン管理システムとの連携が容易です。
    • スクリーンショットでは判別できない、要素の属性の変化などを検出できます。
  • 説明
    • スクリーンショットの代わりに、DOM(Document Object Model)のスナップショットを保存し、テスト実行後に比較する方法です。
    • DOMスナップショットは、ページのHTML構造や要素の属性などをテキスト形式で保存します。

ログの活用


    • cy.log('要素Aの値:', valueA);のように、テスト中の変数の値をログに出力します。
    • cy.on('fail', (err, runnable) => { cy.log('テスト失敗:', err.message); });のように、テスト失敗時にエラーメッセージをログに出力します。
  • 利点
    • スクリーンショットに比べて、テストの実行速度に影響を与えません。
    • エラー発生時の詳細な情報を記録できるため、デバッグに役立ちます。
  • 説明
    • スクリーンショットの代わりに、テスト実行中のログを詳細に記録し、エラー発生時の状況を把握する方法です。
    • Cypressのログ機能や、カスタムログ出力関数などを利用します。

視覚的テストライブラリの利用


    • canvas要素のデータを取得し、Pixelmatchで比較します。
  • 欠点
    • 実装が複雑になる場合があります。
  • 利点
    • 細かいピクセルレベルでの比較を実装できます。
    • 動的に生成されるcanvas要素などのテストに適しています。
  • 説明
    • Cypress内で視覚的テストライブラリ(Pixelmatchなど)を直接利用し、canvas要素などを比較する方法です。
  • 利点
    • テスト結果の可視化や分析が容易になります。
    • チームでの共同作業やCI/CD環境での自動テストに適しています。
  • 説明
    • Cypressのテスト結果を、より詳細な情報を含むレポートツール(Mocha Awesome, Allure Reportなど)と連携させることで、テスト結果の分析や共有を容易にします。