@@ -792,7 +792,7 @@ def validate_and_fix_import_style(test_code: str, source_file_path: Path, functi
792792 Fixed test code with correct import style.
793793
794794 """
795- from codeflash .languages .treesitter_utils import get_analyzer_for_file
795+ from codeflash .languages .javascript . treesitter import get_analyzer_for_file
796796
797797 # Read source file to determine export style
798798 try :
@@ -901,6 +901,115 @@ def is_relevant_import(module_path: str) -> bool:
901901 return test_code
902902
903903
904+ def fix_import_path_for_test_location (
905+ test_code : str , source_file_path : Path , test_file_path : Path , module_root : Path
906+ ) -> str :
907+ """Fix import paths in generated test code to be relative to test file location.
908+
909+ The AI may generate tests with import paths that are relative to the module root
910+ (e.g., 'apps/web/app/file') instead of relative to where the test file is located
911+ (e.g., '../../app/file'). This function fixes such imports.
912+
913+ Args:
914+ test_code: The generated test code.
915+ source_file_path: Absolute path to the source file being tested.
916+ test_file_path: Absolute path to where the test file will be written.
917+ module_root: Root directory of the module/project.
918+
919+ Returns:
920+ Test code with corrected import paths.
921+
922+ """
923+ import os
924+
925+ # Calculate the correct relative import path from test file to source file
926+ test_dir = test_file_path .parent
927+ try :
928+ correct_rel_path = os .path .relpath (source_file_path , test_dir )
929+ correct_rel_path = correct_rel_path .replace ("\\ " , "/" )
930+ # Remove file extension for JS/TS imports
931+ for ext in [".tsx" , ".ts" , ".jsx" , ".js" , ".mjs" , ".cjs" ]:
932+ if correct_rel_path .endswith (ext ):
933+ correct_rel_path = correct_rel_path [: - len (ext )]
934+ break
935+ # Ensure it starts with ./ or ../
936+ if not correct_rel_path .startswith ("." ):
937+ correct_rel_path = "./" + correct_rel_path
938+ except ValueError :
939+ # Can't compute relative path (different drives on Windows)
940+ return test_code
941+
942+ # Try to compute what incorrect path the AI might have generated
943+ # The AI often uses module_root-relative paths like 'apps/web/app/...'
944+ try :
945+ source_rel_to_module = os .path .relpath (source_file_path , module_root )
946+ source_rel_to_module = source_rel_to_module .replace ("\\ " , "/" )
947+ # Remove extension
948+ for ext in [".tsx" , ".ts" , ".jsx" , ".js" , ".mjs" , ".cjs" ]:
949+ if source_rel_to_module .endswith (ext ):
950+ source_rel_to_module = source_rel_to_module [: - len (ext )]
951+ break
952+ except ValueError :
953+ return test_code
954+
955+ # Also check for project root-relative paths (including module_root in path)
956+ try :
957+ project_root = module_root .parent if module_root .name in ["src" , "lib" , "app" , "web" , "apps" ] else module_root
958+ source_rel_to_project = os .path .relpath (source_file_path , project_root )
959+ source_rel_to_project = source_rel_to_project .replace ("\\ " , "/" )
960+ for ext in [".tsx" , ".ts" , ".jsx" , ".js" , ".mjs" , ".cjs" ]:
961+ if source_rel_to_project .endswith (ext ):
962+ source_rel_to_project = source_rel_to_project [: - len (ext )]
963+ break
964+ except ValueError :
965+ source_rel_to_project = None
966+
967+ # Source file name (for matching module paths that end with the file name)
968+ source_name = source_file_path .stem
969+
970+ # Patterns to find import statements
971+ # ESM: import { func } from 'path' or import func from 'path'
972+ esm_import_pattern = re .compile (r"(import\s+(?:{[^}]+}|\w+)\s+from\s+['\"])([^'\"]+)(['\"])" )
973+ # CommonJS: const { func } = require('path') or const func = require('path')
974+ cjs_require_pattern = re .compile (
975+ r"((?:const|let|var)\s+(?:{[^}]+}|\w+)\s*=\s*require\s*\(\s*['\"])([^'\"]+)(['\"])"
976+ )
977+
978+ def should_fix_path (import_path : str ) -> bool :
979+ """Check if this import path looks like it should point to our source file."""
980+ # Skip relative imports that already look correct
981+ if import_path .startswith (("./" , "../" )):
982+ return False
983+ # Skip package imports (no path separators or start with @)
984+ if "/" not in import_path and "\\ " not in import_path :
985+ return False
986+ if import_path .startswith ("@" ) and "/" in import_path :
987+ # Could be an alias like @/utils - skip these
988+ return False
989+ # Check if it looks like it points to our source file
990+ if import_path == source_rel_to_module :
991+ return True
992+ if source_rel_to_project and import_path == source_rel_to_project :
993+ return True
994+ if import_path .endswith ((source_name , "/" + source_name )):
995+ return True
996+ return False
997+
998+ def fix_import (match : re .Match [str ]) -> str :
999+ """Replace incorrect import path with correct relative path."""
1000+ prefix = match .group (1 )
1001+ import_path = match .group (2 )
1002+ suffix = match .group (3 )
1003+
1004+ if should_fix_path (import_path ):
1005+ logger .debug (f"Fixing import path: { import_path } -> { correct_rel_path } " )
1006+ return f"{ prefix } { correct_rel_path } { suffix } "
1007+ return match .group (0 )
1008+
1009+ test_code = esm_import_pattern .sub (fix_import , test_code )
1010+ return cjs_require_pattern .sub (fix_import , test_code )
1011+
1012+
9041013def get_instrumented_test_path (original_path : Path , mode : str ) -> Path :
9051014 """Generate path for instrumented test file.
9061015
0 commit comments