时钟
简介
准确模拟时间相关行为对于验证应用程序的正确性至关重要。利用Clock功能,开发者可以在测试中操纵和控制时间,从而无需实时执行的延迟和变异性,就能精确验证诸如渲染时间、超时、计划任务等特性。
Clock API 提供以下方法来控制时间:
setFixedTime
: 为Date.now()
和new Date()
设置固定时间。install
: initializes the clock and allows you to:pauseAt
: 在特定时间暂停计时。fastForward
: 快速前进时间。runFor
: 运行特定时长的时间。resume
: 恢复时间。
setSystemTime
: 设置当前系统时间。
推荐的方法是使用setFixedTime
将时间设置为特定值。如果这不适用于您的用例,您可以使用install
,它允许您稍后暂停时间、快进时间、计时等。setSystemTime
仅推荐用于高级用例。
note
Page.clock() 覆盖了与时间相关的原生全局类和方法,使它们能够被手动控制:
Date
setTimeout
clearTimeout
setInterval
clearInterval
requestAnimationFrame
cancelAnimationFrame
requestIdleCallback
cancelIdleCallback
performance
Event.timeStamp
warning
如果在测试中的任何时刻调用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.
SimpleDateFormat format = new SimpleDateFormat("yyy-MM-dd'T'HH:mm:ss");
page.clock().install(new Clock.InstallOptions().setTime(format.parse("2024-02-02T08:00:00")));
page.navigate("http://localhost:3333");
Locator locator = page.getByTestId("current-time");
// Pretend that the user closed the laptop lid and opened it again at 10am.
// Pause the time once reached that point.
page.clock().pauseAt(format.parse("2024-02-02T10:00:00"));
// Assert the page state.
assertThat(locator).hasText("2/2/2024, 10:00:00 AM");
// Close the laptop lid again and open it at 10:30am.
page.clock().fastForward("30:00");
assertThat(locator).hasText("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.
page.clock().install();
page.navigate("http://localhost:3333");
Locator locator = page.getByRole("button");
// Interact with the page
locator.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().fastForward("05:00");
// Check that the user was logged out automatically.
assertThat(page.getByText("You have been logged out due to inactivity.")).isVisible();
手动逐步推进时间,一致触发所有计时器
在极少数情况下,您可能需要手动推进时间,在此过程中触发所有计时器和动画帧,以实现对时间流逝的精细控制。
<div id="current-time" data-testid="current-time"></div>
<script>
const renderTime = () => {
document.getElementById('current-time').textContent =
new Date().toLocaleString();
};
setInterval(renderTime, 1000);
</script>
SimpleDateFormat format = new SimpleDateFormat("yyy-MM-dd'T'HH:mm:ss");
// Initialize clock with a specific time, let the page load naturally.
page.clock().install(new Clock.InstallOptions()
.setTime(format.parse("2024-02-02T08:00:00")));
page.navigate("http://localhost:3333");
Locator locator = page.getByTestId("current-time");
// Pause the time flow, stop the timers, you now have manual control
// over the page time.
page.clock().pauseAt(format.parse("2024-02-02T10:00:00"));
assertThat(locator).hasText("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().runFor(2000);
assertThat(locator).hasText("2/2/2024, 10:00:02 AM");