時鐘
簡介
準確模擬時間依賴行為對於驗證應用程式的正確性至關重要。利用 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>
一致的時間和計時器
有時候你的計時器依賴 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("http://localhost: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")).ToHaveText("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")).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>
// Initial time does not matter for the test, so we can pick current time.
await Page.Clock.InstallAsync();
await page.GotoAsync("http://localhost: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("http://localhost: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");