上一篇我們學會了如何處理對話框,由於不曉得對話框何時出現,所以必須設置一個監聽器來處理,接著我們要來聊聊另一個非常類似的狀況:不知道預期的結果需要等多久才會出現,預期結果可能取決於網路、畫面渲染資料庫回應的速度,甚至是資料會隨著時間改變。
那我們也可以在 assertion 設置監聽器嗎?答案是可以的!運用 expect.poll()
就能達成我們想要的效果。expect.poll()
會「不斷重新呼叫一段函式,直到收到的值符合預期或 timeout 為止」,就像一個耐心的警探,一直監聽目標的狀態,直到條件符合,才成功拆除不定時炸彈。
以下這些狀況都能使用 expect.poll()
:
讓我們用一個小小的實驗來驗證 expect.poll()
的效果,設置一個每秒隨機取 1 ~ 10 的計數器,直到結果出現 5:
加入 expect.poll()
等待預期結果為 5,並且設定 timeout
為 10 秒:
await expect.poll(() => {
console.log('polling check: counter =', counter);
return counter;
}, { timeout: 10000 }).toBe(5);
讓我們來看看執行結果:
我們可以看到,expect.poll()
不斷監聽計數器值的變化,直到計數器 random 到 5 才停止監聽,測試結果 passed。
接著,我們要迎接新的挑戰,將 expect.poll()
實際運用在網頁上,看看是不是也能成功監測到預期的值出現。
任務畫面
任務解析
Dynamic Content 這個網頁,每次重整頁面或點擊「click here」,第三段圖片及文字會隨機出現,這次的任務是點擊 30 次「click here」來刷新頁面,看看 30 次內是否會出現非隨機畫面上的文字:veniam。
程式碼如下:
// poll-click.spec.ts
import { test, expect } from '@playwright/test';
test('poll click until specific text appears', async ({ page }) => {
const url = 'https://the-internet.herokuapp.com/dynamic_content?with_content=static';
await page.goto(url);
const targetText = 'eum';
const maxAttempts = 30; // 最多點擊次數
let attempts = 0;
while (attempts < maxAttempts) {
attempts++;
// 點擊按鈕
await page.getByRole('link', { name: 'click here' }).click();
// 嘗試找到目標文字
const isVisible = await page.getByText(targetText).isVisible().catch(() => false);
if (isVisible) {
console.log(`找到了 "${targetText}",共點擊 ${attempts} 次`);
break; // 找到後跳出迴圈
}
// 如果沒有找到,可以加一點延遲,避免太快輪詢
await page.waitForTimeout(500);
}
// 最終斷言確認文字出現
await expect(page.getByText(targetText)).toBeVisible();
});
關卡通關證明
我們一口氣連續執行 10 次,可以觀察到指定文字在每次測試中都於不同的點擊次數後才出現,這正好驗證了 expect.poll()
能有效處理出現時機不可預測的結果等待。
💡 Tips:
透過指令npx playwright test <test file> --repeat-each=<N>
,我們可以讓每個測試案例依照指定次數重複執行。
到這裡,我們已經學會如何透過 expect.poll()
捕捉寶箱(預期結果)出現的時機,不僅精準等待並且驗證非即時可預測的結果。接下來,我們將把焦點轉向另一個常見的測試情境 ── 處理新分頁的開啟與操作。