Skip to main content

时钟

介绍

¥Introduction

准确模拟时间相关行为对于验证应用的正确性至关重要。利用 时钟 功能允许开发者在测试中操纵和控制时间,从而能够精确验证渲染时间、超时、计划任务等功能,而不会出现实时执行的延迟和变化。

¥Accurately simulating time-dependent behavior is essential for verifying the correctness of applications. Utilizing Clock functionality allows developers to manipulate and control time within tests, enabling the precise validation of features such as rendering time, timeouts, scheduled tasks without the delays and variability of real-time execution.

时钟 API 提供以下方法来控制时间:

¥The Clock API provides the following methods to control time:

  • setFixedTime:设置 Date.now()new Date() 的固定时间。

    ¥setFixedTime: Sets the fixed time for Date.now() and new Date().

  • install:初始化时钟并允许你:

    ¥install: initializes the clock and allows you to:

    • pauseAt:在特定时间暂停时间。

      ¥pauseAt: Pauses the time at a specific time.

    • fastForward:快进时间。

      ¥fastForward: Fast forwards the time.

    • runFor:运行特定持续时间的时间。

      ¥runFor: Runs the time for a specific duration.

    • resume:恢复时间。

      ¥resume: Resumes the time.

  • setSystemTime:设置当前系统时间。

    ¥setSystemTime: Sets the current system time.

推荐的方法是使用 setFixedTime 将时间设置为特定值。如果这对你的用例不起作用,你可以使用 install,它允许你稍后暂停时间、快进、勾选等。setSystemTime 仅推荐用于高级用例。

¥The recommended approach is to use setFixedTime to set the time to a specific value. If that doesn't work for your use case, you can use install which allows you to pause time later on, fast forward it, tick it, etc. setSystemTime is only recommended for advanced use cases.

注意

page.clock 覆盖与时间相关的原生全局类和函数,允许手动控制它们:*Date - setTimeout - clearTimeout - setInterval - clearInterval - requestAnimationFrame - cancelAnimationFrame - requestIdleCallback - cancelIdleCallback - performance

¥page.clock overrides native global classes and functions related to time allowing them to be manually controlled: - Date - setTimeout - clearTimeout - setInterval - clearInterval - requestAnimationFrame - cancelAnimationFrame - requestIdleCallback - cancelIdleCallback - performance

使用预定义时间进行测试

¥Test with predefined time

通常,你只需要在保持计时器运行的同时伪造 Date.now。这样,时间自然流动,但 Date.now 始终返回一个固定值。

¥Often you only need to fake Date.now while keeping the timers going. That way the time flows naturally, but Date.now always returns a fixed value.

<div id="current-time" data-testid="current-time"></div>
<script>
const renderTime = () => {
document.getElementById('current-time').textContent =
new Date().toLocaleString();
};
setInterval(renderTime, 1000);
</script>
await page.clock.setFixedTime(new Date('2024-02-02T10:00:00'));
await page.goto('http://localhost:3333');
await expect(page.getByTestId('current-time')).toHaveText('2/2/2024, 10:00:00 AM');

await page.clock.setFixedTime(new Date('2024-02-02T10:30:00'));
// We know that the page has a timer that updates the time every second.
await expect(page.getByTestId('current-time')).toHaveText('2/2/2024, 10:30:00 AM');

一致的时间和计时器

¥Consistent time and timers

有时你的计时器依赖于 Date.now,当 Date.now 值不随时间变化时会感到困惑。在这种情况下,你可以安装时钟并在测试时快进到感兴趣的时间。

¥Sometimes your timers depend on Date.now and are confused when the Date.now value does not change over time. In this case, you can install the clock and fast forward to the time of interest when testing.

<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.install({ time: new Date('2024-02-02T08:00:00') });
await page.goto('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.pauseAt(new Date('2024-02-02T10:00:00'));

// 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.fastForward('30:00');
await expect(page.getByTestId('current-time')).toHaveText('2/2/2024, 10:30:00 AM');

测试不活动监控

¥Test inactivity monitoring

不活动监控是 Web 应用中的常见功能,可在用户不活动一段时间后注销用户。测试此功能可能很棘手,因为你需要等待很长时间才能看到效果。借助时钟,你可以加快时间并快速测试此功能。

¥Inactivity monitoring is a common feature in web applications that logs out users after a period of inactivity. Testing this feature can be tricky because you need to wait for a long time to see the effect. With the help of the clock, you can speed up time and test this feature quickly.

<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.install();
await page.goto('http://localhost:3333');
// Interact with the page
await page.getByRole('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.fastForward('05:00');

// Check that the user was logged out automatically.
await expect(page.getByText('You have been logged out due to inactivity.')).toBeVisible();

手动计时,持续触发所有计时器

¥Tick through time manually, firing all the timers consistently

在极少数情况下,你可能希望手动计时,在此过程中触发所有计时器和动画帧,以实现对时间流逝的细粒度控制。

¥In rare cases, you may want to tick through time manually, firing all timers and animation frames in the process to achieve a fine-grained control over the passage of time.

<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.install({ time: new Date('2024-02-02T08:00:00') });
await page.goto('http://localhost:3333');

// Pause the time flow, stop the timers, you now have manual control
// over the page time.
await page.clock.pauseAt(new Date('2024-02-02T10:00:00'));
await expect(page.getByTestId('current-time')).toHaveText('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.runFor(2000);
await expect(page.getByTestId('current-time')).toHaveText('2/2/2024, 10:00:02 AM');

¥Related Videos