Skip to main content

Часы

Введение

Точное моделирование поведения, зависящего от времени, необходимо для проверки корректности приложений. Использование функциональности Clock позволяет разработчикам манипулировать и контролировать время в тестах, что позволяет точно проверять такие функции, как время рендеринга, тайм-ауты, запланированные задачи без задержек и изменчивости реального времени выполнения.

API Clock предоставляет следующие методы для управления временем:

  • 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
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>
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'));
// Мы знаем, что на странице есть таймер, который обновляет время каждую секунду.
await expect(page.getByTestId('current-time')).toHaveText('2/2/2024, 10:30:00 AM');

Последовательное время и таймеры

Иногда ваши таймеры зависят от 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` будет прогрессировать по мере срабатывания таймеров.
await page.clock.install({ time: new Date('2024-02-02T08:00:00') });
await page.goto('http://localhost:3333');

// Представьте, что пользователь закрыл крышку ноутбука и открыл ее снова в 10 утра,
// Остановите время, как только достигнете этой точки.
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');

// Снова закройте крышку ноутбука и откройте ее в 10:30 утра.
await page.clock.fastForward('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 =
'Вы были выведены из системы из-за неактивности.';
} else {
document.getElementById('remaining-time').textContent =
`Вы будете выведены из системы через ${diffInSeconds} секунд.`;
}
setTimeout(renderTime, 1000);
};
renderTime();
</script>
<button type="button">Взаимодействие</button>
// Начальное время не имеет значения для теста, поэтому мы можем выбрать текущее время.
await page.clock.install();
await page.goto('http://localhost:3333');
// Взаимодействуйте со страницей
await page.getByRole('button').click();

// Перемотайте время на 5 минут вперед, как если бы пользователь ничего не делал.
// Перемотка вперед похожа на закрытие крышки ноутбука и открытие ее через 5 минут.
// Все таймеры, которые должны были сработать, сработают сразу, как в реальном браузере.
await page.clock.fastForward('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>
// Инициализируйте часы с конкретным временем, позвольте странице загрузиться естественно.
await page.clock.install({ time: new Date('2024-02-02T08:00:00') });
await page.goto('http://localhost:3333');

// Остановите поток времени, остановите таймеры, теперь у вас есть ручной контроль
// над временем страницы.
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');

// Ручное перемещение по времени, срабатывая все таймеры в процессе.
// В этом случае время будет обновлено на экране 2 раза.
await page.clock.runFor(2000);
await expect(page.getByTestId('current-time')).toHaveText('2/2/2024, 10:00:02 AM');

Связанные видео