[test optimization] Use real timers in test framework instrumentations#7971
[test optimization] Use real timers in test framework instrumentations#7971juan-fernandez merged 7 commits intomasterfrom
Conversation
dd-trace's jest/mocha/vitest instrumentations used bare `setTimeout` inside `handleTestEvent` and session finish handlers. When a test installs fake timers (e.g. `jest.useFakeTimers()`), these calls are intercepted by the fake clock. Since jest-circus awaits the handler's return promise, and the fake clock is never advanced for dd-trace's internal operations, the test execution deadlocks. The specific trigger: DI (Failed Test Replay) enabled + a new test using fake timers. On the second execution, dd-trace awaits a `setTimeout` for the breakpoint hit grace period, which never fires under fake timers. Fix: capture `setTimeout` at module load time (before any test can install fake timers) and use the captured reference for all internal timer operations. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Overall package sizeSelf size: 5.48 MB Dependency sizes| name | version | self size | total size | |------|---------|-----------|------------| | import-in-the-middle | 3.0.1 | 82.56 kB | 817.39 kB | | dc-polyfill | 0.1.10 | 26.73 kB | 26.73 kB |🤖 This report was automatically generated by heaviest-objects-in-the-universe |
|
✅ Tests 🎉 All green!❄️ No new flaky tests detected 🎯 Code Coverage (details) 🔗 Commit SHA: ce68dbe | Docs | Datadog PR Page | Was this helpful? React with 👍/👎 or give us feedback! |
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## master #7971 +/- ##
=======================================
Coverage 73.82% 73.82%
=======================================
Files 773 773
Lines 35972 35983 +11
=======================================
+ Hits 26556 26565 +9
- Misses 9416 9418 +2 Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Sentry. 🚀 New features to boost your workflow:
|
BenchmarksBenchmark execution time: 2026-04-10 10:10:29 Comparing candidate commit ce68dbe in PR branch Found 0 performance improvements and 0 performance regressions! Performance is the same for 228 metrics, 32 unstable metrics. |
Adds jest and vitest integration tests that verify dd-trace completes normally when tests use fake timers with DI (Failed Test Replay) enabled. The tests install fake timers in beforeAll, run a failing test that triggers ATR retries, and verify the process doesn't hang on the DI breakpoint grace period setTimeout. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…erns The previous names (flaky-fails-with-fake-timers, dynamic-instrumentation-with-fake-timers) were matched by existing broad TESTS_TO_RUN regexes, causing extra tests to run in unrelated test suites. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The DI probe setup in mocha and cucumber uses a synchronous busy-wait loop with Date.now() to wait for breakpoint registration. When sinon.useFakeTimers() is active, Date.now() returns a frozen timestamp, causing an infinite loop. Capture Date.now at module load time (before any test installs fake timers) and use the captured reference in the busy-wait loops. Also adds cucumber and mocha integration test fixtures and tests for fake timers + DI interaction. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…est assertions - Fix remaining setTimeout in cucumber plugin's hitBreakpointPromise (packages/datadog-plugin-cucumber/src/index.js:235) which was still using the ambient setTimeout under fake timers - Strengthen all four integration test assertions to verify retries actually happened (2 tests total, 1 with TEST_IS_RETRY) instead of just asserting tests.length > 0 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The withTimeout function in the jest plugin uses setTimeout to cap the DI probe setup wait. This is awaited inside handleTestEvent under fake timers. Use the captured realSetTimeout instead. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Defensive hardening — same pattern as the other test framework fixes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
What does this PR do?
Captures real timer functions (
setTimeout,Date.now) at module load time in test framework instrumentations, before any test can install fake timers.Motivation
When DI (Failed Test Replay) is enabled and a test uses fake timers (
jest.useFakeTimers(),sinon.useFakeTimers()), dd-trace's internal timer operations get intercepted by the fake clock, causing the test process to hang indefinitely:setTimeoutin the DI breakpoint grace period (handleTestEvent) never fires under fake timersDate.now()in the DI probe setup busy-wait loop returns a frozen timestamp, causing an infinite loopAdditional Notes
setTimeoutintest_done+ session flushrealSetTimeout = setTimeoutsetTimeoutinwaitForHitProberealSetTimeout = setTimeoutDate.now()busy-wait in probe setuprealDateNow = Date.now.bind(Date)Date.now()busy-wait in probe setuprealDateNow = Date.now.bind(Date)