Skip to content

Commit 0252ea1

Browse files
fix(check): exclude test-runner files from app compatibility scans (#2596)
* fix(check): exclude test-runner files from app compatibility scans vinext check scans test modules and test-runner configuration as though they are bundled into the migrated application. Apps using CommonJS globals only in Vitest files therefore receive unsupported migration issues even when the vinext build succeeds. Separate the application compatibility candidate set from the general recursive file finder. Exclude test and spec modules plus conventional Jest, Playwright, and Vitest config files, while keeping ordinary runtime config modules visible to import and convention checks. * ci: rerun performance benchmarks --------- Co-authored-by: James Anderson <james@eli.cx>
1 parent c6f2a87 commit 0252ea1

2 files changed

Lines changed: 54 additions & 2 deletions

File tree

packages/vinext/src/check.ts

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,20 @@ function findSourceFiles(
378378
return results;
379379
}
380380

381+
/**
382+
* Find files that can contribute to the application compatibility surface.
383+
* Test modules and test-runner configuration are executed by their own runners
384+
* rather than bundled into the vinext application, so reporting their imports
385+
* or CJS globals as migration blockers produces false positives.
386+
*/
387+
function findRuntimeSourceFiles(root: string): string[] {
388+
return findSourceFiles(root).filter((file) => {
389+
const basename = path.basename(file);
390+
const isTestRunnerConfig = /^(?:jest|playwright|vitest)\.config\.[cm]?[jt]sx?$/.test(basename);
391+
return !/\.(?:test|spec)\.[cm]?[jt]sx?$/.test(basename) && !isTestRunnerConfig;
392+
});
393+
}
394+
381395
function isIdentStart(c: string): boolean {
382396
return (c >= "a" && c <= "z") || (c >= "A" && c <= "Z") || c === "_" || c === "$";
383397
}
@@ -610,7 +624,7 @@ export function hasFreeCjsGlobal(content: string): boolean {
610624
* Scan source files for `import ... from 'next/...'` statements.
611625
*/
612626
export function scanImports(root: string): CheckItem[] {
613-
const files = findSourceFiles(root);
627+
const files = findRuntimeSourceFiles(root);
614628
const importUsage = new Map<string, string[]>();
615629

616630
const importRegex = /(?:import\s+(?:[\w{},\s*]+\s+from\s+)?|require\s*\()['"]([^'"]+)['"]\)?/g;
@@ -1078,7 +1092,7 @@ export function checkConventions(root: string): CheckItem[] {
10781092
// For __dirname/__filename we use hasFreeCjsGlobal(), a single-pass scanner that
10791093
// skips string literals, template literals, and comments before testing for the
10801094
// identifier, so tokens inside those contexts are never matched.
1081-
const allSourceFiles = findSourceFiles(root);
1095+
const allSourceFiles = findRuntimeSourceFiles(root);
10821096
const viewTransitionRegex = /import\s+\{[^}]*\bViewTransition\b[^}]*\}\s+from\s+['"]react['"]/;
10831097
const viewTransitionFiles: string[] = [];
10841098
const cjsGlobalFiles: string[] = [];

tests/check.test.ts

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -216,6 +216,17 @@ describe("scanImports", () => {
216216
expect(items[0].name).toBe("next/image");
217217
});
218218

219+
it("ignores imports used only by test modules and tool config files", () => {
220+
writeFile("app/page.test.tsx", `import { useAmp } from "next/amp";`);
221+
writeFile("vitest.config.ts", `import { useAmp } from "next/amp";`);
222+
writeFile("site.config.ts", `import { useAmp } from "next/amp";`);
223+
writeFile("app/page.tsx", `import Link from "next/link";`);
224+
225+
const items = scanImports(tmpDir);
226+
227+
expect(items.map((item) => item.name)).toEqual(["next/amp", "next/link"]);
228+
});
229+
219230
it("deduplicates files using the same import", () => {
220231
writeFile(
221232
"app/page.tsx",
@@ -1226,6 +1237,33 @@ describe("checkConventions", () => {
12261237
expect(cjs?.files).toContain("lib/db.ts");
12271238
});
12281239

1240+
it("ignores CJS globals in test modules and tool config files", () => {
1241+
writeFile(
1242+
"src/app/mobile-layout-alignment.test.ts",
1243+
`const css = readFileSync(resolve(__dirname, "film.module.css"), "utf-8");`,
1244+
);
1245+
writeFile("vitest.config.ts", `export default { root: path.resolve(__dirname, "./src") };`);
1246+
writeFile("app/page.tsx", `export default function Home() { return <div/>; }`);
1247+
1248+
const items = checkConventions(tmpDir);
1249+
const cjs = items.find((i) => i.name.includes("__dirname"));
1250+
1251+
expect(cjs).toBeUndefined();
1252+
});
1253+
1254+
it("still reports CJS globals in runtime source alongside excluded files", () => {
1255+
writeFile("lib/db.ts", `const dir = path.join(__dirname, "data");`);
1256+
writeFile("site.config.ts", `const root = path.join(__dirname, "content");`);
1257+
writeFile("lib/db.spec.ts", `const fixture = path.join(__dirname, "fixtures");`);
1258+
writeFile("vitest.config.ts", `export default { root: path.resolve(__dirname, "./src") };`);
1259+
writeFile("app/page.tsx", `export default function Home() { return <div/>; }`);
1260+
1261+
const items = checkConventions(tmpDir);
1262+
const cjs = items.find((i) => i.name.includes("__dirname"));
1263+
1264+
expect(cjs?.files).toEqual(["lib/db.ts", "site.config.ts"]);
1265+
});
1266+
12291267
it("detects __filename usage", () => {
12301268
writeFile("lib/logger.ts", `const file = __filename;`);
12311269
writeFile("app/page.tsx", `export default function Home() { return <div/>; }`);

0 commit comments

Comments
 (0)