スナップショットテスト
概要
Playwrightのスナップショットテストでは、ページのアクセシビリティツリーを事前定義されたスナップショットテンプレートに対して検証できます。
- 同期
- 非同期
page.goto('https://playwright.dokyumento.jp/')
expect(page.query_selector('banner')).to_match_aria_snapshot("""
- banner:
- heading /Playwright enables reliable end-to-end/ [level=1]
- link "Get started"
- link "Star microsoft/playwright on GitHub"
- link /[\\d]+k\\+ stargazers on GitHub/
""")
await page.goto('https://playwright.dokyumento.jp/')
await expect(page.query_selector('banner')).to_match_aria_snapshot("""
- banner:
- heading /Playwright enables reliable end-to-end/ [level=1]
- link "Get started"
- link "Star microsoft/playwright on GitHub"
- link /[\\d]+k\\+ stargazers on GitHub/
""")
アサーションテストとスナップショットテスト
スナップショットテストとアサーションテストは、テスト自動化において異なる目的を果たします。
アサーションテスト
アサーションテストは、要素やコンポーネントに関する特定の値や条件を検証する対象を絞ったアプローチです。例えば、Playwrightでは、expect(locator).to_have_text()
は要素が期待されるテキストを含んでいることを検証し、expect(locator).to_have_value()
は入力フィールドが期待される値を持っていることを確認します。アサーションテストは具体的で、一般的に要素やプロパティの現在の状態を、期待される事前定義された状態と照合します。予測可能で単一値のチェックには効果的ですが、より広範な構造やバリエーションをテストする際には範囲が限られます。
利点
- 明確さ:テストの意図が明確で理解しやすい。
- 具体性:テストは機能の特定の側面に焦点を当てるため、無関係な変更に対してより堅牢です。
- デバッグ:失敗時には的を絞ったフィードバックが提供され、問題のある側面に直接対処できます。
欠点
- 複雑な出力に対する冗長性:複雑なデータ構造や大規模な出力に対してアサーションを記述するのは、手間がかかりエラーが発生しやすい可能性があります。
- メンテナンスのオーバーヘッド:コードの進化に伴い、手動でアサーションを更新するのは時間がかかる場合があります。
スナップショットテスト
スナップショットテストは、要素、コンポーネント、またはデータの全体の状態の「スナップショット」または表現を特定の瞬間にキャプチャし、その後に将来の比較のために保存します。テストを再実行すると、現在の状態がスナップショットと比較され、違いがあればテストは失敗します。このアプローチは、各詳細を手動でアサートするのが非常に時間がかかるような複雑な構造や動的な構造に特に役立ちます。スナップショットテストはアサーションテストよりも広範で包括的であり、時間とともに発生するより複雑な変更を追跡できます。
利点
- 複雑な出力を簡素化:例えば、UIコンポーネントのレンダリングされた出力をテストすることは、従来のアサーションでは退屈な作業になる可能性があります。スナップショットは、比較を容易にするために出力全体をキャプチャします。
- 迅速なフィードバックループ:開発者は出力の意図しない変更を簡単に見つけることができます。
- 一貫性を促進:コードの進化に伴い、一貫した出力を維持するのに役立ちます。
欠点
- 過度の依存:スナップショットへの変更を十分に理解せずに受け入れてしまい、潜在的にバグを隠してしまう可能性があります。
- 粒度:特に軽微な変更が出力の大半に影響を与える場合、差異が生じた際に大規模なスナップショットを解釈するのが難しい場合があります。
- 適合性:出力が頻繁にまたは予測不能に変化するような、非常に動的なコンテンツには理想的ではありません。
使用するタイミング
- スナップショットテストは以下の場合に最適です。
- ページ全体とコンポーネントのUIテスト。
- 複雑なUIコンポーネントの広範な構造チェック。
- 構造がめったに変わらない出力の回帰テスト。
- アサーションテストは以下の場合に最適です。
- コアロジックの検証。
- 計算値のテスト。
- 正確な条件を必要とするきめ細かいテスト。
広範な構造チェックにスナップショットテストを、特定の機能にアサーションテストを組み合わせることで、バランスの取れたテスト戦略を確立できます。
Ariaスナップショット
Playwrightでは、AriaスナップショットはページのアクセシビリティツリーをYAML形式で表現します。これらのスナップショットは保存され、後で比較することで、ページ構造が一貫しているか、または定義された期待値と一致しているかを確認できます。
YAML形式は、ページのアクセシブルな要素の階層構造を記述し、ロール、属性、値、およびテキストコンテンツを詳述します。構造はツリー状の構文に従い、各ノードはアクセシブルな要素を表し、インデントはネストされた要素を示します。
ツリー内の各アクセシブルな要素はYAMLノードとして表現されます。
- role "name" [attribute=value]
- role:要素のARIAまたはHTMLロールを指定します(例:
heading
、list
、listitem
、button
)。 - "name":要素のアクセシブル名。引用符で囲まれた文字列は正確な値を示し、
/patterns/
は正規表現に使用されます。 - [attribute=value]:角括弧内の属性と値は、
checked
、disabled
、expanded
、level
、pressed
、selected
などの特定のARIA属性を表します。
これらの値はARIA属性から派生するか、HTMLセマンティクスに基づいて計算されます。ページのアクセシビリティツリー構造を検査するには、Chrome DevToolsのアクセシビリティタブを使用してください。
スナップショットマッチング
Playwrightのexpect(locator).to_match_aria_snapshot()
アサーションメソッドは、ロケータースコープのアクセシブルな構造を事前定義されたariaスナップショットテンプレートと比較し、ページのAria状態をテスト要件に対して検証するのに役立ちます。
以下のDOMの場合
<h1>title</h1>
以下のスナップショットテンプレートを使用して一致させることができます。
- 同期
- 非同期
expect(page.locator("body")).to_match_aria_snapshot("""
- heading "title"
""")
await expect(page.locator("body")).to_match_aria_snapshot("""
- heading "title"
""")
マッチング時、スナップショットテンプレートはページの現在のアクセシビリティツリーと比較されます。
- ツリー構造がテンプレートと一致すればテストは合格し、一致しない場合は失敗し、期待されるアクセシビリティ状態と実際のアクティビティ状態との不一致を示します。
- 比較は大文字と小文字を区別し、空白は削除されるため、インデントと改行は無視されます。
- 比較は順序に敏感であり、スナップショットテンプレート内の要素の順序がページのアクセシビリティツリー内の順序と一致する必要があります。
部分マッチング
属性やアクセシブル名を省略することで、ノードの部分一致を実行でき、厳密な一致を必要とせずにアクセシビリティツリーの特定の部分を検証できます。この柔軟性は、動的な属性や関連性のない属性に役立ちます。
<button>Submit</button>
ariaスナップショット
- button
この例では、ボタンのロールは一致しますが、アクセシブル名(「Submit」)は指定されていないため、ボタンのラベルに関係なくテストが合格します。
checked
や disabled
のようなARIA属性を持つ要素の場合、これらの属性を省略することで部分マッチングが可能になり、ロールと階層のみに焦点を当てることができます。
<input type="checkbox" checked>
部分一致のためのariaスナップショット
- checkbox
この部分一致では、checked
属性は無視されるため、チェックボックスの状態に関係なくテストは合格します。
同様に、特定のリスト項目やネストされた要素を省略することで、リストやグループ内の子を部分的に一致させることもできます。
<ul>
<li>Feature A</li>
<li>Feature B</li>
<li>Feature C</li>
</ul>
部分一致のためのariaスナップショット
- list
- listitem: Feature B
部分一致により、特定のコンテンツや属性を強制することなく、必須のページ構造を検証する柔軟なスナップショットテストを作成できます。
厳密なマッチング
デフォルトでは、子要素のサブセットを含むテンプレートが一致します。
<ul>
<li>Feature A</li>
<li>Feature B</li>
<li>Feature C</li>
</ul>
部分一致のためのariaスナップショット
- list
- listitem: Feature B
/children
プロパティは、子要素がどのようにマッチングされるかを制御するために使用できます。
contain
(デフォルト):指定されたすべての子が順番に存在する場合に一致します。equal
:子が指定されたリストと順番に完全に一致する場合に一致します。deep-equal
:子が、ネストされた子を含め、指定されたリストと順番に完全に一致する場合に一致します。
<ul>
<li>Feature A</li>
<li>Feature B</li>
<li>Feature C</li>
</ul>
Feature Cがテンプレートにないため、ariaスナップショットは失敗します。
- list
- /children: equal
- listitem: Feature A
- listitem: Feature B
正規表現によるマッチング
正規表現を使用すると、動的または可変テキストを持つ要素に対して柔軟なマッチングが可能です。アクセシブル名とテキストは正規表現パターンをサポートできます。
<h1>Issues 12</h1>
正規表現を使用したariaスナップショット
- heading /Issues \d+/
スナップショットの生成
PlaywrightでAriaスナップショットを作成することは、アプリケーションの構造を確保し、維持するのに役立ちます。テストのセットアップとワークフローに応じて、さまざまな方法でスナップショットを生成できます。
Playwrightコードジェネレーターによるスナップショットの生成
Playwrightのコードジェネレーターを使用している場合、インタラクティブなインターフェースでAriaスナップショットの生成が効率化されます。
- 「スナップショットをアサート」アクション:コードジェネレーターで、「スナップショットをアサート」アクションを使用して、選択した要素のスナップショットアサーションを自動的に作成できます。これは、記録されたテストフローの一部としてariaスナップショットをキャプチャする迅速な方法です。
- 「Ariaスナップショット」タブ:コードジェネレーターインターフェース内の「Ariaスナップショット」タブは、選択したロケーターのariaスナップショットを視覚的に表示し、要素のロール、属性、アクセシブル名を探索、検査、検証して、スナップショットの作成とレビューを支援します。
Locator.ariaSnapshot
メソッドの使用
locator.aria_snapshot() メソッドを使用すると、ロケーターのスコープ内にあるアクセス可能な要素のYAML表現をプログラムで作成できます。これは、テスト実行中に動的にスナップショットを生成する際に特に役立ちます。
例:
- 同期
- 非同期
snapshot = page.locator("body").aria_snapshot()
print(snapshot)
snapshot = await page.locator("body").aria_snapshot()
print(snapshot)
このコマンドは、指定されたロケーターのスコープ内のariaスナップショットをYAML形式で出力します。必要に応じて検証または保存できます。
アクセシビリティツリーの例
レベル属性を持つ見出し
見出しには、その見出しレベルを示す level
属性を含めることができます。
<h1>Title</h1>
<h2>Subtitle</h2>
ariaスナップショット
- heading "Title" [level=1]
- heading "Subtitle" [level=2]
テキストノード
単独のテキスト要素または記述的なテキスト要素はテキストノードとして表示されます。
<div>Sample accessible name</div>
ariaスナップショット
- text: Sample accessible name
インライン複数行テキスト
段落のような複数行のテキストは、ariaスナップショットで正規化されます。
<p>Line 1<br>Line 2</p>
ariaスナップショット
- paragraph: Line 1 Line 2
リンク
リンクは、そのテキストまたは擬似要素から構成されたコンテンツを表示します。
<a href="#more-info">Read more about Accessibility</a>
ariaスナップショット
- link "Read more about Accessibility"
テキストボックス
タイプ text
の入力要素は、その value
属性の内容を表示します。
<input type="text" value="Enter your name">
ariaスナップショット
- textbox: Enter your name
項目付きリスト
順序付きリストと順序なしリストには、そのリスト項目が含まれます。
<ul aria-label="Main Features">
<li>Feature 1</li>
<li>Feature 2</li>
</ul>
ariaスナップショット
- list "Main Features":
- listitem: Feature 1
- listitem: Feature 2
グループ化された要素
グループは、サマリーコンテンツを持つ <details>
要素などのネストされた要素をキャプチャします。
<details>
<summary>Summary</summary>
<p>Detail content here</p>
</details>
ariaスナップショット
- group: Summary
属性と状態
checked
、disabled
、expanded
、level
、pressed
、selected
などの一般的に使用されるARIA属性は、コントロールの状態を表します。
checked
属性を持つチェックボックス
<input type="checkbox" checked>
ariaスナップショット
- checkbox [checked]
pressed
属性を持つボタン
<button aria-pressed="true">Toggle</button>
ariaスナップショット
- button "Toggle" [pressed=true]