Skip to main content

時鐘

簡介

準確模擬時間依賴行為對於驗證應用程式的正確性至關重要。利用 Clock 功能允許開發人員在測試中操縱和控制時間,從而精確驗證渲染時間、超時、排程任務等功能,而不會有即時執行的延遲和變異性。

Clock API 提供以下方法來控制時間:

  • setFixedTime: 設定 Date.now()new Date() 的固定時間。
  • install: 初始化時鐘並允許你:
    • pauseAt: 在特定時間暫停時間。
    • fastForward: 快進時間。
    • runFor: 執行特定時間段。
    • resume: 恢復時間。
  • setSystemTime: 設定當前系統時間。

建議的方法是使用 setFixedTime 將時間設置為特定值。如果這不適用於您的使用案例,您可以使用 install,這允許您稍後暫停時間、快進時間、滴答時間等。setSystemTime 只建議用於高級使用案例。

note

page.clock 覆蓋了與時間相關的原生全域類別和函式,允許手動控制它們:

  • Date
  • setTimeout
  • clearTimeout
  • setInterval
  • clearInterval
  • requestAnimationFrame
  • cancelAnimationFrame
  • requestIdleCallback
  • cancelIdleCallback
  • performance
  • Event.timeStamp

測試預定時間

通常你只需要偽造 Date.now 同時保持計時器運行。這樣時間會自然流動,但 Date.now 總是返回一個固定值。

<div id="current-time" data-testid="current-time"></div>
<script>
const renderTime = () => {
document.getElementById('current-time').textContent =
new Date().toLocaleString();
};
setInterval(renderTime, 1000);
</script>
await page.clock.setFixedTime(new Date('2024-02-02T10:00:00'));
await page.goto('http://localhost:3333');
await expect(page.getByTestId('current-time')).toHaveText('2/2/2024, 10:00:00 AM');

await page.clock.setFixedTime(new Date('2024-02-02T10:30:00'));
// 我們知道頁面有一個每秒更新時間的計時器。
await expect(page.getByTestId('current-time')).toHaveText('2/2/2024, 10:30:00 AM');

一致的時間和計時器

有時候你的計時器依賴 Date.now,當 Date.now 的值隨時間不變時會感到困惑。在這種情況下,你可以安裝時鐘並快進到測試時感興趣的時間。

<div id="current-time" data-testid="current-time"></div>
<script>
const renderTime = () => {
document.getElementById('current-time').textContent =
new Date().toLocaleString();
};
setInterval(renderTime, 1000);
</script>
// 在測試時間之前初始化時鐘,讓頁面自然載入。
// `Date.now` 會隨著計時器觸發而前進。
await page.clock.install({ time: new Date('2024-02-02T08:00:00') });
await page.goto('http://localhost:3333');

// 假設用戶關閉筆記型電腦蓋子,並在上午 10 點再次打開,
// 一旦到達該時間點就暫停時間。
await page.clock.pauseAt(new Date('2024-02-02T10:00:00'));

// 斷言頁面狀態。
await expect(page.getByTestId('current-time')).toHaveText('2/2/2024, 10:00:00 AM');

// 再次關閉筆記型電腦蓋子,並在上午 10:30 打開。
await page.clock.fastForward('30:00');
await expect(page.getByTestId('current-time')).toHaveText('2/2/2024, 10:30:00 AM');

測試非活動監控

在網頁應用程式中,不活動監控是一個常見的功能,會在一段時間不活動後將使用者登出。測試這個功能可能會很棘手,因為你需要等待很長時間才能看到效果。借助時鐘,你可以加速時間並快速測試這個功能。

<div id="remaining-time" data-testid="remaining-time"></div>
<script>
const endTime = Date.now() + 5 * 60_000;
const renderTime = () => {
const diffInSeconds = Math.round((endTime - Date.now()) / 1000);
if (diffInSeconds <= 0) {
document.getElementById('remaining-time').textContent =
'You have been logged out due to inactivity.';
} else {
document.getElementById('remaining-time').textContent =
`You will be logged out in ${diffInSeconds} seconds.`;
}
setTimeout(renderTime, 1000);
};
renderTime();
</script>
<button type="button">Interaction</button>
// 初始時間對測試來說不重要,所以我們可以選擇當前時間。
await page.clock.install();
await page.goto('http://localhost:3333');
// 與頁面互動
await page.getByRole('button').click();

// 快進時間 5 分鐘,就像用戶什麼都沒做一樣。
// 快進就像關閉筆記型電腦蓋子,5 分鐘後再打開。
// 所有到期的計時器會立即觸發一次,就像在真實瀏覽器中一樣。
await page.clock.fastForward('05:00');

// 檢查用戶是否自動被登出。
await expect(page.getByText('You have been logged out due to inactivity.')).toBeVisible();

手動計時,持續觸發所有計時器

在少數情況下,您可能希望手動調整時間,觸發所有計時器和動畫幀,以實現對時間流逝的精細控制。

<div id="current-time" data-testid="current-time"></div>
<script>
const renderTime = () => {
document.getElementById('current-time').textContent =
new Date().toLocaleString();
};
setInterval(renderTime, 1000);
</script>
// 用特定時間初始化時鐘,讓頁面自然載入。
await page.clock.install({ time: new Date('2024-02-02T08:00:00') });
await page.goto('http://localhost:3333');

// 暫停時間流動,停止計時器,現在你可以手動控制
// 頁面時間。
await page.clock.pauseAt(new Date('2024-02-02T10:00:00'));
await expect(page.getByTestId('current-time')).toHaveText('2/2/2024, 10:00:00 AM');

// 手動推進時間,同時觸發所有計時器。
// 在這種情況下,螢幕上的時間會更新 2 次。
await page.clock.runFor(2000);
await expect(page.getByTestId('current-time')).toHaveText('2/2/2024, 10:00:02 AM');

相關影片