Loop index now represents how many times all test files ran (batch count)
instead of per-invocation index. Also fixes Date.now() usage when random
seed is active and removes JS-specific workaround in number_of_loops.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Improvements to loop-runner.js:
- Extract isValidJestRunnerPath() helper to reduce code duplication
- Add comprehensive JSDoc comments for Jest version detection
- Improve error messages with more context about detected versions
- Add better documentation for runTests() method
- Add validation for TestRunner class availability in Jest 30
Improvements to capture.js:
- Extract _recordAsyncTiming() helper to reduce duplication
- Add comprehensive JSDoc for _capturePerfAsync() with all parameters
- Improve error handling in async looping (record timing before throwing)
- Enhance shouldStopStability() documentation with algorithm details
- Improve code organization with clearer comments
These changes improve maintainability and debugging without changing behavior.
After merging main, constants like PERF_STABILITY_CHECK, PERF_MIN_LOOPS,
PERF_LOOP_COUNT were changed to getter functions. Updated all references
in capturePerf and _capturePerfAsync to use the getter function calls.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
- Add Jest 30 compatibility by detecting version and using TestRunner class
- Resolve jest-runner from project's node_modules instead of codeflash's bundle
- Fix time limit enforcement by using local time tracking instead of shared state
(Jest runs tests in worker processes, so state isn't shared with runner)
- Integrate stability-based early stopping into capturePerf
- Use plain object instead of Set for stableInvocations to survive Jest module resets
- Fix async function benchmarking: properly loop through iterations using async helper
(Previously, async functions only got one timing marker due to early return)
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Instead of duplicating monorepo detection logic in JavaScript, leverage
the existing Python _find_node_project_root and add _find_monorepo_root
functions. Pass the detected monorepo root via CODEFLASH_MONOREPO_ROOT
environment variable to the loop-runner.
This approach:
- Reuses existing Python project detection logic
- Provides a reliable monorepo root hint to JavaScript
- Maintains fallback directory traversal for edge cases
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Added resolveJestRunner() function that walks up the directory tree to
find jest-runner in workspace root node_modules. This fixes the
"jest-runner requires jest-runner to be installed" error when running
in monorepo packages.
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Vitest caches modules and may load capture.js before environment
variables like CODEFLASH_PERF_LOOP_COUNT are set. When these were
read as constants at module load time, they would always return
default values.
This change converts the performance configuration from constants
to getter functions that read environment variables at runtime,
ensuring correct values are used even when the module is cached.
Fixes:
- PERF_LOOP_COUNT always being 1 in Vitest
- PERF_BATCH_SIZE, PERF_MIN_LOOPS, etc. using defaults instead of env values
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Previously, MAX_BATCHES was set to PERF_LOOP_COUNT directly (e.g., 250),
which caused the loop-runner to run 250 batches even though only 25
batches were needed to produce timing data (with BATCH_SIZE=10).
The bug was that timing markers only appeared for the first N batches
(where N = LOOP_COUNT / BATCH_SIZE), and the remaining batches were
wasted overhead.
Fix: Calculate MAX_BATCHES as ceil(LOOP_COUNT / BATCH_SIZE) + 1, capped
at LOOP_COUNT. This ensures only the necessary batches run:
- With LOOP_COUNT=250, BATCH_SIZE=10: MAX_BATCHES = 26 (not 250)
This significantly improves benchmark efficiency by eliminating wasted
Jest passes that don't contribute timing data.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>