Merge branch 'main' into fix/vitest-coverage-override
This commit is contained in:
commit
08b9fe8d7f
9 changed files with 394 additions and 12 deletions
|
|
@ -3085,6 +3085,16 @@ class FunctionOptimizer:
|
|||
)
|
||||
)
|
||||
|
||||
def get_js_project_root(self) -> Path | None:
|
||||
# Only calculate for JavaScript/TypeScript projects
|
||||
if self.function_to_optimize.language not in ("javascript", "typescript"):
|
||||
return self.test_cfg.js_project_root # Fall back to cached value for non-JS
|
||||
|
||||
# For JS/TS, calculate fresh for each function to support monorepos
|
||||
from codeflash.languages.javascript.test_runner import find_node_project_root
|
||||
|
||||
return find_node_project_root(Path(self.function_to_optimize.file_path))
|
||||
|
||||
def run_and_parse_tests(
|
||||
self,
|
||||
testing_type: TestingMode,
|
||||
|
|
@ -3103,33 +3113,39 @@ class FunctionOptimizer:
|
|||
coverage_config_file = None
|
||||
try:
|
||||
if testing_type == TestingMode.BEHAVIOR:
|
||||
# Calculate js_project_root for the current function being optimized
|
||||
# instead of using cached value from test_cfg, which may be from a different function
|
||||
js_project_root = self.get_js_project_root()
|
||||
|
||||
result_file_path, run_result, coverage_database_file, coverage_config_file = (
|
||||
self.language_support.run_behavioral_tests(
|
||||
test_paths=test_files,
|
||||
test_env=test_env,
|
||||
cwd=self.project_root,
|
||||
timeout=INDIVIDUAL_TESTCASE_TIMEOUT,
|
||||
project_root=self.test_cfg.js_project_root,
|
||||
project_root=js_project_root,
|
||||
enable_coverage=enable_coverage,
|
||||
candidate_index=optimization_iteration,
|
||||
)
|
||||
)
|
||||
elif testing_type == TestingMode.LINE_PROFILE:
|
||||
js_project_root = self.get_js_project_root()
|
||||
result_file_path, run_result = self.language_support.run_line_profile_tests(
|
||||
test_paths=test_files,
|
||||
test_env=test_env,
|
||||
cwd=self.project_root,
|
||||
timeout=INDIVIDUAL_TESTCASE_TIMEOUT,
|
||||
project_root=self.test_cfg.js_project_root,
|
||||
project_root=js_project_root,
|
||||
line_profile_output_file=line_profiler_output_file,
|
||||
)
|
||||
elif testing_type == TestingMode.PERFORMANCE:
|
||||
js_project_root = self.get_js_project_root()
|
||||
result_file_path, run_result = self.language_support.run_benchmarking_tests(
|
||||
test_paths=test_files,
|
||||
test_env=test_env,
|
||||
cwd=self.project_root,
|
||||
timeout=INDIVIDUAL_TESTCASE_TIMEOUT,
|
||||
project_root=self.test_cfg.js_project_root,
|
||||
project_root=js_project_root,
|
||||
min_loops=pytest_min_loops,
|
||||
max_loops=pytest_max_loops,
|
||||
target_duration_seconds=testing_time,
|
||||
|
|
|
|||
|
|
@ -1287,13 +1287,13 @@ def fix_imports_inside_test_blocks(test_code: str) -> str:
|
|||
|
||||
|
||||
def fix_jest_mock_paths(test_code: str, test_file_path: Path, source_file_path: Path, tests_root: Path) -> str:
|
||||
"""Fix relative paths in jest.mock() calls to be correct from the test file's location.
|
||||
"""Fix relative paths in jest.mock() and vi.mock() calls to be correct from the test file's location.
|
||||
|
||||
The AI sometimes generates jest.mock() calls with paths relative to the source file
|
||||
The AI sometimes generates mock calls with paths relative to the source file
|
||||
instead of the test file. For example:
|
||||
- Source at `src/queue/queue.ts` imports `../environment` (-> src/environment)
|
||||
- Test at `tests/test.test.ts` generates `jest.mock('../environment')` (-> ./environment, wrong!)
|
||||
- Should generate `jest.mock('../src/environment')`
|
||||
- Test at `tests/test.test.ts` generates `jest.mock('../environment')` or `vi.mock('../environment')` (-> ./environment, wrong!)
|
||||
- Should generate `jest.mock('../src/environment')` or `vi.mock('../src/environment')`
|
||||
|
||||
This function detects relative mock paths and adjusts them based on the test file's
|
||||
location relative to the source file's directory.
|
||||
|
|
@ -1318,8 +1318,8 @@ def fix_jest_mock_paths(test_code: str, test_file_path: Path, source_file_path:
|
|||
test_dir = test_file_path.resolve().parent
|
||||
project_root = tests_root.resolve().parent if tests_root.name == "tests" else tests_root.resolve()
|
||||
|
||||
# Pattern to match jest.mock() or jest.doMock() with relative paths
|
||||
mock_pattern = re.compile(r"(jest\.(?:mock|doMock)\s*\(\s*['\"])(\.\./[^'\"]+|\.\/[^'\"]+)(['\"])")
|
||||
# Pattern to match jest.mock(), jest.doMock(), or vi.mock() with relative paths
|
||||
mock_pattern = re.compile(r"((?:jest|vi)\.(?:mock|doMock)\s*\(\s*['\"])(\.\./[^'\"]+|\.\/[^'\"]+)(['\"])")
|
||||
|
||||
def fix_mock_path(match: re.Match[str]) -> str:
|
||||
original = match.group(0)
|
||||
|
|
@ -1359,7 +1359,7 @@ def fix_jest_mock_paths(test_code: str, test_file_path: Path, source_file_path:
|
|||
if not new_rel_path.startswith("../") and not new_rel_path.startswith("./"):
|
||||
new_rel_path = f"./{new_rel_path}"
|
||||
|
||||
logger.debug(f"Fixed jest.mock path: {rel_path} -> {new_rel_path}")
|
||||
logger.debug(f"Fixed mock path: {rel_path} -> {new_rel_path}")
|
||||
return f"{prefix}{new_rel_path}{suffix}"
|
||||
|
||||
except (ValueError, OSError):
|
||||
|
|
|
|||
|
|
@ -7,6 +7,7 @@ verification and performance benchmarking.
|
|||
from __future__ import annotations
|
||||
|
||||
import os
|
||||
import re
|
||||
import subprocess
|
||||
import time
|
||||
from pathlib import Path
|
||||
|
|
@ -169,7 +170,7 @@ def _is_vitest_workspace(project_root: Path) -> bool:
|
|||
return False
|
||||
|
||||
try:
|
||||
content = vitest_config.read_text()
|
||||
content = vitest_config.read_text(encoding="utf-8")
|
||||
# Check for actual workspace configuration patterns (not just the word "workspace" in comments)
|
||||
# Valid indicators:
|
||||
# - defineWorkspace() function call
|
||||
|
|
|
|||
|
|
@ -34,7 +34,9 @@ def generate_tests(
|
|||
# TODO: Sometimes this recreates the original Class definition. This overrides and messes up the original
|
||||
# class import. Remove the recreation of the class definition
|
||||
start_time = time.perf_counter()
|
||||
test_module_path = Path(module_name_from_file_path(test_path, test_cfg.tests_project_rootdir))
|
||||
# Use traverse_up=True to handle co-located __tests__ directories that may be outside
|
||||
# the configured tests_root (e.g., src/gateway/__tests__/ when tests_root is test/)
|
||||
test_module_path = Path(module_name_from_file_path(test_path, test_cfg.tests_project_rootdir, traverse_up=True))
|
||||
|
||||
# Detect module system via language support (non-None for JS/TS, None for Python)
|
||||
lang_support = current_language_support()
|
||||
|
|
|
|||
61
tests/languages/javascript/test_vitest_setupfiles_fix.py
Normal file
61
tests/languages/javascript/test_vitest_setupfiles_fix.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
from pathlib import Path
|
||||
|
||||
import pytest
|
||||
|
||||
from codeflash.languages.javascript.vitest_runner import _ensure_codeflash_vitest_config
|
||||
|
||||
|
||||
def test_codeflash_vitest_config_overrides_setupfiles(tmp_path: Path) -> None:
|
||||
project_root = tmp_path.resolve()
|
||||
|
||||
# Create a project with setup file
|
||||
(project_root / "test").mkdir()
|
||||
(project_root / "test" / "setup.ts").write_text("// Setup file\n", encoding="utf-8")
|
||||
|
||||
vitest_config = """import { defineConfig } from 'vitest/config';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
setupFiles: ["test/setup.ts"], // Relative path - will cause issues
|
||||
include: ["src/**/*.test.ts"],
|
||||
},
|
||||
});
|
||||
"""
|
||||
(project_root / "vitest.config.ts").write_text(vitest_config, encoding="utf-8")
|
||||
|
||||
codeflash_config_path = _ensure_codeflash_vitest_config(project_root)
|
||||
|
||||
assert codeflash_config_path is not None
|
||||
assert codeflash_config_path.exists()
|
||||
|
||||
config_content = codeflash_config_path.read_text(encoding="utf-8")
|
||||
|
||||
assert "setupFiles" in config_content, (
|
||||
"Generated config must explicitly handle setupFiles to prevent "
|
||||
"relative path resolution issues. Current config:\n" + config_content
|
||||
)
|
||||
assert "setupFiles: []" in config_content or "setupFiles:" in config_content, (
|
||||
"setupFiles must be explicitly set in the merged config"
|
||||
)
|
||||
|
||||
|
||||
def test_codeflash_vitest_config_without_setupfiles(tmp_path: Path) -> None:
|
||||
project_root = tmp_path.resolve()
|
||||
|
||||
vitest_config = """import { defineConfig } from 'vitest/config';
|
||||
|
||||
export default defineConfig({
|
||||
test: {
|
||||
include: ["src/**/*.test.ts"],
|
||||
},
|
||||
});
|
||||
"""
|
||||
(project_root / "vitest.config.ts").write_text(vitest_config, encoding="utf-8")
|
||||
|
||||
codeflash_config_path = _ensure_codeflash_vitest_config(project_root)
|
||||
|
||||
assert codeflash_config_path is not None
|
||||
assert codeflash_config_path.exists()
|
||||
|
||||
config_content = codeflash_config_path.read_text(encoding="utf-8")
|
||||
assert "mergeConfig" in config_content or "defineConfig" in config_content
|
||||
94
tests/test_fix_mock_paths_vitest.py
Normal file
94
tests/test_fix_mock_paths_vitest.py
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
"""Test fix_jest_mock_paths function with vitest mocks."""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from codeflash.languages.javascript.instrument import fix_jest_mock_paths
|
||||
|
||||
|
||||
def test_fix_vitest_mock_paths():
|
||||
"""Test that vi.mock() paths are fixed correctly."""
|
||||
# Simulate source at src/agents/workspace.ts importing from ../routing/session-key
|
||||
# Test at test/test_workspace.test.ts should mock ../src/routing/session-key, not ../routing/session-key
|
||||
|
||||
test_code = """
|
||||
vi.mock('../routing/session-key', () => ({
|
||||
isSubagentSessionKey: vi.fn(),
|
||||
isCronSessionKey: vi.fn(),
|
||||
}));
|
||||
|
||||
import { filterBootstrapFilesForSession } from '../src/agents/workspace.js';
|
||||
"""
|
||||
|
||||
# Create temp directories and files for testing
|
||||
import tempfile
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
project = Path(tmpdir)
|
||||
|
||||
# Create directory structure
|
||||
src = project / "src"
|
||||
src_agents = src / "agents"
|
||||
src_routing = src / "routing"
|
||||
test_dir = project / "test"
|
||||
|
||||
src_agents.mkdir(parents=True)
|
||||
src_routing.mkdir(parents=True)
|
||||
test_dir.mkdir(parents=True)
|
||||
|
||||
# Create files
|
||||
source_file = src_agents / "workspace.ts"
|
||||
source_file.write_text("export function filterBootstrapFilesForSession() {}")
|
||||
|
||||
routing_file = src_routing / "session-key.ts"
|
||||
routing_file.write_text("export function isSubagentSessionKey() {}")
|
||||
|
||||
test_file = test_dir / "test_workspace.test.ts"
|
||||
test_file.write_text(test_code)
|
||||
|
||||
# Fix the paths
|
||||
fixed = fix_jest_mock_paths(test_code, test_file, source_file, test_dir)
|
||||
|
||||
# Should change ../routing/session-key to ../src/routing/session-key
|
||||
assert "../src/routing/session-key" in fixed, f"Expected path to be fixed, got: {fixed}"
|
||||
assert "../routing/session-key" not in fixed or "../src/routing/session-key" in fixed
|
||||
|
||||
|
||||
def test_fix_jest_mock_paths_still_works():
|
||||
"""Test that jest.mock() paths are still fixed correctly."""
|
||||
test_code = """
|
||||
jest.mock('../routing/session-key', () => ({
|
||||
isSubagentSessionKey: jest.fn(),
|
||||
}));
|
||||
"""
|
||||
|
||||
import tempfile
|
||||
|
||||
with tempfile.TemporaryDirectory() as tmpdir:
|
||||
project = Path(tmpdir)
|
||||
src = project / "src"
|
||||
src_agents = src / "agents"
|
||||
src_routing = src / "routing"
|
||||
test_dir = project / "test"
|
||||
|
||||
src_agents.mkdir(parents=True)
|
||||
src_routing.mkdir(parents=True)
|
||||
test_dir.mkdir(parents=True)
|
||||
|
||||
source_file = src_agents / "workspace.ts"
|
||||
source_file.write_text("")
|
||||
|
||||
routing_file = src_routing / "session-key.ts"
|
||||
routing_file.write_text("")
|
||||
|
||||
test_file = test_dir / "test_workspace.test.ts"
|
||||
test_file.write_text(test_code)
|
||||
|
||||
fixed = fix_jest_mock_paths(test_code, test_file, source_file, test_dir)
|
||||
|
||||
assert "../src/routing/session-key" in fixed
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
test_fix_vitest_mock_paths()
|
||||
test_fix_jest_mock_paths_still_works()
|
||||
print("All tests passed!")
|
||||
66
tests/test_js_project_root_per_function.py
Normal file
66
tests/test_js_project_root_per_function.py
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
"""Test that js_project_root is recalculated per function, not cached."""
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
from codeflash.languages.javascript.test_runner import find_node_project_root
|
||||
|
||||
|
||||
def test_find_node_project_root_returns_different_roots_for_different_files(tmp_path: Path) -> None:
|
||||
"""Test that find_node_project_root returns the correct root for each file."""
|
||||
# Create main project structure
|
||||
main_project = (tmp_path / "project").resolve()
|
||||
main_project.mkdir()
|
||||
(main_project / "package.json").write_text("{}", encoding="utf-8")
|
||||
(main_project / "src").mkdir()
|
||||
main_file = (main_project / "src" / "main.ts").resolve()
|
||||
main_file.write_text("// main file", encoding="utf-8")
|
||||
|
||||
# Create extension subdirectory with its own package.json
|
||||
extension_dir = (main_project / "extensions" / "discord").resolve()
|
||||
extension_dir.mkdir(parents=True)
|
||||
(extension_dir / "package.json").write_text("{}", encoding="utf-8")
|
||||
(extension_dir / "src").mkdir()
|
||||
extension_file = (extension_dir / "src" / "accounts.ts").resolve()
|
||||
extension_file.write_text("// extension file", encoding="utf-8")
|
||||
|
||||
# Extension file should return extension directory
|
||||
result1 = find_node_project_root(extension_file)
|
||||
assert result1 == extension_dir, f"Expected {extension_dir}, got {result1}"
|
||||
|
||||
# Main file should return main project directory
|
||||
result2 = find_node_project_root(main_file)
|
||||
assert result2 == main_project, f"Expected {main_project}, got {result2}"
|
||||
|
||||
# Calling again with extension file should still return extension dir
|
||||
result3 = find_node_project_root(extension_file)
|
||||
assert result3 == extension_dir, f"Expected {extension_dir}, got {result3}"
|
||||
|
||||
|
||||
def test_js_project_root_recalculated_per_function(tmp_path: Path) -> None:
|
||||
"""Each function in a monorepo should resolve to its own nearest package.json root."""
|
||||
# Create main project
|
||||
main_project = (tmp_path / "project").resolve()
|
||||
main_project.mkdir()
|
||||
(main_project / "package.json").write_text('{"name": "main"}', encoding="utf-8")
|
||||
(main_project / "src").mkdir()
|
||||
|
||||
# Create extension with its own package.json
|
||||
extension_dir = (main_project / "extensions" / "discord").resolve()
|
||||
extension_dir.mkdir(parents=True)
|
||||
(extension_dir / "package.json").write_text('{"name": "discord-extension"}', encoding="utf-8")
|
||||
(extension_dir / "src").mkdir()
|
||||
|
||||
extension_file = (extension_dir / "src" / "accounts.ts").resolve()
|
||||
extension_file.write_text("export function foo() {}", encoding="utf-8")
|
||||
|
||||
main_file = (main_project / "src" / "commands.ts").resolve()
|
||||
main_file.write_text("export function bar() {}", encoding="utf-8")
|
||||
|
||||
js_project_root_1 = find_node_project_root(extension_file)
|
||||
assert js_project_root_1 == extension_dir
|
||||
|
||||
js_project_root_2 = find_node_project_root(main_file)
|
||||
assert js_project_root_2 == main_project, (
|
||||
f"Expected {main_project}, got {js_project_root_2}. "
|
||||
f"Happens when js_project_root is not recalculated per function."
|
||||
)
|
||||
85
tests/test_module_name_from_file_path.py
Normal file
85
tests/test_module_name_from_file_path.py
Normal file
|
|
@ -0,0 +1,85 @@
|
|||
"""Tests for module_name_from_file_path with co-located test directories."""
|
||||
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
from codeflash.code_utils.code_utils import module_name_from_file_path
|
||||
|
||||
|
||||
class TestModuleNameFromFilePath:
|
||||
"""Test module name resolution for various directory structures."""
|
||||
|
||||
def test_file_inside_project_root(self, tmp_path: Path) -> None:
|
||||
"""Test normal case where file is inside project root."""
|
||||
project_root = tmp_path / "project"
|
||||
project_root.mkdir()
|
||||
|
||||
test_file = project_root / "test" / "test_foo.py"
|
||||
test_file.parent.mkdir()
|
||||
test_file.touch()
|
||||
|
||||
result = module_name_from_file_path(test_file, project_root)
|
||||
assert result == "test.test_foo"
|
||||
|
||||
def test_file_outside_project_root_without_traverse_up(self, tmp_path: Path) -> None:
|
||||
"""Test that file outside project root raises ValueError by default."""
|
||||
project_root = tmp_path / "project" / "test"
|
||||
project_root.mkdir(parents=True)
|
||||
|
||||
# File is in a sibling directory, not under project_root
|
||||
test_file = tmp_path / "project" / "src" / "__tests__" / "test_foo.py"
|
||||
test_file.parent.mkdir(parents=True)
|
||||
test_file.touch()
|
||||
|
||||
with pytest.raises(ValueError, match="is not within the project root"):
|
||||
module_name_from_file_path(test_file, project_root)
|
||||
|
||||
def test_file_outside_project_root_with_traverse_up(self, tmp_path: Path) -> None:
|
||||
"""Test that traverse_up=True handles files outside project root."""
|
||||
project_root = tmp_path / "project" / "test"
|
||||
project_root.mkdir(parents=True)
|
||||
|
||||
# File is in a sibling directory, not under project_root
|
||||
test_file = tmp_path / "project" / "src" / "__tests__" / "codeflash-generated" / "test_foo.py"
|
||||
test_file.parent.mkdir(parents=True)
|
||||
test_file.touch()
|
||||
|
||||
# With traverse_up=True, it should find a common ancestor
|
||||
result = module_name_from_file_path(test_file, project_root, traverse_up=True)
|
||||
|
||||
# Should return a relative path from some ancestor directory
|
||||
assert "test_foo" in result
|
||||
assert not result.startswith(".")
|
||||
|
||||
def test_colocated_test_directory_structure(self, tmp_path: Path) -> None:
|
||||
"""Test real-world scenario with co-located __tests__ directory.
|
||||
|
||||
This reproduces the bug from trace 7b97ddba-6ecd-42fd-b572-d40658746836:
|
||||
- Source: /workspace/target/src/gateway/server/ws-connection/connect-policy.ts
|
||||
- Tests root: /workspace/target/test
|
||||
- Generated test: /workspace/target/src/gateway/server/__tests__/codeflash-generated/test_xxx.test.ts
|
||||
|
||||
Without traverse_up=True, this should fail.
|
||||
"""
|
||||
project_root = tmp_path / "target"
|
||||
project_root.mkdir()
|
||||
|
||||
tests_root = project_root / "test"
|
||||
tests_root.mkdir()
|
||||
|
||||
# Source file location
|
||||
source_file = project_root / "src" / "gateway" / "server" / "ws-connection" / "connect-policy.ts"
|
||||
source_file.parent.mkdir(parents=True)
|
||||
source_file.touch()
|
||||
|
||||
# Generated test in co-located __tests__ directory
|
||||
test_file = project_root / "src" / "gateway" / "server" / "__tests__" / "codeflash-generated" / "test_resolveControlUiAuthPolicy.test.ts"
|
||||
test_file.parent.mkdir(parents=True)
|
||||
test_file.touch()
|
||||
|
||||
# This should fail WITHOUT traverse_up
|
||||
with pytest.raises(ValueError, match="is not within the project root"):
|
||||
module_name_from_file_path(test_file, tests_root)
|
||||
|
||||
# This should succeed WITH traverse_up
|
||||
result = module_name_from_file_path(test_file, tests_root, traverse_up=True)
|
||||
assert "test_resolveControlUiAuthPolicy" in result
|
||||
57
tests/test_optimizer_js_project_root_bug.py
Normal file
57
tests/test_optimizer_js_project_root_bug.py
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
"""Test that test_cfg.js_project_root caching bug is demonstrated and bypassed by the fix."""
|
||||
|
||||
from pathlib import Path
|
||||
from unittest.mock import patch
|
||||
|
||||
from codeflash.languages.javascript.support import JavaScriptSupport
|
||||
from codeflash.verification.verification_utils import TestConfig
|
||||
|
||||
|
||||
@patch("codeflash.languages.javascript.optimizer.verify_js_requirements")
|
||||
def test_js_project_root_cached_in_test_cfg(mock_verify: object, tmp_path: Path) -> None:
|
||||
"""Demonstrates that test_cfg.js_project_root is set once per setup_test_config call.
|
||||
|
||||
This test shows the root cause: test_cfg caches the project root from the first function.
|
||||
The fix bypasses this cache in FunctionOptimizer.get_js_project_root() instead of
|
||||
changing how test_cfg stores the value.
|
||||
"""
|
||||
mock_verify.return_value = [] # type: ignore[attr-defined]
|
||||
|
||||
# Create main project
|
||||
main_project = (tmp_path / "project").resolve()
|
||||
main_project.mkdir()
|
||||
(main_project / "package.json").write_text('{"name": "main"}', encoding="utf-8")
|
||||
(main_project / "src").mkdir()
|
||||
(main_project / "test").mkdir()
|
||||
(main_project / "node_modules").mkdir()
|
||||
|
||||
# Create extension with its own package.json
|
||||
extension_dir = (main_project / "extensions" / "discord").resolve()
|
||||
extension_dir.mkdir(parents=True)
|
||||
(extension_dir / "package.json").write_text('{"name": "discord-extension"}', encoding="utf-8")
|
||||
(extension_dir / "src").mkdir()
|
||||
(extension_dir / "node_modules").mkdir()
|
||||
|
||||
test_cfg = TestConfig(
|
||||
tests_root=main_project / "test",
|
||||
project_root_path=main_project,
|
||||
tests_project_rootdir=main_project / "test",
|
||||
)
|
||||
test_cfg.set_language("javascript")
|
||||
|
||||
js_support = JavaScriptSupport()
|
||||
|
||||
extension_file = (extension_dir / "src" / "accounts.ts").resolve()
|
||||
extension_file.write_text("export function foo() {}", encoding="utf-8")
|
||||
|
||||
success = js_support.setup_test_config(test_cfg, extension_file, current_worktree=None)
|
||||
assert success, "setup_test_config should succeed"
|
||||
# After setup for extension file, js_project_root is the extension directory
|
||||
assert test_cfg.js_project_root == extension_dir
|
||||
|
||||
# test_cfg is NOT re-initialized for subsequent functions — js_project_root stays cached
|
||||
main_file = (main_project / "src" / "commands.ts").resolve()
|
||||
main_file.write_text("export function bar() {}", encoding="utf-8")
|
||||
|
||||
# The cached value is still extension_dir, not main_project — this is the root cause
|
||||
assert test_cfg.js_project_root == extension_dir
|
||||
Loading…
Reference in a new issue