@@ -12,7 +12,7 @@ import * as readline from 'readline';
1212import ts from 'typescript' ;
1313import yargs from 'yargs' ;
1414import { hideBin } from 'yargs/helpers' ;
15- import { FILTER_PATH , PROJECT_ROOT } from './constants' ;
15+ import { FILTER_PATH , FIXTURES_PATH , PROJECT_ROOT } from './constants' ;
1616import { TestFilter , getFixtures , readTestFilter } from './fixture-utils' ;
1717import { TestResult , TestResults , report , update } from './reporter' ;
1818import {
@@ -23,6 +23,7 @@ import {
2323} from './runner-watch' ;
2424import * as runnerWorker from './runner-worker' ;
2525import { execSync } from 'child_process' ;
26+ import * as glob from 'glob' ;
2627
2728const WORKER_PATH = require . resolve ( './runner-worker.js' ) ;
2829const NUM_WORKERS = cpus ( ) . length - 1 ;
@@ -35,9 +36,17 @@ type RunnerOptions = {
3536 watch : boolean ;
3637 filter : boolean ;
3738 update : boolean ;
39+ pattern ?: string ;
3840} ;
3941
4042const opts : RunnerOptions = yargs
43+ . command ( '$0 [pattern]' , 'Run snapshot tests' , yargs => {
44+ yargs . positional ( 'pattern' , {
45+ type : 'string' ,
46+ describe :
47+ 'Optional glob pattern to filter fixtures (e.g., "error.*", "use-memo")' ,
48+ } ) ;
49+ } )
4150 . boolean ( 'sync' )
4251 . describe (
4352 'sync' ,
@@ -66,6 +75,54 @@ const opts: RunnerOptions = yargs
6675 . strict ( )
6776 . parseSync ( hideBin ( process . argv ) ) ;
6877
78+ /**
79+ * Create a TestFilter from a glob pattern
80+ */
81+ async function createPatternFilter ( pattern : string ) : Promise < TestFilter > {
82+ // The pattern works against the base fixture path (without extensions)
83+ // We need to append extensions to find the actual files, similar to how
84+ // readInputFixtures works in fixture-utils.ts
85+ const INPUT_EXTENSIONS = [
86+ '.js' ,
87+ '.cjs' ,
88+ '.mjs' ,
89+ '.ts' ,
90+ '.cts' ,
91+ '.mts' ,
92+ '.jsx' ,
93+ '.tsx' ,
94+ ] ;
95+ const SNAPSHOT_EXTENSION = '.expect.md' ;
96+
97+ // Try to match both input files and snapshot files
98+ const [ inputMatches , snapshotMatches ] = await Promise . all ( [
99+ glob . glob ( `${ pattern } {${ INPUT_EXTENSIONS . join ( ',' ) } }` , {
100+ cwd : FIXTURES_PATH ,
101+ } ) ,
102+ glob . glob ( `${ pattern } ${ SNAPSHOT_EXTENSION } ` , { cwd : FIXTURES_PATH } ) ,
103+ ] ) ;
104+
105+ // Remove file extensions to get the base paths
106+ const allMatches = [ ...inputMatches , ...snapshotMatches ] ;
107+ const paths = allMatches . map ( ( match : string ) => {
108+ // Remove common test file extensions
109+ return match
110+ . replace ( / \. ( j s | j s x | t s | t s x | m j s | c j s | m t s | c t s ) $ / , '' )
111+ . replace ( / \. e x p e c t \. m d $ / , '' ) ;
112+ } ) ;
113+
114+ // Deduplicate paths
115+ const uniquePaths = Array . from ( new Set ( paths ) ) as string [ ] ;
116+
117+ // Enable debug if there's only one unique match
118+ const debug = uniquePaths . length === 1 ;
119+
120+ return {
121+ debug,
122+ paths : uniquePaths ,
123+ } ;
124+ }
125+
69126/**
70127 * Do a test run and return the test results
71128 */
@@ -171,7 +228,10 @@ export async function main(opts: RunnerOptions): Promise<void> {
171228 worker . getStderr ( ) . pipe ( process . stderr ) ;
172229 worker . getStdout ( ) . pipe ( process . stdout ) ;
173230
174- if ( opts . watch ) {
231+ // If pattern is provided, force watch mode off and use pattern filter
232+ const shouldWatch = opts . pattern ? false : opts . watch ;
233+
234+ if ( shouldWatch ) {
175235 makeWatchRunner ( state => onChange ( worker , state ) , opts . filter ) ;
176236 if ( opts . filter ) {
177237 /**
@@ -216,7 +276,15 @@ export async function main(opts: RunnerOptions): Promise<void> {
216276 try {
217277 execSync ( 'yarn build' , { cwd : PROJECT_ROOT } ) ;
218278 console . log ( 'Built compiler successfully with tsup' ) ;
219- const testFilter = opts . filter ? await readTestFilter ( ) : null ;
279+
280+ // Determine which filter to use
281+ let testFilter : TestFilter | null = null ;
282+ if ( opts . pattern ) {
283+ testFilter = await createPatternFilter ( opts . pattern ) ;
284+ } else if ( opts . filter ) {
285+ testFilter = await readTestFilter ( ) ;
286+ }
287+
220288 const results = await runFixtures ( worker , testFilter , 0 ) ;
221289 if ( opts . update ) {
222290 update ( results ) ;
0 commit comments