Version
1.57.0
Steps to reproduce
- Download this HTML file: test.html
- Run the following test using
pytest-playwright:
def test_bug_poc(page: Page):
path_to_test_html = "change-me"
page.goto(f"file:///{path_to_test_html}")
page.clock.set_fixed_time(datetime(2026, 1, 2, 10, 0, 0))
page.goto(f"file:///{path_to_test_html}")
- (Optional) Add a breakpoint on:
page.clock.set_fixed_time(datetime(2026, 1, 2, 10, 0, 0))
Expected behavior
The animation should behave identically before and after applying the clock patch, including after page navigation or refresh.
Actual behavior
After calling clock.set_fixed_time and navigating / refreshing the page, the animation no longer runs at the expected time. Instead, it starts several seconds later than it should.
Additional context
While writing tests that require mocking new Date(), I noticed flaky behavior in animations. After further investigation, I identified two related issues with the current clock implementation:
-
set_fixed_time implicitly calls install() and patches all time-related APIs
The clock.set_fixed_time method internally calls install() and patches multiple time-related functions (see code here)).
In my use case, I only wanted to mock Date. Patching additional APIs such as performance.now() and animation timing APIs introduces unintended side effects. It would be preferable if set_fixed_time only patched Date, unless explicitly requested otherwise.
-
document.timeline.currentTime is not patched
The clock patches performance.now(), but does not patch document.timeline.currentTime. This causes issues with animation libraries like motion, which rely on both performance.now() and document.timeline.currentTime() (example here).
As a result, after navigation or refresh:
- The browser’s native
performance.now() and document.timeline.currentTime resets to 0
- The patched
performance.now() continues from the original patched offset
document.timeline.currentTime continues to use the unpatched timeline
This mismatch causes animations to be delayed by the time elapsed between the original clock patch and the page navigation.
In the provided reproducer console, you can also observe that after a page refresh or navigation, the animation’s currentTime becomes negative, starting from the difference between the original time patch and the refresh/navigation.
This bug is difficult to notice because:
- It only appears when using Web Animations APIs
- The animation library must rely on both
performance.now() and document.timeline.currentTime()
- A page refresh or navigation is required
When using set_fixed_time without navigation, the issue is often masked because the patched and unpatched performance.now() values remain close.
Proposed solutions
- When calling
clock.set_fixed_time, only patch Date() by default
- For cases where full clock mocking is desired, also patch
document.timeline.currentTime
- Provide a way to unpatch / restore patched time functions, for example via:
- a
clock.reset() / clock.uninstall() API, or
- automatically restoring the original implementations on page navigation or reload.
Either approach would significantly improve reliability when testing animation-heavy applications, especially those using libraries like motion.
Environment
System:
OS: Windows 11 10.0.26200
CPU: (20) x64 13th Gen Intel(R) Core(TM) i9-13900H
Memory: 37.95 GB / 63.66 GB
Binaries:
Node: 22.16.0 - C:\Program Files\nodejs\node.EXE
npm: 11.4.2 - C:\Program Files\nodejs\npm.CMD
pnpm: 10.26.0 - C:\Users\xxx\AppData\Roaming\npm\pnpm.CMD
IDEs:
VSCode: 1.108.2 - C:\Users\xxx\AppData\Local\Programs\Microsoft VS Code\bin\code.CMD
Cursor: 1.7.17 - C:\Users\xxx\AppData\Local\Programs\cursor\resources\app\bin\cursor.CMD
Version
1.57.0
Steps to reproduce
pytest-playwright:Expected behavior
The animation should behave identically before and after applying the clock patch, including after page navigation or refresh.
Actual behavior
After calling
clock.set_fixed_timeand navigating / refreshing the page, the animation no longer runs at the expected time. Instead, it starts several seconds later than it should.Additional context
While writing tests that require mocking
new Date(), I noticed flaky behavior in animations. After further investigation, I identified two related issues with the current clock implementation:set_fixed_timeimplicitly callsinstall()and patches all time-related APIsThe
clock.set_fixed_timemethod internally callsinstall()and patches multiple time-related functions (see code here)).In my use case, I only wanted to mock
Date. Patching additional APIs such asperformance.now()and animation timing APIs introduces unintended side effects. It would be preferable ifset_fixed_timeonly patchedDate, unless explicitly requested otherwise.document.timeline.currentTimeis not patchedThe clock patches
performance.now(), but does not patchdocument.timeline.currentTime. This causes issues with animation libraries like motion, which rely on bothperformance.now()anddocument.timeline.currentTime()(example here).As a result, after navigation or refresh:
performance.now()anddocument.timeline.currentTimeresets to 0performance.now()continues from the original patched offsetdocument.timeline.currentTimecontinues to use the unpatched timelineThis mismatch causes animations to be delayed by the time elapsed between the original clock patch and the page navigation.
In the provided reproducer console, you can also observe that after a page refresh or navigation, the animation’s
currentTimebecomes negative, starting from the difference between the original time patch and the refresh/navigation.This bug is difficult to notice because:
performance.now()anddocument.timeline.currentTime()When using
set_fixed_timewithout navigation, the issue is often masked because the patched and unpatchedperformance.now()values remain close.Proposed solutions
clock.set_fixed_time, only patchDate()by defaultdocument.timeline.currentTimeclock.reset()/clock.uninstall()API, orEither approach would significantly improve reliability when testing animation-heavy applications, especially those using libraries like
motion.Environment