diff --git a/compiler/packages/snap/src/fixture-utils.ts b/compiler/packages/snap/src/fixture-utils.ts index 931b4f29352ad..ebf6a34e1dbca 100644 --- a/compiler/packages/snap/src/fixture-utils.ts +++ b/compiler/packages/snap/src/fixture-utils.ts @@ -44,6 +44,21 @@ function stripExtension(filename: string, extensions: Array): string { return filename; } +/** + * Strip all extensions from a filename + * e.g., "foo.expect.md" -> "foo" + */ +function stripAllExtensions(filename: string): string { + let result = filename; + while (true) { + const extension = path.extname(result); + if (extension === '') { + return result; + } + result = path.basename(result, extension); + } +} + export async function readTestFilter(): Promise { if (!(await exists(FILTER_PATH))) { throw new Error(`testfilter file not found at \`${FILTER_PATH}\``); @@ -111,11 +126,25 @@ async function readInputFixtures( } else { inputFiles = ( await Promise.all( - filter.paths.map(pattern => - glob.glob(`${pattern}{${INPUT_EXTENSIONS.join(',')}}`, { + filter.paths.map(pattern => { + // If the pattern already has an extension other than .expect.md, + // search for the pattern directly. Otherwise, search for the + // pattern with the expected input extensions added. + // Eg + // `alias-while` => search for `alias-while{.js,.jsx,.ts,.tsx}` + // `alias-while.js` => search as-is + // `alias-while.expect.md` => search for `alias-while{.js,.jsx,.ts,.tsx}` + const basename = path.basename(pattern); + const basenameWithoutExt = stripAllExtensions(basename); + const hasExtension = basename !== basenameWithoutExt; + const globPattern = + hasExtension && !pattern.endsWith(SNAPSHOT_EXTENSION) + ? pattern + : `${basenameWithoutExt}{${INPUT_EXTENSIONS.join(',')}}`; + return glob.glob(globPattern, { cwd: rootDir, - }), - ), + }); + }), ) ).flat(); } @@ -150,11 +179,13 @@ async function readOutputFixtures( } else { outputFiles = ( await Promise.all( - filter.paths.map(pattern => - glob.glob(`${pattern}${SNAPSHOT_EXTENSION}`, { + filter.paths.map(pattern => { + // Strip all extensions and find matching .expect.md files + const basenameWithoutExt = stripAllExtensions(pattern); + return glob.glob(`${basenameWithoutExt}${SNAPSHOT_EXTENSION}`, { cwd: rootDir, - }), - ), + }); + }), ) ).flat(); } diff --git a/compiler/packages/snap/src/runner.ts b/compiler/packages/snap/src/runner.ts index d46a18712e883..92a0a0f82eec9 100644 --- a/compiler/packages/snap/src/runner.ts +++ b/compiler/packages/snap/src/runner.ts @@ -35,6 +35,7 @@ type RunnerOptions = { watch: boolean; filter: boolean; update: boolean; + pattern?: string; }; const opts: RunnerOptions = yargs @@ -62,9 +63,15 @@ const opts: RunnerOptions = yargs 'Only run fixtures which match the contents of testfilter.txt', ) .default('filter', false) + .string('pattern') + .alias('p', 'pattern') + .describe( + 'pattern', + 'Optional glob pattern to filter fixtures (e.g., "error.*", "use-memo")', + ) .help('help') .strict() - .parseSync(hideBin(process.argv)); + .parseSync(hideBin(process.argv)) as RunnerOptions; /** * Do a test run and return the test results @@ -171,7 +178,13 @@ export async function main(opts: RunnerOptions): Promise { worker.getStderr().pipe(process.stderr); worker.getStdout().pipe(process.stdout); - if (opts.watch) { + // If pattern is provided, force watch mode off and use pattern filter + const shouldWatch = opts.watch && opts.pattern == null; + if (opts.watch && opts.pattern != null) { + console.warn('NOTE: --watch is ignored when a --pattern is supplied'); + } + + if (shouldWatch) { makeWatchRunner(state => onChange(worker, state), opts.filter); if (opts.filter) { /** @@ -216,7 +229,18 @@ export async function main(opts: RunnerOptions): Promise { try { execSync('yarn build', {cwd: PROJECT_ROOT}); console.log('Built compiler successfully with tsup'); - const testFilter = opts.filter ? await readTestFilter() : null; + + // Determine which filter to use + let testFilter: TestFilter | null = null; + if (opts.pattern) { + testFilter = { + debug: true, + paths: [opts.pattern], + }; + } else if (opts.filter) { + testFilter = await readTestFilter(); + } + const results = await runFixtures(worker, testFilter, 0); if (opts.update) { update(results);