時鐘
簡介
精確地模擬與時間相關的行為,對於驗證應用程式的正確性至關重要。利用 Clock 功能,開發人員可以在測試中操作和控制時間,從而能夠精確驗證諸如渲染時間、逾時、排程任務等功能,而不會受到即時執行的延遲和變異性的影響。
Clock API 提供了以下方法來控制時間
setFixedTime
:為Date.now()
和new Date()
設定固定時間。install
:初始化時鐘並允許您pauseAt
:在特定時間暫停時間。fastForward
:快轉時間。runFor
:將時間運行特定持續時間。resume
:繼續時間。
setSystemTime
:設定目前的系統時間。
建議的方法是使用 setFixedTime
將時間設定為特定值。如果這不適用於您的使用案例,您可以使用 install
,它允許您稍後暫停時間、快轉時間、滴答計時等等。setSystemTime
僅建議用於進階使用案例。
注意
Page.Clock 覆寫與時間相關的原生全域類別和函式,允許手動控制它們
Date
setTimeout
clearTimeout
setInterval
clearInterval
requestAnimationFrame
cancelAnimationFrame
requestIdleCallback
cancelIdleCallback
performance
Event.timeStamp
警告
如果您在測試中的任何時間點呼叫 install
,則此呼叫必須在任何其他與時鐘相關的呼叫之前發生 (請參閱上面的注意事項以取得清單)。不依順序呼叫這些方法將導致未定義的行為。例如,您無法呼叫 setInterval
,然後呼叫 install
,再呼叫 clearInterval
,因為 install
會覆寫時鐘函式的原生定義。
使用預先定義的時間進行測試
通常您只需要偽造 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
,並且在 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>
// Initialize clock with some time before the test time and let the page load naturally.
// `Date.now` will progress as the timers fire.
await Page.Clock.InstallAsync(new()
{
TimeDate = new DateTime(2024, 2, 2, 8, 0, 0)
});
await Page.GotoAsync("https://127.0.0.1:3333");
// Pretend that the user closed the laptop lid and opened it again at 10am.
// Pause the time once reached that point.
await Page.Clock.PauseAtAsync(new DateTime(2024, 2, 2, 10, 0, 0));
// Assert the page state.
await Expect(Page.GetByTestId("current-time")).ToHaveTextAsync("2/2/2024, 10:00:00 AM");
// Close the laptop lid again and open it at 10:30am.
await Page.Clock.FastForwardAsync("30:00");
await Expect(Page.GetByTestId("current-time")).ToHaveTextAsync("2/2/2024, 10:30:00 AM");
測試非活動監控
非活動監控是 Web 應用程式中的常見功能,會在一段時間不活動後登出使用者。測試此功能可能很棘手,因為您需要等待很長時間才能看到效果。借助時鐘,您可以加快時間並快速測試此功能。
<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>
// Initial time does not matter for the test, so we can pick current time.
await Page.Clock.InstallAsync();
await page.GotoAsync("https://127.0.0.1:3333");
// Interact with the page
await page.GetByRole("button").ClickAsync();
// Fast forward time 5 minutes as if the user did not do anything.
// Fast forward is like closing the laptop lid and opening it after 5 minutes.
// All the timers due will fire once immediately, as in the real browser.
await Page.Clock.FastForwardAsync("05:00");
// Check that the user was logged out automatically.
await Expect(Page.GetByText("You have been logged out due to inactivity.")).ToBeVisibleAsync();
手動滴答計時,一致地觸發所有計時器
在極少數情況下,您可能想要手動滴答計時,在此過程中觸發所有計時器和動畫影格,以實現對時間流逝的精細控制。
<div id="current-time" data-testid="current-time"></div>
<script>
const renderTime = () => {
document.getElementById('current-time').textContent =
new Date().toLocaleString();
};
setInterval(renderTime, 1000);
</script>
// Initialize clock with a specific time, let the page load naturally.
await Page.Clock.InstallAsync(new()
{
TimeDate = new DateTime(2024, 2, 2, 8, 0, 0, DateTimeKind.Pst)
});
await page.GotoAsync("https://127.0.0.1:3333");
var locator = page.GetByTestId("current-time");
// Pause the time flow, stop the timers, you now have manual control
// over the page time.
await Page.Clock.PauseAtAsync(new DateTime(2024, 2, 2, 10, 0, 0));
await Expect(locator).ToHaveTextAsync("2/2/2024, 10:00:00 AM");
// Tick through time manually, firing all timers in the process.
// In this case, time will be updated in the screen 2 times.
await Page.Clock.RunForAsync(2000);
await Expect(locator).ToHaveTextAsync("2/2/2024, 10:00:02 AM");