diff --git a/test/vitest-scoped-config.test.ts b/test/vitest-scoped-config.test.ts index 2de4962e799..e091a9461d0 100644 --- a/test/vitest-scoped-config.test.ts +++ b/test/vitest-scoped-config.test.ts @@ -131,6 +131,17 @@ describe("createScopedVitestConfig", () => { expect(config.test?.include).toEqual(["slack/**/*.test.*"]); }); + it("keeps broad scoped cli directory filters aligned with repo-root include patterns", () => { + const config = createScopedVitestConfig([BUNDLED_PLUGIN_TEST_GLOB], { + argv: ["vitest", "run", "extensions/speech-core"], + dir: "extensions", + env: {}, + passWithNoTests: true, + }); + + expect(config.test?.include).toEqual(["speech-core/**/*.test.*"]); + }); + it("relativizes scoped include and exclude patterns to the configured dir", () => { const config = createScopedVitestConfig([BUNDLED_PLUGIN_TEST_GLOB], { dir: "extensions", diff --git a/test/vitest/vitest.pattern-file.ts b/test/vitest/vitest.pattern-file.ts index b883f221c92..93bd456181c 100644 --- a/test/vitest/vitest.pattern-file.ts +++ b/test/vitest/vitest.pattern-file.ts @@ -26,6 +26,31 @@ function looksLikeCliIncludePattern(value: string): boolean { ); } +function literalPrefixForGlobPattern(value: string): string { + const normalized = value.replaceAll("\\", "/"); + const globIndex = normalized.search(/[?*[\]{}]/u); + if (globIndex === -1) { + return normalized; + } + const slashIndex = normalized.lastIndexOf("/", globIndex); + return slashIndex === -1 ? "" : normalized.slice(0, slashIndex + 1); +} + +function patternsCouldOverlap(value: string, pattern: string): boolean { + if (path.matchesGlob(value, pattern) || path.matchesGlob(pattern, value)) { + return true; + } + + const valuePrefix = literalPrefixForGlobPattern(value); + const patternPrefix = literalPrefixForGlobPattern(pattern); + return ( + patternPrefix === "" || + valuePrefix === "" || + valuePrefix.startsWith(patternPrefix) || + patternPrefix.startsWith(valuePrefix) + ); +} + export function loadPatternListFile(filePath: string, label: string): string[] { const parsed = JSON.parse(fs.readFileSync(filePath, "utf8")) as unknown; if (!Array.isArray(parsed)) { @@ -99,9 +124,7 @@ export function narrowIncludePatternsForCli( } const matched = cliPatterns.filter((value) => - includePatterns.some( - (pattern) => path.matchesGlob(value, pattern) || path.matchesGlob(pattern, value), - ), + includePatterns.some((pattern) => patternsCouldOverlap(value, pattern)), ); return [...new Set(matched)];