Playwrightの自動待機と待機処理
自動テストを作成していると、**「昨日動いたテストが、今日は失敗する。でも、もう一度実行したら成功する…」**という、気まぐれで不安定なテストに遭遇することがあります。
なぜ「待機」が必要なのか?
Playwrightの処理は非常に高速です。一方、Webサイトがデータを取得して画面に表示するには、コンマ数秒〜数秒の時間がかかります。
テストコードは、電子レンジのタイマーが終わる前に「チン!」と音が鳴ったか確認しにいくような、せっかちなものです。
なので時より画面の表示が完了する前に「表示されていません!」と判断し、テストを失敗させてしまうこともあります。
Playwrightの賢い「自動待機」
幸いなことに、Playwrightは非常に賢く、多くの場面でこの待機を自動で行ってくれます。これを**自動待機(Auto-waiting)**と呼びます。
click() や fill() といった操作を行うとき、Playwrightは対象の要素が操作可能な状態になるまで、自動的に待ってくれます。このおかげで、私たちは多くの「待機」を意識することなく、安定したテストを書くことができます。
自動待機だけでは足りないケース
Playwrightの自動待機は非常に優秀ですが、それだけではテストが安定しないことも、残念ながら多々あります。
特に、クリックした後に少し複雑な処理が動く画面などでは、この自動待機が効かずに、原因の分かりにくいテスト失敗が起きてしまうことがあります。
様々な待機(wait)の方法と使い分け
1. 特定の要素を待つ locator(...).waitFor()
指定した要素が、画面上に表示されるまで待つための、最も直接的な待機コマンドです。
基本的な書き方
// 指定した要素が表示されるまで待つ
await page.locator("セレクタ").waitFor();
具体例
// idが "loading-spinner" の要素が表示されるまで待つ
await page.locator("#loading-spinner").waitFor();
2. ページの読み込み状態を待つ page.waitForLoadState()
ページの読み込み状態が、特定の段階に達するまで待機します。特に**「ネットワークが落ち着くまで待つ」**という指定が強力です。
基本的な書き方
// ネットワーク通信が落ち着くまで待つ
await page.waitForLoadState('networkidle');
指定できる状態
| 状態 | 説明 |
|---|---|
domcontentloaded |
HTMLの読み込みが終わるまで待つ |
load |
画像なども含め、ページリソースの読み込みが終わるまで待つ |
networkidle |
ネットワーク通信がほぼなくなるまで待つ |
3.【最後の手段】固定時間待機 page.waitForTimeout()
理由を問わず、指定した時間(ミリ秒)だけ、処理を強制的に停止します。
基本的な書き方
// 3秒待機
await page.waitForTimeout(3000);
固定時間待機の考え方とリスク
固定時間待機に意味深に**【最後の手段】**と記述した理由をご説明いたします。
テストを「遅く、かつ不安定にする」ための「悪い待機」だからです。
リスク1:テストが「遅く」なる
waitForTimeout(5000) は、「最大5秒待つ」という意味ではなく、**「必ず5秒間、何があっても待つ」**という命令です。
その後、サーバーの性能が改善され、実際の表示は1秒で終わるようになったとしましょう。
しかし、テストコードは賢くありません。
処理が1秒で終わっていても、命令通り残りの4秒間を、何もせずにぼーっと待ち続けます。
特に、何百ものテストを一度に実行するリグレッションテストでは、この数秒の無駄が積み重なり、テスト全体の実行時間が数分、数十分と、どんどん長くなってしまうのです。
これは、開発のスピードを大きく下げる原因になります。
リスク2:テストが「不安定(フレーキー)」になる
waitForTimeout は、テストを遅くするだけでなく、非常に不安定にする大きな原因にもなります。
waitForTimeout(5000)(5秒待機)を設定したとします。しかし、ある日ネットワークが少し混雑し、その処理に 5.1秒 かかってしまいました。
結果、5秒の待機では足りず、テストは失敗します。
私たちには予測できない要因によって簡単に崩壊してしまうのです。
使う際の、大切な心構え
locator(...).waitFor() や page.waitForLoadState() といった優秀な待機コマンドを使っても、なぜかタイミングが合わずにテストが失敗してしまう、という非常に厄介な状況は必ずあります。これは、画面の裏側で動いている複雑な処理などが原因で、通常の待機方法では検知しきれない場合に起こります。
そういった、waitFor系コマンドを試したけど改善されない、本当にどうしようもない場合の「最後の手段」として、固定時間待機をご利用ください。
固定時間待機を使う場合の2つのルール
「テストをパスさせることが目的ではない」ことを意識してください。
待機処理には、必ず「コメント」を残してください
理由1:将来、不要になった「待機」を安全に消せるようにするため
Webサイトの仕様は、日々変わっていきます。
例えば、「サーバーの応答が遅いから」という理由で3秒の待機を入れていたとしても、半年後にサーバーが新しくなれば、その待機はもう必要ないかもしれません。
理由が書かれていれば、「サーバーが新しくなったから、この待機はもう不要だな」と、自信を持ってコードを改善できます。
理由2:必要な「待機」が、勝手に消されるのを防ぐため
逆に、特定の環境でだけ発生する不安定さを解決するために、やむを得ず待機を入れている場合もあります。
その結果、一度対応したはずの特定の環境でだけテストが失敗すると、不安定さを再発させることになります。
具体的な書き方
コメントは、// の後に、誰が読んでも分かるように、「何を待っているのか」や「なぜ待つ必要があるのか」を具体的に書くのがポイントです。
// 画面遷移後、非同期処理を待たないと後続のクリックにスカる
await page.waitForLoadState('domcontentloaded');
// ファイルアップロード後、5秒待たないと一覧画面に反映されない
await page.waitForTimeout(5000);
未来のチームにとって、はるかにメンテナンスしやすく、信頼性の高い財産になるのです。
やってみよう
「待機(wait)」コマンドを実際に体験してみましょう。要素の出現を待つ方法や、指定した時間だけ処理を止める方法などを学びます。
演習ファイル
tests/document-4/lesson-07.spec.ts
手順動画
waitForTimeout() 以外は目に見えて「ちゃんと待ってる!」と実感しづらいかもしれません。そのため動画では、あえて「存在しない要素」を指定して、実際には存在しないにもかかわらず、処理がしっかり待機していることを確認しています。
進め方
-
演習ファイルを実行し、待機処理がどのように動作するか確認してください
-
興味がある方は、以下のように試してみると理解が深まります
waitForTimeout()の時間を長めに設定してみる- 存在しない要素を指定して、waitFor 系の処理が要素の表示を待つ挙動を確かめる