From 0116a1f9e6559e281ae058f4b9c1ca7169b39f91 Mon Sep 17 00:00:00 2001 From: mohammed ahmed Date: Fri, 3 Apr 2026 20:06:27 +0000 Subject: [PATCH 1/2] Fix Vitest setupFiles path resolution and workspace detection **Problem:** 1. Vitest tests were failing with 'Cannot find module .../test/setup.ts' when testing functions in nested directories (e.g., extensions/discord/). 2. Root cause had two parts: - _is_vitest_workspace() was doing substring search for 'workspace', matching it even in comments, causing false positives - Custom vitest config wasn't overriding setupFiles, leaving relative paths from original config that resolved incorrectly **Solution:** 1. Improved workspace detection (vitest_runner.py:172-191): - Use regex to match actual workspace config patterns - Match defineWorkspace( function calls - Match workspace: [ property assignments - Ignore 'workspace' in comments 2. Override setupFiles in custom config (vitest_runner.py:235-242): - Set setupFiles: [] to disable project setup files - Prevents relative path resolution issues - Safe since Codeflash tests are self-contained **Testing:** Added test_vitest_setupfiles_fix.py with 2 test cases: - Verifies setupFiles is overridden in generated config - Verifies configs without setupFiles still work **Trace ID:** 161e21be-9306-4a4d-a9dc-978f65a1af7a Co-Authored-By: Claude Sonnet 4.5 --- .../languages/javascript/vitest_runner.py | 25 ++++- .../javascript/test_vitest_setupfiles_fix.py | 97 +++++++++++++++++++ 2 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 tests/languages/javascript/test_vitest_setupfiles_fix.py 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 From 9d22f43216b706456a2fef4d3223cc5fcbf9b7aa Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 3 Apr 2026 20:11:05 +0000 Subject: [PATCH 2/2] style: fix linting issues in vitest setupFiles PR - Move `import re` to module-level (was inside function body) - Add encoding="utf-8" to read_text() call - Fix tests: use tmp_path fixture, add -> None return types, add encoding args Co-authored-by: mohammed ahmed --- .../languages/javascript/vitest_runner.py | 10 +- .../javascript/test_vitest_setupfiles_fix.py | 94 ++++++------------- 2 files changed, 34 insertions(+), 70 deletions(-) diff --git a/codeflash/languages/javascript/vitest_runner.py b/codeflash/languages/javascript/vitest_runner.py index 021da6e5c..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,18 +170,17 @@ 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 # - 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 + 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 diff --git a/tests/languages/javascript/test_vitest_setupfiles_fix.py b/tests/languages/javascript/test_vitest_setupfiles_fix.py index 14349d4c3..73ade492e 100644 --- a/tests/languages/javascript/test_vitest_setupfiles_fix.py +++ b/tests/languages/javascript/test_vitest_setupfiles_fix.py @@ -1,34 +1,18 @@ -"""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. +import pytest - When a project has setupFiles with relative paths, and Codeflash generates tests - for functions in nested directories, those relative paths will resolve incorrectly. +from codeflash.languages.javascript.vitest_runner import _ensure_codeflash_vitest_config - 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) +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() - setup_file = project_root / "test" / "setup.ts" - setup_file.write_text("// Setup file\n") + # Create a project with setup file + (project_root / "test").mkdir() + (project_root / "test" / "setup.ts").write_text("// Setup file\n", encoding="utf-8") - # Create vitest config with relative setupFiles path - vitest_config = """import { defineConfig } from 'vitest/config'; + vitest_config = """import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { @@ -37,45 +21,28 @@ def test_codeflash_vitest_config_overrides_setupfiles(): }, }); """ - (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() + (project_root / "vitest.config.ts").write_text(vitest_config, encoding="utf-8") - # 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 + codeflash_config_path = _ensure_codeflash_vitest_config(project_root) - # 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 - ) + assert codeflash_config_path is not None + assert codeflash_config_path.exists() - # 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" - ) + 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(): - """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) +def test_codeflash_vitest_config_without_setupfiles(tmp_path: Path) -> None: + project_root = tmp_path.resolve() - # Create vitest config WITHOUT setupFiles - vitest_config = """import { defineConfig } from 'vitest/config'; + vitest_config = """import { defineConfig } from 'vitest/config'; export default defineConfig({ test: { @@ -83,15 +50,12 @@ def test_codeflash_vitest_config_without_setupfiles(): }, }); """ - (project_root / "vitest.config.ts").write_text(vitest_config) + (project_root / "vitest.config.ts").write_text(vitest_config, encoding="utf-8") - # Call the function to create Codeflash config - codeflash_config_path = _ensure_codeflash_vitest_config(project_root) + 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() + 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 + config_content = codeflash_config_path.read_text(encoding="utf-8") + assert "mergeConfig" in config_content or "defineConfig" in config_content