时钟
简介
准确模拟时间依赖行为对于验证应用程序的正确性至关重要。利用 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>
- 同步
- 异步
# 在测试时间之前初始化时钟并将页面加载自然地进行。
# 自然流逝,正如计时器触发一样。
page.clock.install(time=datetime.datetime(2024, 2, 2, 8, 0, 0))
page.goto("http://localhost:3333")
# 假设用户关闭了笔记本电脑盖子,然后再次打开时间为上午10点。
# 达到那一点后暂停时间。
page.clock.pause_at(datetime.datetime(2024, 2, 2, 10, 0, 0))
# 断言页面状态。
expect(page.get_by_test_id("current-time")).to_have_text("2/2/2024, 10:00:00 AM")
# 再次关闭笔记本电脑盖子,并在10点半打开。
page.clock.fast_forward("30:00")
expect(page.get_by_test_id("current-time")).to_have_text("2/2/2024, 10:30:00 AM")
# 在测试时间之前初始化时钟并将页面加载自然地进行。
# 自然流逝,正如计时器触发一样。
await page.clock.install(time=datetime.datetime(2024, 2, 2, 8, 0, 0))
await page.goto("http://localhost:3333")
# 假设用户关闭了笔记本电脑盖子,然后再次打开时间为上午10点。
# 达到那一点后暂停时间。
await page.clock.pause_at(datetime.datetime(2024, 2, 2, 10, 0, 0))
# 断言页面状态。
await expect(page.get_by_test_id("current-time")).to_have_text("2/2/2024, 10:00:00 AM")
# 再次关闭笔记本电脑盖子,并在10点半打开。
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 =
'由于长时间无操作,您已被自动登出。';
} else {
document.getElementById('remaining-time').textContent =
`您将在 ${diffInSeconds} 秒内被自动登出。`;
}
setTimeout(renderTime, 1000);
};
renderTime();
</script>
<button type="button">交互按钮</button>
- 同步
- 异步
# 初始时间对测试无关紧要,因此我们可以选择当前时间。
page.clock.install()
page.goto("http://localhost:3333")
# 与页面互动
page.get_by_role("button").click()
# 快进时间5分钟,就像用户什么也没做一样。
# 快进就像是关闭笔记本电脑盖子,5分钟后再次打开。
# 所有到期的计时器都会立即触发,就像真实的浏览器一样。
page.clock.fast_forward("05:00")
# 检查用户是否因非活动而自动注销。
expect(page.get_by_text("由于长时间无操作,您已被自动登出。")).to_be_visible()
# 初始时间对测试无关紧要,因此我们可以选择当前时间。
await page.clock.install()
await page.goto("http://localhost:3333")
# 与页面互动
await page.get_by_role("button").click()
# 快进时间5分钟,就像用户什么也没做一样。
# 快进就像是关闭笔记本电脑盖子,5分钟后再次打开。
# 所有到期的计时器都会立即触发,就像真实的浏览器一样。
await page.clock.fast_forward("05:00")
# 检查用户是否因非活动而自动注销。
await expect(page.getByText("由于长时间无操作,您已被自动登出。")).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>
- 同步
- 异步
# 初始化时钟为特定时间,让页面自然加载。
page.clock.install(
time=datetime.datetime(2024, 2, 2, 8, 0, 0, tzinfo=datetime.timezone.pst),
)
page.goto("http://localhost:3333")
locator = page.get_by_test_id("current-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")
# 手动推进时间,同时触发所有计时器。
# 在这种情况下,屏幕上显示的时间将更新两次。
page.clock.run_for(2000)
expect(locator).to_have_text("2/2/2024, 10:00:02 AM")
# 初始化时钟为特定时间,让页面自然加载。
await page.clock.install(time=
datetime.datetime(2024, 2, 2, 8, 0, 0, tzinfo=datetime.timezone.pst),
)
await page.goto("http://localhost:3333")
locator = page.get_by_test_id("current-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")
# 手动推进时间,同时触发所有计时器。
# 在这种情况下,屏幕上显示的时间将更新两次。
await page.clock.run_for(2000)
await expect(locator).to_have_text("2/2/2024, 10:00:02 AM")