使用 Playwright 測試 UI 狀態和動畫
如何使用 Playwright 為動畫 UI 編寫穩定的測試:使用 page.clock 控制時間、模擬簡化運動和黑暗模式以及停用動畫的螢幕截圖。
核心要點
使動畫測試具有確定性:使用 page.clock 控制時間,涵蓋計時器、requestAnimationFrame 和效能;使用 page.emulateMedia({ returnedMotion, colorScheme }) 模擬使用者設定;對狀態而不是動畫中像素進行斷言;並在禁用動畫的情況下截取螢幕截圖。將簡化運動路徑作為一流案例進行測試。
為什麼動畫測試不穩定
動畫取決於時間,而實際時間因運行和機器而異。早或晚 10 毫秒拍攝的螢幕截圖會顯示不同的畫面。解決方法是控制時間和設置,並測試動畫在各個幀之間移動的狀態,而不是單獨的幀。
控制時間
Playwright 的時鐘 API 可測試安裝假時鐘,然後在設定的持續時間內暫停、快轉或運行時間。它涵蓋了 setTimeout、setInterval、requestAnimationFrame 和效能,因此您可以快轉經過載入延遲並檢查是否出現成功狀態。
模擬用戶設定
page.emulateMedia()可以將reducedMotion設定為“reduce”,將colorScheme設定為“dark”或“light”。以減少的動作運行關鍵流程,以確認沒有任何重要的事情取決於動畫,並在兩個主題中捕獲對比問題。
穩定的截圖
Playwright Test可以將螢幕截圖與expect(page).toHaveScreenshot()進行比較,螢幕截圖選項包括動畫:“disabled”,它會停止CSS動畫和捕獲的過渡。對最終狀態使用視覺比較,對行為使用 DOM 或可訪問性斷言。
測試基於畫布的組件
畫布動畫(例如 Lottie、Rive 或 ExodeUI 運行時繪製的動畫)在 DOM 中不可見。測試程式碼發送的輸入及其接收的事件,將真正可存取的元素保留在畫布旁邊,並在控制時間後使用螢幕截圖進行視覺檢查。
生產實施片段
import { test, expect } from '@playwright/test';
test('save button shows success, also with reduced motion', async ({ page }) => {
await page.clock.install(); // fake timers + rAF
await page.emulateMedia({ reducedMotion: 'reduce' }); // test the calm path
await page.goto('/settings');
await page.getByRole('button', { name: 'Save' }).click();
await expect(page.getByRole('status')).toHaveText('Saving…');
await page.clock.runFor(2000); // skip the wait deterministically
await expect(page.getByRole('status')).toHaveText('Saved');
await expect(page).toHaveScreenshot('saved.png', { animations: 'disabled' });
});要記住的關鍵 Principle
- 使用 page.clock 控制時間(計時器、requestAnimationFrame、效能)
- 使用 page.emulateMedia 模擬 returnedMotion 和 colorScheme
- 對狀態和可存取的文字進行斷言,而不是對動畫中的像素進行斷言
- 帶動畫的螢幕截圖:“已停用”
- 將簡化運動路徑作為一流案例進行測試
常見問題解答
來源
- Clock — Playwright 文檔
- Page.emulateMedia and screenshot options — Playwright 文檔
- Visual comparisons — Playwright 文檔