Some checks are pending
Claude Code / pr-review (pull_request) Waiting to run
Claude Code / claude-mention (pull_request) Waiting to run
CodeFlash / Optimize new Python code (pull_request) Waiting to run
E2E - Async / async-optimization (pull_request) Waiting to run
E2E - Bubble Sort Benchmark / benchmark-bubble-sort-optimization (pull_request) Waiting to run
E2E - Bubble Sort Pytest (No Git) / bubble-sort-optimization-pytest-no-git (pull_request) Waiting to run
E2E - Bubble Sort Unittest / bubble-sort-optimization-unittest (pull_request) Waiting to run
Coverage E2E / end-to-end-test-coverage (pull_request) Waiting to run
E2E - Futurehouse Structure / futurehouse-structure (pull_request) Waiting to run
E2E - Init Optimization / init-optimization (pull_request) Waiting to run
E2E - Java Fibonacci (No Git) / java-fibonacci-optimization-no-git (pull_request) Waiting to run
E2E - Java Tracer / java-tracer-e2e (pull_request) Waiting to run
E2E - JS CommonJS Function / js-cjs-function-optimization (pull_request) Waiting to run
E2E - JS ESM Async / js-esm-async-optimization (pull_request) Waiting to run
E2E - JS TypeScript Class / js-ts-class-optimization (pull_request) Waiting to run
E2E - Topological Sort (Worktree) / topological-sort-worktree-optimization (pull_request) Waiting to run
E2E - Tracer Replay / tracer-replay (pull_request) Waiting to run
Java E2E Tests / java-e2e (pull_request) Waiting to run
PR Labeler / label-workflow-changes (pull_request) Waiting to run
Mypy Type Checking for CLI / type-check-cli (pull_request) Waiting to run
Lint / prek (pull_request) Waiting to run
unit-tests / unit-tests (ubuntu-latest, 3.10) (pull_request) Waiting to run
unit-tests / unit-tests (ubuntu-latest, 3.11) (pull_request) Waiting to run
unit-tests / unit-tests (ubuntu-latest, 3.12) (pull_request) Waiting to run
unit-tests / unit-tests (ubuntu-latest, 3.13) (pull_request) Waiting to run
unit-tests / unit-tests (ubuntu-latest, 3.14) (pull_request) Waiting to run
unit-tests / unit-tests (ubuntu-latest, 3.9) (pull_request) Waiting to run
unit-tests / unit-tests (windows-latest, 3.13) (pull_request) Waiting to run
## Problem
When test files were inside the project root (common case), Codeflash did NOT
create the runtime config that disables globalSetup/globalTeardown. This caused
Jest to use the project's original config WITH globalSetup, leading to failures
when globalSetup required unavailable infrastructure (Docker, databases, etc.):
Error: Jest: Got error running globalSetup - /workspace/target/globalSetup.ts,
reason: Command failed: docker context ls --format json
/bin/sh: 1: docker: not found
## Root Cause
Runtime config was only created when tests were OUTSIDE project root:
if any(not Path(d).is_relative_to(resolved_root) for d in test_dirs):
jest_config = _create_runtime_jest_config(...)
But globalSetup should be disabled for ALL Codeflash test runs.
## Solution
Always create runtime config when `jest_config` and `test_files` exist:
if test_files and jest_config:
test_dirs = {str(Path(f).resolve().parent) for f in test_files}
jest_config = _create_runtime_jest_config(jest_config, effective_cwd, test_dirs)
## Impact
- Affected: ALL projects with globalSetup/globalTeardown in Jest config
- Reproducibility: 100% systematic
- Example trace: 04dc4dcf-ca9f-449e-aed5-7a82f28c5e23
## Changes
- test_runner.py: Updated 3 functions (behavioral, benchmarking, line profiling)
- New test file: test_globalsetup_invocation_bug.py (3 test cases)
- All existing tests still pass
Fixes #18
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
198 lines
8 KiB
Python
198 lines
8 KiB
Python
"""
|
|
Test for Issue #18: globalSetup not disabled when tests are inside project root.
|
|
|
|
When test files are inside the project root (common case), the runtime config that
|
|
disables globalSetup/globalTeardown is never created. This causes Jest to use the
|
|
project's original config, which may have globalSetup hooks that require
|
|
infrastructure (Docker, databases) that isn't available during Codeflash runs.
|
|
|
|
Example failure:
|
|
Error: Jest: Got error running globalSetup - /workspace/target/globalSetup.ts,
|
|
reason: Command failed: docker context ls --format json
|
|
/bin/sh: 1: docker: not found
|
|
|
|
Root cause (before fix):
|
|
In test_runner.py, _create_runtime_jest_config was only called when:
|
|
if any(not Path(d).is_relative_to(resolved_root) for d in test_dirs):
|
|
jest_config = _create_runtime_jest_config(...)
|
|
|
|
But globalSetup should be disabled for ALL Codeflash test runs, not just when
|
|
tests are outside the project root.
|
|
|
|
Fix:
|
|
Always call _create_runtime_jest_config when jest_config and test_files exist,
|
|
regardless of whether tests are inside or outside the project root.
|
|
"""
|
|
|
|
import tempfile
|
|
from pathlib import Path
|
|
from unittest.mock import MagicMock, call, patch
|
|
|
|
import pytest
|
|
|
|
from codeflash.languages.javascript.test_runner import _create_runtime_jest_config
|
|
from codeflash.models.models import TestFile, TestFiles
|
|
from codeflash.models.test_type import TestType
|
|
|
|
|
|
def test_runtime_config_always_created_when_jest_config_exists():
|
|
"""
|
|
Test that _create_runtime_jest_config is called even when tests are inside project root.
|
|
|
|
This is the KEY fix for Issue #18: we must ALWAYS create the runtime config
|
|
to ensure globalSetup is disabled, not just when tests are outside project root.
|
|
"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
project_root = Path(tmpdir) / "project"
|
|
project_root.mkdir()
|
|
|
|
# Create a Jest config
|
|
jest_config = project_root / "jest.config.js"
|
|
jest_config.write_text("module.exports = { globalSetup: './setup.ts' };")
|
|
|
|
# Create test file INSIDE project root (common case)
|
|
test_dir = project_root / "src" / "tests"
|
|
test_dir.mkdir(parents=True)
|
|
test_file = test_dir / "test_example.test.ts"
|
|
test_file.write_text("test('example', () => expect(true).toBe(true));")
|
|
|
|
# Create package.json
|
|
(project_root / "package.json").write_text('{"name": "test"}')
|
|
|
|
# Create node_modules/codeflash
|
|
(project_root / "node_modules" / "codeflash").mkdir(parents=True)
|
|
|
|
# Create TestFiles object
|
|
test_file_obj = TestFile(
|
|
instrumented_behavior_file_path=test_file,
|
|
benchmarking_file_path=test_file,
|
|
test_type=TestType.GENERATED_REGRESSION,
|
|
)
|
|
test_paths = TestFiles(test_files=[test_file_obj])
|
|
|
|
# Mock _create_runtime_jest_config to track if it's called
|
|
with patch('codeflash.languages.javascript.test_runner._create_runtime_jest_config', wraps=_create_runtime_jest_config) as mock_create_runtime:
|
|
with patch('codeflash.languages.javascript.test_runner.subprocess.run') as mock_run:
|
|
# Mock Jest execution
|
|
mock_run.return_value = MagicMock(returncode=0, stdout="", stderr="")
|
|
|
|
with patch('codeflash.languages.javascript.test_runner._get_jest_config_for_project', return_value=jest_config):
|
|
from codeflash.languages.javascript.test_runner import run_jest_behavioral_tests
|
|
try:
|
|
run_jest_behavioral_tests(
|
|
test_paths=test_paths,
|
|
test_env={},
|
|
cwd=project_root,
|
|
project_root=project_root,
|
|
enable_coverage=False,
|
|
timeout=60,
|
|
)
|
|
except Exception:
|
|
pass # May fail due to mocking, that's OK
|
|
|
|
# THE KEY ASSERTION: _create_runtime_jest_config MUST be called
|
|
# even when tests are inside the project root
|
|
assert mock_create_runtime.call_count > 0, (
|
|
"VULNERABILITY: _create_runtime_jest_config was not called when tests are inside project root. "
|
|
f"This means globalSetup is NOT disabled, causing failures on projects with Docker/DB setup hooks. "
|
|
f"Test file: {test_file}, Project root: {project_root}"
|
|
)
|
|
|
|
# Verify it was called with correct arguments
|
|
call_args = mock_create_runtime.call_args
|
|
assert call_args is not None
|
|
assert call_args[0][0] == jest_config # base_config_path
|
|
assert call_args[0][1] == project_root # project_root
|
|
# test_dirs should include the test directory
|
|
assert str(test_dir) in call_args[0][2]
|
|
|
|
|
|
def test_runtime_config_disables_globalsetup_for_tests_inside_project():
|
|
"""
|
|
Test the actual runtime config file created for tests inside project root.
|
|
|
|
Verifies that the config file disables globalSetup/globalTeardown.
|
|
"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
project_root = Path(tmpdir) / "project"
|
|
project_root.mkdir()
|
|
|
|
# Create base config with globalSetup
|
|
jest_config = project_root / "jest.config.js"
|
|
jest_config.write_text("""
|
|
module.exports = {
|
|
testEnvironment: 'node',
|
|
globalSetup: './globalSetup.ts',
|
|
globalTeardown: './globalTeardown.ts',
|
|
};
|
|
""")
|
|
|
|
# Test directory INSIDE project root
|
|
test_dir = project_root / "src" / "tests" / "codeflash-generated"
|
|
test_dir.mkdir(parents=True)
|
|
|
|
# Create runtime config
|
|
test_dirs = {str(test_dir)}
|
|
runtime_config = _create_runtime_jest_config(
|
|
base_config_path=jest_config,
|
|
project_root=project_root,
|
|
test_dirs=test_dirs
|
|
)
|
|
|
|
# Verify runtime config was created
|
|
assert runtime_config is not None, (
|
|
"VULNERABILITY: Runtime config not created for tests inside project root"
|
|
)
|
|
assert runtime_config.exists(), (
|
|
f"VULNERABILITY: Runtime config file doesn't exist: {runtime_config}"
|
|
)
|
|
|
|
# Verify it disables globalSetup and globalTeardown
|
|
config_content = runtime_config.read_text()
|
|
assert "globalSetup: undefined" in config_content, (
|
|
f"VULNERABILITY: globalSetup not disabled in runtime config.\nContent:\n{config_content}"
|
|
)
|
|
assert "globalTeardown: undefined" in config_content, (
|
|
f"VULNERABILITY: globalTeardown not disabled in runtime config.\nContent:\n{config_content}"
|
|
)
|
|
|
|
|
|
def test_runtime_config_created_for_tests_in_subdirectories():
|
|
"""
|
|
Test that runtime config is created even when tests are in subdirectories of project root.
|
|
|
|
This is the most common case: tests in packages/server/src/tests/, project root at packages/server/.
|
|
"""
|
|
with tempfile.TemporaryDirectory() as tmpdir:
|
|
project_root = Path(tmpdir) / "packages" / "server"
|
|
project_root.mkdir(parents=True)
|
|
|
|
jest_config = project_root / "jest.config.ts"
|
|
jest_config.write_text("""
|
|
export default {
|
|
testEnvironment: 'node',
|
|
globalSetup: './setup.ts',
|
|
};
|
|
""")
|
|
|
|
# Test file in deeply nested subdirectory (still inside project root)
|
|
test_dir = project_root / "src" / "automations" / "tests" / "codeflash-generated"
|
|
test_dir.mkdir(parents=True)
|
|
test_file = test_dir / "test_example.test.ts"
|
|
test_file.write_text("test('example', () => expect(true).toBe(true));")
|
|
|
|
# Create the runtime config directly (unit test, not full integration)
|
|
test_dirs = {str(test_dir)}
|
|
runtime_config = _create_runtime_jest_config(
|
|
base_config_path=jest_config,
|
|
project_root=project_root,
|
|
test_dirs=test_dirs
|
|
)
|
|
|
|
# Verify runtime config exists and disables globalSetup
|
|
assert runtime_config is not None
|
|
assert runtime_config.exists()
|
|
|
|
config_content = runtime_config.read_text()
|
|
assert "globalSetup: undefined" in config_content
|
|
assert "globalTeardown: undefined" in config_content
|