@@ -27,6 +27,8 @@ export type ReplayTestDiscoveryEntry =
2727
2828export type ReplayTestRunEntry = Extract < ReplayTestDiscoveryEntry , { kind : 'run' } > ;
2929
30+ type ReplayTestInputSource = 'directory' | 'file' | 'glob' ;
31+
3032export function discoverReplayTestEntries ( params : {
3133 inputs : string [ ] ;
3234 cwd ?: string ;
@@ -36,11 +38,7 @@ export function discoverReplayTestEntries(params: {
3638 const { inputs, cwd, platformFilter, replayBackend } = params ;
3739 const extensions = replayTestExtensions ( replayBackend ) ;
3840 const resolvedCwd = cwd ?? process . cwd ( ) ;
39- const filePaths = [
40- ...new Set ( inputs . flatMap ( ( input ) => expandReplayTestInput ( input , resolvedCwd , extensions ) ) ) ,
41- ]
42- . map ( ( entry ) => path . normalize ( entry ) )
43- . sort ( ( left , right ) => left . localeCompare ( right ) ) ;
41+ const filePaths = discoverReplayTestFilePaths ( inputs , resolvedCwd , extensions , replayBackend ) ;
4442
4543 const entries : ReplayTestDiscoveryEntry [ ] = [ ] ;
4644 for ( const filePath of filePaths ) {
@@ -136,24 +134,57 @@ export function resolveReplayTestRetries(
136134 return Math . max ( 0 , Math . min ( MAX_REPLAY_TEST_RETRIES , resolved ) ) ;
137135}
138136
139- function expandReplayTestInput ( input : string , cwd : string , extensions : Set < string > ) : string [ ] {
137+ function discoverReplayTestFilePaths (
138+ inputs : string [ ] ,
139+ cwd : string ,
140+ extensions : Set < string > ,
141+ replayBackend : string | undefined ,
142+ ) : string [ ] {
143+ if ( ! isMaestroReplayBackend ( replayBackend ) ) {
144+ return [
145+ ...new Set ( inputs . flatMap ( ( input ) => expandReplayTestInput ( input , cwd , extensions ) . paths ) ) ,
146+ ]
147+ . map ( ( entry ) => path . normalize ( entry ) )
148+ . sort ( ( left , right ) => left . localeCompare ( right ) ) ;
149+ }
150+
151+ const files : string [ ] = [ ] ;
152+ const expandedGroups : string [ ] [ ] = [ ] ;
153+ for ( const input of inputs ) {
154+ const expanded = expandReplayTestInput ( input , cwd , extensions ) ;
155+ if ( expanded . source === 'file' ) {
156+ files . push ( ...expanded . paths ) ;
157+ } else {
158+ expandedGroups . push ( sortMaestroExpandedReplayTestPaths ( expanded . paths ) ) ;
159+ }
160+ }
161+
162+ return uniqueNormalizedPaths ( [ ...files , ...expandedGroups . flat ( ) ] ) ;
163+ }
164+
165+ function expandReplayTestInput (
166+ input : string ,
167+ cwd : string ,
168+ extensions : Set < string > ,
169+ ) : { paths : string [ ] ; source : ReplayTestInputSource } {
140170 const expandedInput = SessionStore . expandHome ( input , cwd ) ;
141171 if ( fs . existsSync ( expandedInput ) ) {
142172 const stat = fs . statSync ( expandedInput ) ;
143173 if ( stat . isDirectory ( ) ) {
144- return replayTestGlobPatterns ( extensions ) . flatMap ( ( pattern ) =>
174+ const paths = replayTestGlobPatterns ( extensions ) . flatMap ( ( pattern ) =>
145175 fs
146176 . globSync ( pattern , { cwd : expandedInput } )
147177 . map ( ( match ) => path . join ( expandedInput , match ) ) ,
148178 ) ;
179+ return { paths, source : 'directory' } ;
149180 }
150181 if ( stat . isFile ( ) ) {
151182 if ( ! extensions . has ( path . extname ( expandedInput ) ) ) {
152183 throw new AppError ( 'INVALID_ARGS' , `test does not support this file type: ${ input } ` ) ;
153184 }
154- return [ expandedInput ] ;
185+ return { paths : [ expandedInput ] , source : 'file' } ;
155186 }
156- return [ ] ;
187+ return { paths : [ ] , source : 'file' } ;
157188 }
158189
159190 if ( ! looksLikeGlob ( input ) && ! looksLikeGlob ( expandedInput ) ) {
@@ -165,21 +196,43 @@ function expandReplayTestInput(input: string, cwd: string, extensions: Set<strin
165196 cwd : path . isAbsolute ( expandedInput ) ? undefined : cwd ,
166197 } ) ;
167198
168- return matches
199+ const paths = matches
169200 . map ( ( match ) => ( path . isAbsolute ( match ) ? match : path . resolve ( cwd , match ) ) )
170201 . filter ( ( match ) => extensions . has ( path . extname ( match ) ) && isExistingFile ( match ) ) ;
202+ return { paths, source : 'glob' } ;
171203}
172204
173205function replayTestExtensions ( replayBackend : string | undefined ) : Set < string > {
174206 return isMaestroReplayBackend ( replayBackend )
175- ? new Set ( [ '.ad ' , '.yaml ' , '.yml ' ] )
207+ ? new Set ( [ '.yaml ' , '.yml ' , '.ad ' ] )
176208 : new Set ( [ '.ad' ] ) ;
177209}
178210
179211function replayTestGlobPatterns ( extensions : Set < string > ) : string [ ] {
180212 return [ ...extensions ] . map ( ( extension ) => `**/*${ extension } ` ) ;
181213}
182214
215+ function sortMaestroExpandedReplayTestPaths ( paths : string [ ] ) : string [ ] {
216+ return paths . map ( ( entry ) => path . normalize ( entry ) ) . sort ( compareMaestroReplayTestPath ) ;
217+ }
218+
219+ function compareMaestroReplayTestPath ( left : string , right : string ) : number {
220+ const leftRank = maestroReplayTestExtensionRank ( left ) ;
221+ const rightRank = maestroReplayTestExtensionRank ( right ) ;
222+ if ( leftRank !== rightRank ) {
223+ return leftRank - rightRank ;
224+ }
225+ return left . localeCompare ( right ) ;
226+ }
227+
228+ function maestroReplayTestExtensionRank ( filePath : string ) : number {
229+ return path . extname ( filePath ) === '.ad' ? 1 : 0 ;
230+ }
231+
232+ function uniqueNormalizedPaths ( paths : string [ ] ) : string [ ] {
233+ return [ ...new Set ( paths . map ( ( entry ) => path . normalize ( entry ) ) ) ] ;
234+ }
235+
183236function isMaestroReplayBackend ( replayBackend : string | undefined ) : boolean {
184237 return replayBackend === 'maestro' ;
185238}
0 commit comments