diff --git a/codeflash/languages/javascript/vitest_runner.py b/codeflash/languages/javascript/vitest_runner.py index 7c5e11c46..313c9cd86 100644 --- a/codeflash/languages/javascript/vitest_runner.py +++ b/codeflash/languages/javascript/vitest_runner.py @@ -7,6 +7,7 @@ from __future__ import annotations import os +import re import subprocess import time from pathlib import Path @@ -169,9 +170,24 @@ def _is_vitest_workspace(project_root: Path) -> bool: return False try: - content = vitest_config.read_text() - # Check for workspace indicators - return "workspace" in content.lower() or "defineWorkspace" in content + 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 + # - workspace: [ array config + # - separate vitest.workspace.ts/js file + # 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..73ade492e --- /dev/null +++ b/tests/languages/javascript/test_vitest_setupfiles_fix.py @@ -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