diff --git a/codeflash/languages/javascript/vitest_runner.py b/codeflash/languages/javascript/vitest_runner.py index 7c5e11c46..021da6e5c 100644 --- a/codeflash/languages/javascript/vitest_runner.py +++ b/codeflash/languages/javascript/vitest_runner.py @@ -170,8 +170,24 @@ def _is_vitest_workspace(project_root: Path) -> bool: try: content = vitest_config.read_text() - # Check for workspace indicators - return "workspace" in content.lower() or "defineWorkspace" in content + # Check for actual workspace configuration patterns (not just the word "workspace" in comments) + # Valid indicators: + # - defineWorkspace() function call + # - workspace: [ array config + # - separate vitest.workspace.ts/js file + import re + # Match defineWorkspace calls or workspace: property assignments + workspace_pattern = re.compile( + r'(?:^|[^a-zA-Z_])defineWorkspace\s*\(|' # defineWorkspace( function call + r'(?:^|[^a-zA-Z_])workspace\s*:\s*\[', # workspace: [ array + re.MULTILINE + ) + if workspace_pattern.search(content): + return True + # Also check for separate workspace config file + if (project_root / "vitest.workspace.ts").exists() or (project_root / "vitest.workspace.js").exists(): + return True + return False except Exception: return False @@ -238,6 +254,11 @@ def _ensure_codeflash_vitest_config(project_root: Path) -> Path | None: include: ['**/*.test.ts', '**/*.test.js', '**/*.test.tsx', '**/*.test.jsx'], // Use forks pool so timing markers from process.stdout.write flow to parent stdout pool: 'forks', + // Disable setupFiles to prevent relative path resolution issues in nested directories. + // Project setupFiles often use relative paths (e.g., "test/setup.ts") which resolve + // incorrectly when tests are in subdirectories (e.g., extensions/discord/test/). + // Codeflash-generated tests are self-contained and don't require project setup files. + setupFiles: [], }}, }}); """ diff --git a/tests/languages/javascript/test_vitest_setupfiles_fix.py b/tests/languages/javascript/test_vitest_setupfiles_fix.py new file mode 100644 index 000000000..14349d4c3 --- /dev/null +++ b/tests/languages/javascript/test_vitest_setupfiles_fix.py @@ -0,0 +1,97 @@ +"""Test that Codeflash Vitest config properly handles setupFiles from project config. + +This test verifies that when creating a custom Vitest config, setupFiles paths +are converted to absolute paths or cleared to prevent resolution issues in nested directories. +""" + +from pathlib import Path +import tempfile +import pytest + + +def test_codeflash_vitest_config_overrides_setupfiles(): + """Test that generated config overrides setupFiles to prevent path resolution issues. + + When a project has setupFiles with relative paths, and Codeflash generates tests + for functions in nested directories, those relative paths will resolve incorrectly. + + The fix: Convert setupFiles paths to absolute, or disable them for generated tests. + """ + from codeflash.languages.javascript.vitest_runner import _ensure_codeflash_vitest_config + + with tempfile.TemporaryDirectory() as tmpdir: + project_root = Path(tmpdir) + + # Create a project with setup file + (project_root / "test").mkdir() + setup_file = project_root / "test" / "setup.ts" + setup_file.write_text("// Setup file\n") + + # Create vitest config with relative setupFiles path + 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) + + # Call the function to create Codeflash config + codeflash_config_path = _ensure_codeflash_vitest_config(project_root) + + # Verify the config was created + assert codeflash_config_path is not None + assert codeflash_config_path.exists() + + # Read the generated config + config_content = codeflash_config_path.read_text() + + # The config should either: + # 1. Set setupFiles to an empty array (disable setup files for generated tests) + # 2. OR convert the path to absolute using project root resolution + + # Check that setupFiles is mentioned and handled in the merge + assert "setupFiles" in config_content, ( + "Generated config must explicitly handle setupFiles to prevent " + "relative path resolution issues. Current config:\n" + config_content + ) + + # The config should set setupFiles to [] or to absolute paths + # This prevents the relative path from being resolved incorrectly + 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(): + """Test that configs without setupFiles still work correctly.""" + from codeflash.languages.javascript.vitest_runner import _ensure_codeflash_vitest_config + + with tempfile.TemporaryDirectory() as tmpdir: + project_root = Path(tmpdir) + + # Create vitest config WITHOUT setupFiles + vitest_config = """import { defineConfig } from 'vitest/config'; + +export default defineConfig({ + test: { + include: ["src/**/*.test.ts"], + }, +}); +""" + (project_root / "vitest.config.ts").write_text(vitest_config) + + # Call the function to create Codeflash config + codeflash_config_path = _ensure_codeflash_vitest_config(project_root) + + # Verify the config was created + assert codeflash_config_path is not None + assert codeflash_config_path.exists() + + # Config should be created successfully + config_content = codeflash_config_path.read_text() + assert "mergeConfig" in config_content or "defineConfig" in config_content