時鐘
簡介
準確地模擬時間相關的行為對於驗證應用程式的正確性至關重要。利用 時鐘 功能,開發人員可以在測試中操控和控制時間,從而精確驗證諸如渲染時間、逾時、排程任務等功能,而無需實時執行的延遲和變異性。
時鐘 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.
page.clock.install(time=datetime.datetime(2024, 2, 2, 8, 0, 0))
page.goto("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.
page.clock.pause_at(datetime.datetime(2024, 2, 2, 10, 0, 0))
# Assert the page state.
expect(page.get_by_test_id("current-time")).to_have_text("2/2/2024, 10:00:00 AM")
# Close the laptop lid again and open it at 10:30am.
page.clock.fast_forward("30:00")
expect(page.get_by_test_id("current-time")).to_have_text("2/2/2024, 10:30:00 AM")
# 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.install(time=datetime.datetime(2024, 2, 2, 8, 0, 0))
await page.goto("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.pause_at(datetime.datetime(2024, 2, 2, 10, 0, 0))
# Assert the page state.
await expect(page.get_by_test_id("current-time")).to_have_text("2/2/2024, 10:00:00 AM")
# Close the laptop lid again and open it at 10:30am.
await page.clock.fast_forward("30:00")
await expect(page.get_by_test_id("current-time")).to_have_text("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.
page.clock.install()
page.goto("https://127.0.0.1:3333")
# Interact with the page
page.get_by_role("button").click()
# 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.
page.clock.fast_forward("05:00")
# Check that the user was logged out automatically.
expect(page.get_by_text("You have been logged out due to inactivity.")).to_be_visible()
# Initial time does not matter for the test, so we can pick current time.
await page.clock.install()
await page.goto("https://127.0.0.1:3333")
# Interact with the page
await page.get_by_role("button").click()
# 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.fast_forward("05:00")
# Check that the user was logged out automatically.
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>
- 同步
- 非同步
# Initialize clock with a specific time, let the page load naturally.
page.clock.install(
time=datetime.datetime(2024, 2, 2, 8, 0, 0, tzinfo=datetime.timezone.pst),
)
page.goto("https://127.0.0.1:3333")
locator = page.get_by_test_id("current-time")
# Pause the time flow, stop the timers, you now have manual control
# over the page time.
page.clock.pause_at(datetime.datetime(2024, 2, 2, 10, 0, 0))
expect(locator).to_have_text("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.
page.clock.run_for(2000)
expect(locator).to_have_text("2/2/2024, 10:00:02 AM")
# Initialize clock with a specific time, let the page load naturally.
await page.clock.install(time=
datetime.datetime(2024, 2, 2, 8, 0, 0, tzinfo=datetime.timezone.pst),
)
await page.goto("https://127.0.0.1:3333")
locator = page.get_by_test_id("current-time")
# Pause the time flow, stop the timers, you now have manual control
# over the page time.
await page.clock.pause_at(datetime.datetime(2024, 2, 2, 10, 0, 0))
await expect(locator).to_have_text("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.run_for(2000)
await expect(locator).to_have_text("2/2/2024, 10:00:02 AM")