Skip to content

Commit fd891c9

Browse files
Saga4claude
andcommitted
fix: handle multi-project Jest configs for generated tests
Rocket.Chat uses jest.config.ts with a projects: [...] field containing restrictive testMatch patterns that reject generated test files. Detects multi-project configs and creates a flat single-project config so generated tests can run without matching the project's patterns. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent d96c2d8 commit fd891c9

1 file changed

Lines changed: 81 additions & 1 deletion

File tree

codeflash/languages/javascript/test_runner.py

Lines changed: 81 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,12 +333,84 @@ def _create_codeflash_jest_config(
333333
return None
334334

335335

336+
def _is_multi_project_jest_config(config_path: Path) -> bool:
337+
"""Check if a Jest config file uses a multi-project setup (projects: [...]).
338+
339+
Multi-project Jest configs restrict test matching to each project's testMatch patterns,
340+
which prevents codeflash-generated tests from being discovered since they use a
341+
different naming convention (test_*.test.ts vs *.spec.ts).
342+
"""
343+
if config_path is None or not config_path.exists():
344+
return False
345+
try:
346+
content = config_path.read_text(encoding="utf-8")
347+
# Look for "projects:" or "projects =" in the config — both TS and JS forms
348+
import re
349+
350+
return bool(re.search(r"\bprojects\s*[=:]", content))
351+
except Exception:
352+
return False
353+
354+
355+
def _create_flat_jest_config_for_generated_tests(project_root: Path, original_config: Path) -> Path | None:
356+
"""Create a simple single-project Jest config for running codeflash-generated tests.
357+
358+
When a project uses a multi-project Jest config (projects: [...]), each project has its own
359+
testMatch/testPathPattern. Generated tests (test_*.test.ts) don't match these patterns.
360+
This function creates a flat config that inherits transform/preset settings but uses
361+
a broad testMatch so generated tests can be discovered.
362+
"""
363+
is_esm = _is_esm_project(project_root)
364+
config_ext = ".cjs" if is_esm else ".js"
365+
codeflash_config_path = original_config.parent / f"jest.codeflash.config{config_ext}"
366+
367+
# Check if it already exists
368+
if codeflash_config_path.exists():
369+
return codeflash_config_path
370+
alt_ext = ".js" if is_esm else ".cjs"
371+
alt_path = codeflash_config_path.with_suffix(alt_ext)
372+
if alt_path.exists():
373+
return alt_path
374+
375+
has_ts_jest = _has_ts_jest_dependency(project_root)
376+
377+
if has_ts_jest:
378+
transform_block = """
379+
transform: {
380+
'^.+\\\\.(ts|tsx)$': ['ts-jest', { isolatedModules: true }],
381+
'^.+\\\\.js$': ['ts-jest', { isolatedModules: true }],
382+
},"""
383+
else:
384+
transform_block = ""
385+
386+
# Create a flat single-project config (no 'projects' array) with broad testMatch
387+
jest_config_content = f"""// Auto-generated by codeflash — flat config for generated test files
388+
// This replaces the multi-project config so codeflash-generated tests can be discovered
389+
module.exports = {{
390+
rootDir: '{project_root.as_posix()}',
391+
testEnvironment: 'node',
392+
testMatch: ['**/*.test.ts', '**/*.test.js', '**/*.test.tsx', '**/*.test.jsx', '**/*.spec.ts', '**/*.spec.js'],
393+
testPathIgnorePatterns: ['/node_modules/', '/dist/'],{transform_block}
394+
moduleFileExtensions: ['ts', 'tsx', 'js', 'jsx', 'json', 'node'],
395+
}};
396+
"""
397+
try:
398+
codeflash_config_path.write_text(jest_config_content)
399+
_created_config_files.add(codeflash_config_path)
400+
logger.info(f"Created flat Jest config for generated tests: {codeflash_config_path}")
401+
return codeflash_config_path
402+
except Exception as e:
403+
logger.warning(f"Failed to create flat Jest config: {e}")
404+
return None
405+
406+
336407
def _get_jest_config_for_project(project_root: Path) -> Path | None:
337408
"""Get the appropriate Jest config for the project.
338409
339410
If the project uses bundler moduleResolution, creates and returns a
340411
codeflash-compatible Jest config. Otherwise, returns the project's
341-
existing Jest config.
412+
existing Jest config. For multi-project Jest configs, creates a flat
413+
single-project config so codeflash-generated tests can be discovered.
342414
343415
Args:
344416
project_root: Root of the project.
@@ -360,6 +432,14 @@ def _get_jest_config_for_project(project_root: Path) -> Path | None:
360432
if codeflash_jest_config:
361433
return codeflash_jest_config
362434

435+
# Handle multi-project Jest configs (projects: [...]) — these restrict testMatch
436+
# per-project and prevent generated tests from being discovered
437+
if _is_multi_project_jest_config(original_jest_config):
438+
logger.info("Detected multi-project Jest config — creating flat config for generated tests")
439+
flat_config = _create_flat_jest_config_for_generated_tests(project_root, original_jest_config)
440+
if flat_config:
441+
return flat_config
442+
363443
return original_jest_config
364444

365445

0 commit comments

Comments
 (0)