Skip to content

[Bug]: clock.set_fixed_time does not patch document.timeline.currentTime, causing broken animations after navigation #38951

@alexjrk

Description

@alexjrk

Version

1.57.0

Steps to reproduce

  1. Download this HTML file: test.html
  2. 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}")
  1. (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:

  1. 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.

  2. 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

  1. When calling clock.set_fixed_time, only patch Date() by default
  2. For cases where full clock mocking is desired, also patch document.timeline.currentTime
  3. 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

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions