自動テストが見逃すビジュアルバグ: ユーザーが見るものをテストする方法
自動テストが見逃すビジュアルバグ: toBeVisible() と isDisplayed() が覆われた要素や読めない要素を通してしまう理由と、ユーザーが本当に見るものをテストする方法。
読了 10 分更新日: 2026年11月6日執筆: Ait Nohaila (事業開発担当)
ビジュアルバグとは、背後のコードは問題なさそうなのに、人が画面上で目にする欠陥です: 覆われたボタン、読めないテキスト、誤ったアイコンなどです。自動テストがそれを見逃すのは、画面ではなくページのコードに尋ねるからです。
ビジュアルバグとは?
エンドツーエンドテストは緑です。そこへ顧客がチェックアウトページのスクリーンショットを送ってきます: 注文合計がプロモーションバナーの後ろに隠れています。すべての自動テストが合格したのは、すべての自動テストが画面ではなくページのコードに尋ねたからです。このようなビジュアルバグのためにあるのがビジュアルテストです: ユーザーが実際に見るものを確かめます。
テストが尋ねたこと
await expect(
page.getByTestId('order-total')
).toBeVisible();顧客が見たもの
Definition
ビジュアルバグとは、背後のコードは問題なさそうなのに、人が画面上で目にする欠陥です。要素は存在し、サイズがあり、正しいテキストを持っています。コードの確認は合格します。それでも画面の前の人は、それを読めず、見つけられず、押せません。
この記事では、その隙間がどこから生まれるのか、どのバグがそこに落ちるのか、そしてユーザーと同じように画面を見るエンドツーエンドテストをどう作るのかを説明します。
ユーザーが問うこと
- 見えるか?
- 読めるか?
- あるべき場所にあるか?
- 昨日と同じ見た目か?
コードの確認が問うこと
- 要素はページの中にあるか?
- サイズはあるか?
- 非表示のスタイルが付いているか?
- 正しいテキストを持っているか?
Playwright、Cypress、Selenium にとって「表示されている」とは
コードで書いたエンドツーエンドテストは、セレクターで要素を見つけ、それについて何かをアサートします。ユーザーの体験に最も近いアサーションは「表示されているか?」です。各ツールはそれぞれのやり方でこれに答えますが、どれも画面を見てはいません。
Playwright
Playwright の toBeVisible() は、要素に空でないバウンディングボックスがあり、visibility: hidden のスタイルがなければ合格します。ドキュメントには、opacity: 0 の要素も表示されているものと見なすと書かれています。別の要素がその要素を覆っていないか、テキストが何色かは問いません。
操作はアサーションより厳密です。クリックの前に、Playwright はクリック位置でその要素がヒット対象であることを確かめるので、覆われたボタンに対するクリックはタイムアウトまで待ちます。Playwright には、ビューポートの中になければならない要素のための toBeInViewport() もあり、toHaveText() は既定で要素の textContent を読みます。
Cypress
Cypress 16 以降、既定の可視性の確認はブラウザー自身の Element.checkVisibility() に委ねられています。要素は、幅や高さがない、display: none、visibility: hidden、またはアサーションの場合は opacity: 0 のときに非表示と見なされます。クリックの前に、Cypress は要素の中心が覆われていないことを確かめます。
アサーションは別の話です。Cypress のドキュメントにははっきりこう書かれています: 「新しいアルゴリズムはヒットテストを行わないため、覆われた要素を表示されているものとして報告します。」
Selenium
Selenium のドキュメントの言葉を借りれば「あらゆる条件を網羅することは不可能」なため、Selenium の isDisplayed() は W3C WebDriver 仕様では定義されていません。代わりに Selenium は大きな JavaScript 関数を実行し、要素のスタイル、サイズ、それを切り取る祖先要素を評価します。別の要素がその上に描画されていないか、背景に対してテキストが読めるかは確かめません。
覆われた要素へのクリックは「element click intercepted」エラーで失敗します。テストが読み取るだけの要素は、それでも表示されていると報告されます。
| 確認 | ページ内にあり、サイズがある | 別の要素に覆われていない | 背景の上で読めるテキスト |
|---|---|---|---|
Playwright toBeVisible() | はい | いいえ | いいえ |
Cypress be.visible | はい | いいえ | いいえ |
Selenium isDisplayed() | はい | いいえ | いいえ |
| 画面の確認 | はい | はい | はい |
コードで書いた確認を通過する 9 つのビジュアルバグ
これらのバグはどれも、要素をサイズと正しいテキストとともにページのコードの中に残します。要素が存在する、表示されている、そのテキストを持っている、とアサートするコードのテストは合格します。ユーザーが見るものは別物です。
1. 別の要素に覆われた要素
Cookie バナー、チャットウィジェット、固定ヘッダー、閉じ損ねたダイアログが、多くの場合 z-index の変更のあとに、要素の上に重なります。上のどの定義でも、要素は今も表示されています。クリックは拒否されますが、価格、エラーメッセージ、確認文のように読み取るだけのテストは、誰にも見えないのに合格します。
2. 誰にも読めないテキスト
白地に白のテキスト、テーマ変更後の灰色の上の灰色、壊れたアニメーションで透明のまま残ったラベルです。色を読む可視性の確認はありません。Playwright の toBeVisible() は opacity: 0 でも合格します。
3. 途中で切れたテキスト
ボックスに対して長すぎるラベルが省略記号で終わるか、固定の高さが 2 行目を隠します。ページにはすべての単語が残っているので、テキストを読むアサーションは合格します。ユーザーが読むのは「Confirm your or...」です。
4. 画面の外に押し出された要素
幅の広い表や長い見出しが、狭い画面の右端の外へ「購入」ボタンを押し出します。ボタンのサイズは変わらないので、toBeVisible() は合格したままです。テストがこれを捉えるのは、そのボタンについて toBeInViewport() も問うた場合だけです。
5. 誤った画像やアイコン
商品に別の商品の写真が表示される、アイコンフォントが失敗して空の四角が残る、スプライトの更新で 2 つのアイコンが入れ替わる。画像要素とアイコンのクラスは変わっていないので、コードは正しく見えます。
6. CSS の変更で崩れたレイアウト
1 つのルールが余白、flex の方向、グリッドの列を変えます。カードが重なり、列が別の列の下に落ち、フォームの整列が崩れます。すべての要素はテキストとサイズを保ったままコードの中にあるので、すべてのアサーションが合格します。
7. 収まらない翻訳済みラベル
ドイツ語やフランス語の単語は、英語より長くなることがよくあります。ラベルがボタンからはみ出し、2 行目に折り返され、隣のボタンを押しのけます。翻訳自体は正しいので、テキストのアサーションはどの言語でも合格します。
8. 読み込みに失敗したフォント
Web フォントの読み込みに失敗すると、ブラウザーは別のフォントで代用します: 行の折り返しが変わり、フォントで描かれたアイコンは空の四角になります。コードの中のテキストは同じなので、何も失敗しません。
9. 止まらないスピナー
データが届いて行がページに追加されますが、読み込み中のオーバーレイが上に残ったままです。テストはコードの中に行を見つけて合格します。ユーザーはスピナーの前で待ち続けます。
Cypress 自身のドキュメントが一行でまとめています: 「アプリケーションはすべての機能テストに合格しても、目に見えて壊れたまま出荷されることがある。」
ビジュアルバグの種類: DOM の確認が見逃し、ビジュアルアサーションが捉えるもの
同じバグを種類別に見ます。DOM の確認はページのコードに尋ねます: 要素はあるか、サイズとテキストを持っているか? ビジュアルアサーションは画面を見ます: 要素はあるべき場所で、あるべき見た目をしているか?
| ビジュアルバグ | DOM の確認 | ビジュアルアサーション |
|---|---|---|
| 欠けたアイコン | 合格: アイコンの要素とそのクラスは変わっていません。 | 捉える: 画像が変わりました。 |
| 途中で切れたテキスト | 合格: ページにはすべての単語が残っています。 | 捉える: ラベルの末尾が欠けています。 |
| 誤った色 | 合格: 色を読む表示の確認はありません。 | 捉える: 色が変わりました。 |
| 要素の重なり、または別の要素に覆われた要素 | テストが要素を読むだけなら合格で、要素へのクリックは拒否されます。 | 捉える: 画面に、期待どおりの要素が表示されなくなっています。 |
| 誤った状態 | 見た目だけが変わった場合は合格: 無効として描かれたボタン、オフとして描かれたトグルなどです。 | 捉える: 要素の見た目が期待したものと異なります。 |
| 画面の外に押し出された要素 | 要素がビューポート内にあるかどうかもテストが尋ねない限り、合格です。 | 捉える: レイアウトアサーションが、その要素と移動量を示します。 |
| スタイルの変更で崩れたレイアウト | 合格: すべての要素が、テキストとサイズを保ったままコードの中にあります。 | 捉える: 移動した各要素と、その移動量を示します。 |
| 読み込みに失敗したフォント | 合格: コードの中のテキストは同じです。 | 捉える: 文字が変わりました。 |
| 止まらないスピナー | 合格: 行はコードの中にあります。 | 捉える: ビジュアル不在アサーションが、まだ画面上にあるスピナーを見つけます。 |
スクリーンショットによるビジュアルリグレッションテストで捉えられるか?
はい、それが一般的な答えです。ビジュアルリグレッションテストは、画面の画像を以前に撮った基準画像と比較します。
Playwright には toHaveScreenshot() として組み込まれています。ドキュメントは、ブラウザーの描画がホストの OS、そのバージョンと設定、ハードウェア、ヘッドレスモードによって変わりうると注意しています。そのため、ブラウザーとプラットフォームごとに基準画像を持つことになります。
Cypress はスクリーンショットを撮りますが、ドキュメントには「画像比較自体は行わない」とあります。比較はプラグインやビジュアルテストサービスが追加します。
Percy や Applitools Eyes のようなサービスは、コードで書いたテストに画像のチェックポイントを追加します。Percy はテスト実行中にスクリーンショットを撮って比較します。Applitools Eyes はテストの中に確認の呼び出しを追加します。
これらのツールの比較は比較調査を参照してください。
手動テストでは隙間が埋まらない理由
人なら、これらのバグはどれもひと目で分かります。だからこそ多くのチームは、今もリリース前にアプリケーションをクリックして回ります。しかし、手動テストには限界があります。
| 限界 | 起きること |
|---|---|
| 時間 | リグレッションテストを一通り行うには何時間もかかるので、ビルドのたびではなくリリース前にしか実行されません。 |
| 注意力 | 同じ作業の 20 画面目ともなると、目は流し見になります。小さな色の変化や欠けたアイコンは見過ごされます。 |
| 再現性 | 2 人のテスターは別のものを見ますし、同じテスターでも金曜の夕方には見方が変わります。一度見つかったバグが、二度と探されないこともあります。 |
| カバレッジ | ブラウザー、デバイス、言語が増えるたびに作業が倍増します。 |
ユーザーが見るものを見るエンドツーエンドテストはどう作るか?
どのツールを使うにしても、6 つの原則によって、エンドツーエンドテストはユーザーと同じようにアプリケーションを体験できるようになります。
- 1
実際のアプリケーションを操作する
人と同じように、実際の画面でクリックし、入力します。覆われたボタンを押せないテストは、ユーザーが行き詰まる場所で失敗します。
- 2
表示されているものを確かめる
画面を 3 つの観点で確かめます: 要素の見た目が正しいかを画像で、正しい内容を示しているかを文字で、すべてがあるべき場所にあるかを配置で確かめます。
- 3
まず要素を見つけ、それから比較する
移動したウィンドウやスクロールしたページはバグではありません。テストは要素を今ある場所で見つけてから、その見た目を判断すべきです。
- 4
ノイズは無視し、本当の変化は決して見逃さない
画面はコンピューターごとにわずかに異なるので、比較は描画のノイズを無視しつつ、人が気づくあらゆる変化を捉えるべきです。
- 5
エビデンスを示す
失敗したときは、期待する画面と検出した画面を並べ、変化に印を付けて、チームの誰もが読めるようにすべきです。
- 6
変更のコストを低く保つ
アプリケーションを意図的に変えたとき、新しい見た目の採用は書き直しではなくワンクリックで済むべきです。
GUI Test Studio がユーザーの見るものをテストする方法
GUI Test Studio は、これらの原則に基づいてエンドツーエンドテストをコードなしで作ります。Web アプリ、Windows デスクトップアプリ、Android スマートフォン、ゲームを、1 種類のテストでテストします。詳しくはビジュアルテストと GUI テストを参照してください。
ワークフローを一度記録する
GUI Test Runner-Recorder で記録をクリックし、いつもどおりにワークフローを行います: マウス、キーボード、画面が記録されます。Claude、ChatGPT、または当社提供もしくは持ち込みのローカル AI モデルにワークフローをプロンプトで説明して、代わりに記録してもらうこともできます。
停止すると、テストが何を検証すべきかを尋ねられます。既定の答えのままなら、クリックした要素や入力した要素には、操作の直前にビジュアルアサーションが付きます。メニュー、ダイアログ、メッセージのように自然に表示されるものには、グループアサーションが付きます。
画面に表示されるもののアサーション
| アサーション | 確かめる内容 |
|---|---|
| ビジュアルアサーション | 要素が画面上にあり、見た目が正しいこと: 画像、色、アイコンです。 |
| ビジュアル不在アサーション | 何かが消えたこと: スピナー、バナー、閉じるべきダイアログです。 |
| テキストアサーション | フォントや色にかかわらず、文字が正しいこと。 |
| レイアウトアサーション | 要素があるべき場所にあること: 移動も、重なりも、画面外への消失もないことです。 |
| グループアサーション | 1 つの画面の同じ時点での複数のアサーションと、必要に応じてその配置です。 |
それぞれにガイドがあります: ビジュアルアサーション、テキストアサーション、レイアウトアサーションとグループアサーションです。
要素を見つけてから比較する
すべてのビジュアルアサーションは 2 つのフェーズで判定されます。検索フェーズは要素が画面上にあるかを問い、アサーションのタイムアウトまでそれを待ちます。GTS Engine + AI はまずアクセシビリティ情報やページ自身の要素を通じてアプリケーションに尋ね、アプリケーションが答えない場合は視覚で要素を見つけます。GUI Test Studio がすべての要素を見つける方法を参照してください。
要素が記録時とは別の場所で見つかった場合、その後のクリックは今ある場所に向けられます。また、テストがバナーの上から盲目的にクリックすることはありません: 要素が覆われていれば、クリックの前にそのアサーションが不合格になります。
何が変わったかを読む
実行後、信頼度レポートに各アサーションが表示されます。期待画像と検出画像が並び、変化が強調表示され、判定が平易な一文で示されます。
AI スマート分析がオンなら、不合格になったアサーションは AI による再確認も受け、何が変わったかが平易な言葉で説明されます。クラウドモデルと自分のキーで、または自分のコンピューター上のローカル AI モデルで実行できます: 当社提供のものか、持ち込みのものです。
意図した変更なら、レポートから新しい見た目を採用すれば、以後テストはそれを期待します。コマンドラインの gtr-cli は、同じテストを任意の CI/CD パイプラインから、ビルドのたびに実行します。
どのアサーションがどのビジュアルバグを捉えるか
9 つのバグを、それぞれを捉える GUI Test Studio のアサーションとともに改めて挙げます。
| バグ | 確認 | レポートの表示 |
|---|---|---|
| 別の要素に覆われた要素 | ビジュアルアサーション | 未検出、または差異あり: 画面に要素の画像が表示されなくなっています。 |
| 誰にも読めないテキスト | ビジュアルアサーション | 差異あり: 色が変わりました。 |
| 途中で切れたテキスト | ビジュアルアサーション | 差異あり: ラベルの末尾が欠けています。 |
| 画面の外に押し出された要素 | レイアウトアサーション | 要素の名前と、どれだけ移動したかが示されます。 |
| 誤った画像やアイコン | ビジュアルアサーション | 差異あり: 画像が変わりました。 |
| CSS の変更で崩れたレイアウト | レイアウトアサーション、またはグループレイアウト付きのグループアサーション | 移動した各要素と、その移動量です。 |
| 収まらない翻訳済みラベル | ビジュアルアサーション、レイアウトアサーション | 差異あり、または移動です。 |
| 読み込みに失敗したフォント | ビジュアルアサーション | 差異あり: 文字が変わりました。 |
| 止まらないスピナー | ビジュアル不在アサーション | 時間切れになっても、まだ画面上にあります。 |
コードで書いた確認が今も必要な場所
要点
- 1ビジュアルバグは、コードを正しいまま、画面を誤ったままにします。要素はサイズとテキストを保ってそこにあるのに、誰にも見えません。
- 2コードで書いた表示の確認は、決して画面を見ません。覆われた要素、読めないテキスト、誤ったアイコンは、そのどれも通過します。
- 3スクリーンショットと手動テストは、代償と引き換えに隙間を埋めます: ブラウザーとシステムごとのリファレンス画像か、ビルドのたびに何時間もの注意です。
- 4まず要素を見つけてから比較し、描画のノイズを無視しつつ本当のリグレッションをすべて捉え、エビデンスを示します。
- 5GUI Test Studio はそれをコードなしで行います: ワークフローを一度記録すれば、すべてのビジュアルアサーションがユーザーの見る画面を比較します。
質問
ビジュアルバグとは何ですか?
ビジュアルバグとは、背後のコードは問題なさそうなのに、人が画面上で目にする欠陥です。要素は存在し、サイズがあり、正しいテキストを持っているのに、画面の前の人はそれを読めず、見つけられず、押せません。覆われた合計、白地に白のテキスト、誤ったアイコンはビジュアルバグです。
自動テストはなぜビジュアルバグを見逃すのですか?
自動テストがビジュアルバグを見逃すのは、画面ではなくページのコードに尋ねるからです。要素が存在する、表示されている、テキストを持っているというアサーションは、要素の見た目がどうであれ、コードが正しい限り合格します。覆われた要素、読めない色、切れたラベルが見えるのは、画面の確認だけです。
要素が覆われているのに Playwright の toBeVisible() が合格するのはなぜですか?
Playwright の可視性の確認が問うのは、要素に空でないバウンディングボックスがあり、visibility: hidden のスタイルがないかどうかだけです。別の要素がその上に重なっていないかは問いません。その要素へのクリックなら確かめられるので、テストが覆われた要素をクリックせずに読むだけのときに、このバグがすり抜けます。
Selenium は別の要素の後ろに隠れた要素を検出できますか?
isDisplayed() ではできません: これは要素のスタイル、サイズ、クリッピングを見るだけで、その上に描画されているものは決して見ません。覆われた要素へのクリックは element click intercepted エラーで失敗します。テストが読み取るだけの要素は、それでも表示されていると報告されます。
ビジュアルリグレッションテストとは何ですか?
ビジュアルリグレッションテストは、画面が今表示しているものを以前表示していたものと比べ、ユーザーの目に映る変化を捉えます: 欠けたアイコン、途中で切れた単語、誤った色のボタンなどです。素のスクリーンショット比較は、コンピューター間で異なる描画のノイズも含めて、変化したすべてのピクセルを報告します。優れたビジュアルリグレッションテストは、まず各要素を見つけ、そのノイズを無視しつつ本当のリグレッションを捉え、何が変わったかを示します。
ビジュアルテストと機能テストの違いは何ですか?
機能テストは機能が正しく振る舞うことを確かめます: クリックで正しいページに進む、フォームがデータを保存する、などです。ビジュアルテストは画面に表示されるものを確かめます: 正しい要素が、読める状態で、あるべき場所にあることです。両方を行うエンドツーエンドテストは、ユーザーが気づくものを捉えます。
GUI Test Studio でビジュアルアサーションを追加するには、コードを書く必要がありますか?
いいえ。ワークフローを一度記録すれば、GUI Test Studio がクリックや入力をするすべての要素の前にビジュアルアサーションを追加し、画面に表示されるものも確かめます。アサーションの調整は、視覚的なタイムライン上で行います。
自動化したビジュアルテストは手動テストの代わりになりますか?
繰り返しの部分、つまりビルドのたびに同じ画面をたどる作業の代わりにはなります。新しいデザインを判断したり、機能を初めて探索したりするのは、今も人がいちばん得意です。
Selenium、Playwright、Cypress、Percy、Applitools Eyes は、それぞれの所有者の商標です。
テスト対象のアプリでご覧になりますか? チームとの 30 分の無料相談を予約してください。