Skip to content

Commit 1d6cd20

Browse files
committed
fix: align Maestro test discovery order
1 parent be5f20e commit 1d6cd20

2 files changed

Lines changed: 83 additions & 11 deletions

File tree

src/daemon/handlers/__tests__/session-test-discovery.test.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,3 +84,42 @@ test('discoverReplayTestEntries includes Maestro yaml flows for Maestro test sui
8484
assert.equal(entries[0].title, 'Bottom Tabs - Dynamic');
8585
}
8686
});
87+
88+
test('discoverReplayTestEntries preserves explicit Maestro file order', () => {
89+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-device-test-discovery-maestro-order-'));
90+
const second = path.join(root, '02-second.yaml');
91+
const first = path.join(root, '01-first.yaml');
92+
fs.writeFileSync(first, 'appId: demo\n---\n- launchApp\n');
93+
fs.writeFileSync(second, 'appId: demo\n---\n- launchApp\n');
94+
95+
const entries = discoverReplayTestEntries({
96+
inputs: [second, first],
97+
cwd: root,
98+
replayBackend: 'maestro',
99+
});
100+
101+
assert.deepEqual(
102+
entries.map((entry) => path.basename(entry.path)),
103+
['02-second.yaml', '01-first.yaml'],
104+
);
105+
});
106+
107+
test('discoverReplayTestEntries orders Maestro file inputs before directory flows', () => {
108+
const root = fs.mkdtempSync(path.join(os.tmpdir(), 'agent-device-test-discovery-maestro-files-'));
109+
const suite = path.join(root, 'suite');
110+
fs.mkdirSync(suite);
111+
const explicit = path.join(root, '99-explicit.yaml');
112+
fs.writeFileSync(explicit, 'appId: demo\n---\n- launchApp\n');
113+
fs.writeFileSync(path.join(suite, '01-directory.yaml'), 'appId: demo\n---\n- launchApp\n');
114+
115+
const entries = discoverReplayTestEntries({
116+
inputs: [suite, explicit],
117+
cwd: root,
118+
replayBackend: 'maestro',
119+
});
120+
121+
assert.deepEqual(
122+
entries.map((entry) => path.basename(entry.path)),
123+
['99-explicit.yaml', '01-directory.yaml'],
124+
);
125+
});

src/daemon/handlers/session-test-discovery.ts

Lines changed: 44 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,11 +36,7 @@ export function discoverReplayTestEntries(params: {
3636
const { inputs, cwd, platformFilter, replayBackend } = params;
3737
const extensions = replayTestExtensions(replayBackend);
3838
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));
39+
const filePaths = discoverReplayTestFilePaths(inputs, resolvedCwd, extensions, replayBackend);
4440

4541
const entries: ReplayTestDiscoveryEntry[] = [];
4642
for (const filePath of filePaths) {
@@ -136,24 +132,60 @@ export function resolveReplayTestRetries(
136132
return Math.max(0, Math.min(MAX_REPLAY_TEST_RETRIES, resolved));
137133
}
138134

139-
function expandReplayTestInput(input: string, cwd: string, extensions: Set<string>): string[] {
135+
function discoverReplayTestFilePaths(
136+
inputs: string[],
137+
cwd: string,
138+
extensions: Set<string>,
139+
replayBackend: string | undefined,
140+
): string[] {
141+
if (!isMaestroReplayBackend(replayBackend)) {
142+
return [
143+
...new Set(inputs.flatMap((input) => expandReplayTestInput(input, cwd, extensions).paths)),
144+
]
145+
.map((entry) => path.normalize(entry))
146+
.sort((left, right) => left.localeCompare(right));
147+
}
148+
149+
const files: string[] = [];
150+
const directories: string[] = [];
151+
const globs: string[] = [];
152+
for (const input of inputs) {
153+
const expanded = expandReplayTestInput(input, cwd, extensions);
154+
if (expanded.source === 'directory') {
155+
directories.push(...expanded.paths);
156+
} else if (expanded.source === 'glob') {
157+
globs.push(...expanded.paths);
158+
} else {
159+
files.push(...expanded.paths);
160+
}
161+
}
162+
163+
return [...new Set([...files, ...directories, ...globs].map((entry) => path.normalize(entry)))];
164+
}
165+
166+
function expandReplayTestInput(
167+
input: string,
168+
cwd: string,
169+
extensions: Set<string>,
170+
): { paths: string[]; source: 'directory' | 'file' | 'glob' } {
140171
const expandedInput = SessionStore.expandHome(input, cwd);
141172
if (fs.existsSync(expandedInput)) {
142173
const stat = fs.statSync(expandedInput);
143174
if (stat.isDirectory()) {
144-
return replayTestGlobPatterns(extensions).flatMap((pattern) =>
175+
const paths = replayTestGlobPatterns(extensions).flatMap((pattern) =>
145176
fs
146177
.globSync(pattern, { cwd: expandedInput })
147178
.map((match) => path.join(expandedInput, match)),
148179
);
180+
return { paths, source: 'directory' };
149181
}
150182
if (stat.isFile()) {
151183
if (!extensions.has(path.extname(expandedInput))) {
152184
throw new AppError('INVALID_ARGS', `test does not support this file type: ${input}`);
153185
}
154-
return [expandedInput];
186+
return { paths: [expandedInput], source: 'file' };
155187
}
156-
return [];
188+
return { paths: [], source: 'file' };
157189
}
158190

159191
if (!looksLikeGlob(input) && !looksLikeGlob(expandedInput)) {
@@ -165,14 +197,15 @@ function expandReplayTestInput(input: string, cwd: string, extensions: Set<strin
165197
cwd: path.isAbsolute(expandedInput) ? undefined : cwd,
166198
});
167199

168-
return matches
200+
const paths = matches
169201
.map((match) => (path.isAbsolute(match) ? match : path.resolve(cwd, match)))
170202
.filter((match) => extensions.has(path.extname(match)) && isExistingFile(match));
203+
return { paths, source: 'glob' };
171204
}
172205

173206
function replayTestExtensions(replayBackend: string | undefined): Set<string> {
174207
return isMaestroReplayBackend(replayBackend)
175-
? new Set(['.ad', '.yaml', '.yml'])
208+
? new Set(['.yaml', '.yml', '.ad'])
176209
: new Set(['.ad']);
177210
}
178211

0 commit comments

Comments
 (0)