Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 24 additions & 3 deletions codeflash/languages/javascript/vitest_runner.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from __future__ import annotations

import os
import re
import subprocess
import time
from pathlib import Path
Expand Down Expand Up @@ -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

Expand Down Expand Up @@ -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: [],
}},
}});
"""
Expand Down
61 changes: 61 additions & 0 deletions tests/languages/javascript/test_vitest_setupfiles_fix.py
Original file line number Diff line number Diff line change
@@ -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
Loading