Skip to content

Commit 3948463

Browse files
cameroncookeCodex
andcommitted
fix(ui-automation): Address remaining PR feedback
Tighten UI automation tests and output compaction around the runtime snapshot work. Use valid describe-ui responses in key action tests, cap wait candidate output before it reaches structured responses, and restore explicit envelope coverage for omitted next steps. Document the runtime/session boundary for snapshot refs and the narrow simulator-name default refresh tradeoff so those contracts remain clear. Co-Authored-By: Codex <noreply@example.com>
1 parent c3888f8 commit 3948463

10 files changed

Lines changed: 163 additions & 181 deletions

File tree

src/mcp/tools/ui-automation/__tests__/batch.test.ts

Lines changed: 4 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
import { beforeEach, describe, expect, it, vi } from 'vitest';
22
import * as z from 'zod';
33
import type { UiActionResultDomainResult } from '../../../../types/domain-results.ts';
4-
import type { CommandExecutor } from '../../../../utils/execution/index.ts';
54
import { DebuggerManager } from '../../../../utils/debugger/debugger-manager.ts';
65
import { sessionStore } from '../../../../utils/session-store.ts';
76
import { callHandler, createMockToolHandlerContext } from '../../../../test-utils/test-helpers.ts';
@@ -377,17 +376,12 @@ describe('Batch UI Automation Tool', () => {
377376
recordSnapshot([createNode()]);
378377
const { calls, executor } = createTrackingExecutor();
379378

380-
const { ctx, run } = createMockToolHandlerContext();
381-
await run(() =>
382-
(
383-
handler as unknown as (
384-
args: Record<string, unknown>,
385-
executor: CommandExecutor,
386-
) => Promise<void>
387-
)({ steps: [{ action: 'tap', elementRef: 'e1' }] }, executor),
379+
const result = await runBatch(
380+
{ simulatorId, steps: [{ action: 'tap', elementRef: 'e1' }] },
381+
executor,
388382
);
389383

390-
expect(ctx.structuredOutput?.result.didError).toBe(false);
384+
expect(result.didError).toBe(false);
391385
expect(calls[0]?.command.slice(1)).toEqual([
392386
'batch',
393387
'--step',

src/mcp/tools/ui-automation/__tests__/key_press.test.ts

Lines changed: 13 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,6 @@
11
import { describe, it, expect, beforeEach } from 'vitest';
22
import * as z from 'zod';
3-
import {
4-
createMockCommandResponse,
5-
createMockExecutor,
6-
createNoopExecutor,
7-
mockProcess,
8-
} from '../../../../test-utils/mock-executors.ts';
3+
import { createMockExecutor, createNoopExecutor } from '../../../../test-utils/mock-executors.ts';
94
import { sessionStore } from '../../../../utils/session-store.ts';
105
import { schema, handler, key_pressLogic, createKeyPressExecutor } from '../key_press.ts';
116
import { AXE_NOT_AVAILABLE_MESSAGE } from '../../../../utils/axe-helpers.ts';
@@ -83,19 +78,7 @@ describe('Key Press Tool', () => {
8378

8479
describe('Command Generation', () => {
8580
it('should generate correct axe command for basic key press', async () => {
86-
let capturedCommand: string[] = [];
87-
const trackingExecutor = async (command: string[]) => {
88-
if (command[1] !== 'describe-ui') {
89-
capturedCommand = command;
90-
}
91-
return createMockCommandResponse({
92-
success: true,
93-
output: 'key press completed',
94-
error: undefined,
95-
process: mockProcess,
96-
});
97-
};
98-
81+
const { calls, executor } = createTrackingExecutor();
9982
const mockAxeHelpers = createDefaultMockAxeHelpers();
10083

10184
await runLogic(() =>
@@ -104,12 +87,12 @@ describe('Key Press Tool', () => {
10487
simulatorId: '12345678-1234-4234-8234-123456789012',
10588
keyCode: 40,
10689
},
107-
trackingExecutor,
90+
executor,
10891
mockAxeHelpers,
10992
),
11093
);
11194

112-
expect(capturedCommand).toEqual([
95+
expect(calls.find((call) => call.command[1] !== 'describe-ui')?.command).toEqual([
11396
'/usr/local/bin/axe',
11497
'key',
11598
'40',
@@ -119,19 +102,7 @@ describe('Key Press Tool', () => {
119102
});
120103

121104
it('should generate correct axe command for key press with duration', async () => {
122-
let capturedCommand: string[] = [];
123-
const trackingExecutor = async (command: string[]) => {
124-
if (command[1] !== 'describe-ui') {
125-
capturedCommand = command;
126-
}
127-
return createMockCommandResponse({
128-
success: true,
129-
output: 'key press completed',
130-
error: undefined,
131-
process: mockProcess,
132-
});
133-
};
134-
105+
const { calls, executor } = createTrackingExecutor();
135106
const mockAxeHelpers = createDefaultMockAxeHelpers();
136107

137108
await runLogic(() =>
@@ -141,12 +112,12 @@ describe('Key Press Tool', () => {
141112
keyCode: 42,
142113
duration: 1.5,
143114
},
144-
trackingExecutor,
115+
executor,
145116
mockAxeHelpers,
146117
),
147118
);
148119

149-
expect(capturedCommand).toEqual([
120+
expect(calls.find((call) => call.command[1] !== 'describe-ui')?.command).toEqual([
150121
'/usr/local/bin/axe',
151122
'key',
152123
'42',
@@ -158,19 +129,7 @@ describe('Key Press Tool', () => {
158129
});
159130

160131
it('should generate correct axe command for different key codes', async () => {
161-
let capturedCommand: string[] = [];
162-
const trackingExecutor = async (command: string[]) => {
163-
if (command[1] !== 'describe-ui') {
164-
capturedCommand = command;
165-
}
166-
return createMockCommandResponse({
167-
success: true,
168-
output: 'key press completed',
169-
error: undefined,
170-
process: mockProcess,
171-
});
172-
};
173-
132+
const { calls, executor } = createTrackingExecutor();
174133
const mockAxeHelpers = createDefaultMockAxeHelpers();
175134

176135
await runLogic(() =>
@@ -179,12 +138,12 @@ describe('Key Press Tool', () => {
179138
simulatorId: '12345678-1234-4234-8234-123456789012',
180139
keyCode: 255,
181140
},
182-
trackingExecutor,
141+
executor,
183142
mockAxeHelpers,
184143
),
185144
);
186145

187-
expect(capturedCommand).toEqual([
146+
expect(calls.find((call) => call.command[1] !== 'describe-ui')?.command).toEqual([
188147
'/usr/local/bin/axe',
189148
'key',
190149
'255',
@@ -194,19 +153,7 @@ describe('Key Press Tool', () => {
194153
});
195154

196155
it('should generate correct axe command with bundled axe path', async () => {
197-
let capturedCommand: string[] = [];
198-
const trackingExecutor = async (command: string[]) => {
199-
if (command[1] !== 'describe-ui') {
200-
capturedCommand = command;
201-
}
202-
return createMockCommandResponse({
203-
success: true,
204-
output: 'key press completed',
205-
error: undefined,
206-
process: mockProcess,
207-
});
208-
};
209-
156+
const { calls, executor } = createTrackingExecutor();
210157
const mockAxeHelpers = {
211158
getAxePath: () => '/path/to/bundled/axe',
212159
getBundledAxeEnvironment: () => ({ AXE_PATH: '/some/path' }),
@@ -218,12 +165,12 @@ describe('Key Press Tool', () => {
218165
simulatorId: '12345678-1234-4234-8234-123456789012',
219166
keyCode: 44,
220167
},
221-
trackingExecutor,
168+
executor,
222169
mockAxeHelpers,
223170
),
224171
);
225172

226-
expect(capturedCommand).toEqual([
173+
expect(calls.find((call) => call.command[1] !== 'describe-ui')?.command).toEqual([
227174
'/path/to/bundled/axe',
228175
'key',
229176
'44',

src/mcp/tools/ui-automation/__tests__/key_sequence.test.ts

Lines changed: 13 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,6 @@
11
import { describe, it, expect, beforeEach } from 'vitest';
22
import * as z from 'zod';
3-
import {
4-
createMockExecutor,
5-
createNoopExecutor,
6-
mockProcess,
7-
} from '../../../../test-utils/mock-executors.ts';
3+
import { createMockExecutor, createNoopExecutor } from '../../../../test-utils/mock-executors.ts';
84
import { sessionStore } from '../../../../utils/session-store.ts';
95
import { schema, handler, key_sequenceLogic, createKeySequenceExecutor } from '../key_sequence.ts';
106
import { AXE_NOT_AVAILABLE_MESSAGE } from '../../../../utils/axe-helpers.ts';
@@ -77,19 +73,7 @@ describe('Key Sequence Tool', () => {
7773

7874
describe('Command Generation', () => {
7975
it('should generate correct axe command for basic key sequence', async () => {
80-
let capturedCommand: string[] = [];
81-
const trackingExecutor = async (command: string[]) => {
82-
if (command[1] !== 'describe-ui') {
83-
capturedCommand = command;
84-
}
85-
return {
86-
success: true,
87-
output: 'key sequence completed',
88-
error: undefined,
89-
process: mockProcess,
90-
};
91-
};
92-
76+
const { calls, executor } = createTrackingExecutor();
9377
const mockAxeHelpers = {
9478
getAxePath: () => '/usr/local/bin/axe',
9579
getBundledAxeEnvironment: () => ({}),
@@ -101,12 +85,12 @@ describe('Key Sequence Tool', () => {
10185
simulatorId: '12345678-1234-4234-8234-123456789012',
10286
keyCodes: [40, 42, 44],
10387
},
104-
trackingExecutor,
88+
executor,
10589
mockAxeHelpers,
10690
),
10791
);
10892

109-
expect(capturedCommand).toEqual([
93+
expect(calls.find((call) => call.command[1] !== 'describe-ui')?.command).toEqual([
11094
'/usr/local/bin/axe',
11195
'key-sequence',
11296
'--keycodes',
@@ -117,19 +101,7 @@ describe('Key Sequence Tool', () => {
117101
});
118102

119103
it('should generate correct axe command for key sequence with delay', async () => {
120-
let capturedCommand: string[] = [];
121-
const trackingExecutor = async (command: string[]) => {
122-
if (command[1] !== 'describe-ui') {
123-
capturedCommand = command;
124-
}
125-
return {
126-
success: true,
127-
output: 'key sequence completed',
128-
error: undefined,
129-
process: mockProcess,
130-
};
131-
};
132-
104+
const { calls, executor } = createTrackingExecutor();
133105
const mockAxeHelpers = {
134106
getAxePath: () => '/usr/local/bin/axe',
135107
getBundledAxeEnvironment: () => ({}),
@@ -142,12 +114,12 @@ describe('Key Sequence Tool', () => {
142114
keyCodes: [58, 59, 60],
143115
delay: 0.5,
144116
},
145-
trackingExecutor,
117+
executor,
146118
mockAxeHelpers,
147119
),
148120
);
149121

150-
expect(capturedCommand).toEqual([
122+
expect(calls.find((call) => call.command[1] !== 'describe-ui')?.command).toEqual([
151123
'/usr/local/bin/axe',
152124
'key-sequence',
153125
'--keycodes',
@@ -160,19 +132,7 @@ describe('Key Sequence Tool', () => {
160132
});
161133

162134
it('should generate correct axe command for single key in sequence', async () => {
163-
let capturedCommand: string[] = [];
164-
const trackingExecutor = async (command: string[]) => {
165-
if (command[1] !== 'describe-ui') {
166-
capturedCommand = command;
167-
}
168-
return {
169-
success: true,
170-
output: 'key sequence completed',
171-
error: undefined,
172-
process: mockProcess,
173-
};
174-
};
175-
135+
const { calls, executor } = createTrackingExecutor();
176136
const mockAxeHelpers = {
177137
getAxePath: () => '/usr/local/bin/axe',
178138
getBundledAxeEnvironment: () => ({}),
@@ -184,12 +144,12 @@ describe('Key Sequence Tool', () => {
184144
simulatorId: '12345678-1234-4234-8234-123456789012',
185145
keyCodes: [255],
186146
},
187-
trackingExecutor,
147+
executor,
188148
mockAxeHelpers,
189149
),
190150
);
191151

192-
expect(capturedCommand).toEqual([
152+
expect(calls.find((call) => call.command[1] !== 'describe-ui')?.command).toEqual([
193153
'/usr/local/bin/axe',
194154
'key-sequence',
195155
'--keycodes',
@@ -200,19 +160,7 @@ describe('Key Sequence Tool', () => {
200160
});
201161

202162
it('should generate correct axe command with bundled axe path', async () => {
203-
let capturedCommand: string[] = [];
204-
const trackingExecutor = async (command: string[]) => {
205-
if (command[1] !== 'describe-ui') {
206-
capturedCommand = command;
207-
}
208-
return {
209-
success: true,
210-
output: 'key sequence completed',
211-
error: undefined,
212-
process: mockProcess,
213-
};
214-
};
215-
163+
const { calls, executor } = createTrackingExecutor();
216164
const mockAxeHelpers = {
217165
getAxePath: () => '/path/to/bundled/axe',
218166
getBundledAxeEnvironment: () => ({ AXE_PATH: '/some/path' }),
@@ -225,12 +173,12 @@ describe('Key Sequence Tool', () => {
225173
keyCodes: [0, 1, 2, 3, 4],
226174
delay: 1.0,
227175
},
228-
trackingExecutor,
176+
executor,
229177
mockAxeHelpers,
230178
),
231179
);
232180

233-
expect(capturedCommand).toEqual([
181+
expect(calls.find((call) => call.command[1] !== 'describe-ui')?.command).toEqual([
234182
'/path/to/bundled/axe',
235183
'key-sequence',
236184
'--keycodes',

0 commit comments

Comments
 (0)