Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions codeflash/languages/javascript/support.py
Original file line number Diff line number Diff line change
Expand Up @@ -2068,9 +2068,9 @@ def process_generated_test_strings(
generated_test_source, project_module_system, test_cfg.tests_project_rootdir
)

# Add .js extensions to relative imports for ESM projects
# TypeScript + ESM requires explicit .js extensions even for .ts source files
if project_module_system == ModuleSystem.ES_MODULE:
# Add .js extensions to relative imports for ESM projects — but NOT for Jest,
# which resolves .ts imports without .js extensions via its transform/resolver.
if project_module_system == ModuleSystem.ES_MODULE and test_cfg.test_framework != "jest":
from codeflash.languages.javascript.module_system import add_js_extensions_to_relative_imports

generated_test_source = add_js_extensions_to_relative_imports(generated_test_source)
Expand Down Expand Up @@ -2270,10 +2270,13 @@ def get_module_path(self, source_file: Path, project_root: Path, tests_root: Pat
# Use os.path.relpath to compute relative path from tests_root to source file
rel_path = os.path.relpath(str(source_without_ext), str(tests_root_abs))

# For ESM, add .js extension (TypeScript convention)
# TypeScript requires imports to reference the OUTPUT file extension (.js),
# even when the source file is .ts. This is required for Node.js ESM resolution.
if module_system == ModuleSystem.ES_MODULE:
# For ESM, add .js extension (TypeScript convention) — but only for Vitest/native ESM.
# Jest resolves .ts imports without .js extensions via its transform/resolver config,
# so adding .js breaks Jest module resolution (Cannot find module '../foo.js').
from codeflash.languages.test_framework import get_js_test_framework_or_default

test_framework = get_js_test_framework_or_default()
if module_system == ModuleSystem.ES_MODULE and test_framework != "jest":
rel_path = rel_path + ".js"
logger.debug(
f"!lsp|Module path (ESM): source={source_file_abs}, tests_root={tests_root_abs}, "
Expand All @@ -2292,7 +2295,7 @@ def get_module_path(self, source_file: Path, project_root: Path, tests_root: Pat
# For fallback, also check module system
module_system = detect_module_system(project_root, source_file)
path_without_ext = "../" + rel_path.with_suffix("").as_posix()
if module_system == ModuleSystem.ES_MODULE:
if module_system == ModuleSystem.ES_MODULE and test_framework != "jest":
return path_without_ext + ".js"
return path_without_ext

Expand Down
10 changes: 8 additions & 2 deletions codeflash/languages/javascript/test_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -1104,6 +1104,9 @@ def run_jest_benchmarking_tests(
jest_env["CODEFLASH_PERF_TARGET_DURATION_MS"] = str(target_duration_ms)
jest_env["CODEFLASH_PERF_STABILITY_CHECK"] = "true" if stability_check else "false"
jest_env["CODEFLASH_LOOP_INDEX"] = "1" # Initial value for compatibility
# Warmup and calibration for accurate benchmarking
jest_env["CODEFLASH_PERF_WARMUP_ITERATIONS"] = "3"
jest_env["CODEFLASH_PERF_MIN_TIME_NS"] = "5000" # 5us minimum time for calibration

# Enable console output for timing markers
# Some projects mock console.log in test setup (e.g., based on LOG_LEVEL or DEBUG)
Expand All @@ -1119,10 +1122,13 @@ def run_jest_benchmarking_tests(
# Configure ESM support if project uses ES Modules
_configure_esm_environment(jest_env, effective_cwd)

# Increase Node.js heap size for large TypeScript projects
# Increase Node.js heap size and expose GC for accurate benchmarking
existing_node_options = jest_env.get("NODE_OPTIONS", "")
if "--max-old-space-size" not in existing_node_options:
jest_env["NODE_OPTIONS"] = f"{existing_node_options} --max-old-space-size=4096".strip()
existing_node_options = f"{existing_node_options} --max-old-space-size=4096".strip()
if "--expose-gc" not in existing_node_options:
existing_node_options = f"{existing_node_options} --expose-gc".strip()
jest_env["NODE_OPTIONS"] = existing_node_options

# Subprocess timeout: target_duration + 120s headroom for Jest startup
# and TS compilation. capturePerf's time budget governs actual looping.
Expand Down
11 changes: 11 additions & 0 deletions codeflash/languages/javascript/vitest_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -681,6 +681,17 @@ def run_vitest_benchmarking_tests(
vitest_env["CODEFLASH_PERF_TARGET_DURATION_MS"] = str(target_duration_ms)
vitest_env["CODEFLASH_PERF_STABILITY_CHECK"] = "true" if stability_check else "false"
vitest_env["CODEFLASH_LOOP_INDEX"] = "1"
# Warmup and calibration for accurate benchmarking
vitest_env["CODEFLASH_PERF_WARMUP_ITERATIONS"] = "3"
vitest_env["CODEFLASH_PERF_MIN_TIME_NS"] = "5000" # 5us minimum time for calibration

# Expose GC for accurate benchmarking (allows capturePerf to force GC before timing)
existing_node_options = vitest_env.get("NODE_OPTIONS", "")
if "--expose-gc" not in existing_node_options:
existing_node_options = f"{existing_node_options} --expose-gc".strip()
if "--max-old-space-size" not in existing_node_options:
existing_node_options = f"{existing_node_options} --max-old-space-size=4096".strip()
vitest_env["NODE_OPTIONS"] = existing_node_options

# Set test module for marker identification (use first test file as reference)
if test_files:
Expand Down
Loading