Skip to content

Commit ee83df8

Browse files
authored
chore: prune redundant tests (#229)
* chore: prune redundant tests * chore: address test review feedback
1 parent b0d598c commit ee83df8

9 files changed

Lines changed: 295 additions & 331 deletions

File tree

package.json

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
"agent-device": "bin/agent-device.mjs"
2121
},
2222
"scripts": {
23-
"lint": "node --eval \"console.log('no lint')\"",
2423
"build": "rslib build",
2524
"clean:daemon": "rm -f ~/.agent-device/daemon.json && rm -f ~/.agent-device/daemon.lock",
2625
"build:node": "pnpm build && pnpm clean:daemon",

src/core/__tests__/capabilities.test.ts

Lines changed: 73 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -40,48 +40,67 @@ const tvOsSimulator: DeviceInfo = {
4040
target: 'tv',
4141
};
4242

43-
test('iOS simulator-only commands reject iOS devices and Android', () => {
44-
for (const cmd of ['alert', 'pinch']) {
45-
assert.equal(isCommandSupportedOnDevice(cmd, iosSimulator), true, `${cmd} on iOS sim`);
46-
assert.equal(isCommandSupportedOnDevice(cmd, iosDevice), false, `${cmd} on iOS device`);
47-
assert.equal(isCommandSupportedOnDevice(cmd, androidDevice), false, `${cmd} on Android`);
48-
}
49-
});
43+
type SupportCheck = {
44+
device: DeviceInfo;
45+
expected: boolean;
46+
label: string;
47+
};
5048

51-
test('simulator-only iOS commands with Android support reject iOS devices', () => {
52-
for (const cmd of ['settings', 'push', 'clipboard']) {
53-
assert.equal(isCommandSupportedOnDevice(cmd, iosSimulator), true, `${cmd} on iOS sim`);
54-
assert.equal(isCommandSupportedOnDevice(cmd, iosDevice), false, `${cmd} on iOS device`);
55-
assert.equal(isCommandSupportedOnDevice(cmd, androidDevice), true, `${cmd} on Android`);
49+
function assertCommandSupport(commands: string[], checks: SupportCheck[]): void {
50+
for (const command of commands) {
51+
for (const check of checks) {
52+
assert.equal(
53+
isCommandSupportedOnDevice(command, check.device),
54+
check.expected,
55+
`${command} ${check.label}`,
56+
);
57+
}
5658
}
57-
});
59+
}
5860

59-
test('keyboard command is Android-only', () => {
60-
assert.equal(isCommandSupportedOnDevice('keyboard', iosSimulator), false, 'keyboard on iOS sim');
61-
assert.equal(isCommandSupportedOnDevice('keyboard', iosDevice), false, 'keyboard on iOS device');
62-
assert.equal(isCommandSupportedOnDevice('keyboard', androidDevice), true, 'keyboard on Android');
63-
});
64-
65-
test('swipe supports iOS simulator, iOS device, and Android', () => {
66-
assert.equal(isCommandSupportedOnDevice('swipe', iosSimulator), true, 'swipe on iOS sim');
67-
assert.equal(isCommandSupportedOnDevice('swipe', iosDevice), true, 'swipe on iOS device');
68-
assert.equal(isCommandSupportedOnDevice('swipe', androidDevice), true, 'swipe on Android');
69-
});
61+
test('device capability matrix stays consistent across shared command groups', () => {
62+
const scenarios: Array<{ commands: string[]; checks: SupportCheck[] }> = [
63+
{
64+
commands: ['alert', 'pinch'],
65+
checks: [
66+
{ device: iosSimulator, expected: true, label: 'on iOS sim' },
67+
{ device: iosDevice, expected: false, label: 'on iOS device' },
68+
{ device: androidDevice, expected: false, label: 'on Android' },
69+
],
70+
},
71+
{
72+
commands: ['settings', 'push', 'clipboard'],
73+
checks: [
74+
{ device: iosSimulator, expected: true, label: 'on iOS sim' },
75+
{ device: iosDevice, expected: false, label: 'on iOS device' },
76+
{ device: androidDevice, expected: true, label: 'on Android' },
77+
],
78+
},
79+
{
80+
commands: ['keyboard'],
81+
checks: [
82+
{ device: iosSimulator, expected: false, label: 'on iOS sim' },
83+
{ device: iosDevice, expected: false, label: 'on iOS device' },
84+
{ device: androidDevice, expected: true, label: 'on Android' },
85+
],
86+
},
87+
{
88+
commands: ['swipe', 'reinstall', 'install'],
89+
checks: [
90+
{ device: iosSimulator, expected: true, label: 'on iOS sim' },
91+
{ device: iosDevice, expected: true, label: 'on iOS device' },
92+
{ device: androidDevice, expected: true, label: 'on Android' },
93+
],
94+
},
95+
];
7096

71-
test('reinstall supports iOS simulator, iOS device, and Android', () => {
72-
assert.equal(isCommandSupportedOnDevice('reinstall', iosSimulator), true, 'reinstall on iOS sim');
73-
assert.equal(isCommandSupportedOnDevice('reinstall', iosDevice), true, 'reinstall on iOS device');
74-
assert.equal(isCommandSupportedOnDevice('reinstall', androidDevice), true, 'reinstall on Android');
75-
});
76-
77-
test('install supports iOS simulator, iOS device, and Android', () => {
78-
assert.equal(isCommandSupportedOnDevice('install', iosSimulator), true, 'install on iOS sim');
79-
assert.equal(isCommandSupportedOnDevice('install', iosDevice), true, 'install on iOS device');
80-
assert.equal(isCommandSupportedOnDevice('install', androidDevice), true, 'install on Android');
97+
for (const scenario of scenarios) {
98+
assertCommandSupport(scenario.commands, scenario.checks);
99+
}
81100
});
82101

83102
test('core commands support iOS simulator, iOS device, and Android', () => {
84-
for (const cmd of [
103+
assertCommandSupport([
85104
'app-switcher',
86105
'apps',
87106
'back',
@@ -108,21 +127,22 @@ test('core commands support iOS simulator, iOS device, and Android', () => {
108127
'trigger-app-event',
109128
'type',
110129
'wait',
111-
]) {
112-
assert.equal(isCommandSupportedOnDevice(cmd, iosSimulator), true, `${cmd} on iOS sim`);
113-
assert.equal(isCommandSupportedOnDevice(cmd, iosDevice), true, `${cmd} on iOS device`);
114-
assert.equal(isCommandSupportedOnDevice(cmd, androidDevice), true, `${cmd} on Android`);
115-
}
130+
], [
131+
{ device: iosSimulator, expected: true, label: 'on iOS sim' },
132+
{ device: iosDevice, expected: true, label: 'on iOS device' },
133+
{ device: androidDevice, expected: true, label: 'on Android' },
134+
]);
116135
});
117136

118137
test('Android TV uses Android capabilities for core commands', () => {
119-
for (const cmd of ['open', 'apps', 'snapshot', 'press', 'swipe', 'back', 'home', 'scroll']) {
120-
assert.equal(isCommandSupportedOnDevice(cmd, androidTvDevice), true, `${cmd} on Android TV`);
121-
}
138+
assertCommandSupport(
139+
['open', 'apps', 'snapshot', 'press', 'swipe', 'back', 'home', 'scroll'],
140+
[{ device: androidTvDevice, expected: true, label: 'on Android TV' }],
141+
);
122142
});
123143

124144
test('tvOS follows iOS capability matrix by device kind', () => {
125-
for (const cmd of [
145+
assertCommandSupport([
126146
'open',
127147
'close',
128148
'apps',
@@ -131,15 +151,15 @@ test('tvOS follows iOS capability matrix by device kind', () => {
131151
'logs',
132152
'reinstall',
133153
'boot',
134-
]) {
135-
assert.equal(isCommandSupportedOnDevice(cmd, tvOsSimulator), true, `${cmd} on tvOS`);
136-
}
137-
for (const cmd of ['snapshot', 'wait', 'press', 'get', 'fill', 'scroll', 'back', 'home', 'app-switcher', 'record']) {
138-
assert.equal(isCommandSupportedOnDevice(cmd, tvOsSimulator), true, `${cmd} on tvOS`);
139-
}
140-
for (const cmd of ['pinch', 'push', 'settings', 'alert']) {
141-
assert.equal(isCommandSupportedOnDevice(cmd, tvOsSimulator), true, `${cmd} on tvOS simulator`);
142-
}
154+
], [{ device: tvOsSimulator, expected: true, label: 'on tvOS' }]);
155+
assertCommandSupport(
156+
['snapshot', 'wait', 'press', 'get', 'fill', 'scroll', 'back', 'home', 'app-switcher', 'record'],
157+
[{ device: tvOsSimulator, expected: true, label: 'on tvOS' }],
158+
);
159+
assertCommandSupport(
160+
['pinch', 'push', 'settings', 'alert'],
161+
[{ device: tvOsSimulator, expected: true, label: 'on tvOS simulator' }],
162+
);
143163
assert.equal(isCommandSupportedOnDevice('keyboard', tvOsSimulator), false, 'keyboard on tvOS simulator');
144164
});
145165

src/daemon/handlers/__tests__/find.test.ts

Lines changed: 97 additions & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import test from 'node:test';
1+
import test, { type TestContext } from 'node:test';
22
import assert from 'node:assert/strict';
33
import fs from 'node:fs';
44
import os from 'node:os';
@@ -37,6 +37,44 @@ const INCREMENT_NODE = {
3737
depth: 0,
3838
};
3939

40+
async function runFindClickScenario(options: {
41+
positionals: string[];
42+
nodes: Array<Record<string, unknown>>;
43+
invoke?: (req: DaemonRequest) => Promise<Record<string, unknown>>;
44+
}): Promise<{ response: NonNullable<Awaited<ReturnType<typeof handleFindCommands>>>; invokeCalls: DaemonRequest[] }> {
45+
const sessionStore = makeSessionStore();
46+
const sessionName = 'default';
47+
sessionStore.set(sessionName, makeSession(sessionName));
48+
49+
const invokeCalls: DaemonRequest[] = [];
50+
const response = await handleFindCommands({
51+
req: {
52+
token: 't',
53+
session: sessionName,
54+
command: 'find',
55+
positionals: options.positionals,
56+
flags: {},
57+
},
58+
sessionName,
59+
logPath: '/tmp/test.log',
60+
sessionStore,
61+
invoke: async (req) => {
62+
invokeCalls.push(req);
63+
const data = options.invoke ? await options.invoke(req) : {};
64+
return { ok: true, data };
65+
},
66+
dispatch: async (_device, command) => {
67+
if (command === 'snapshot') {
68+
return { nodes: options.nodes };
69+
}
70+
return {};
71+
},
72+
});
73+
74+
assert.ok(response, 'expected a response');
75+
return { response, invokeCalls };
76+
}
77+
4078
test('parseFindArgs defaults to click with any locator', () => {
4179
const parsed = parseFindArgs(['Login']);
4280
assert.equal(parsed.locator, 'any');
@@ -132,63 +170,7 @@ test('parseFindArgs with bare locator yields empty query', () => {
132170
assert.equal(parsed.action, 'click');
133171
});
134172

135-
test('handleFindCommands click returns deterministic matched-target metadata', async () => {
136-
const sessionStore = makeSessionStore();
137-
const sessionName = 'default';
138-
sessionStore.set(sessionName, makeSession(sessionName));
139-
140-
const invokeCalls: DaemonRequest[] = [];
141-
const response = await handleFindCommands({
142-
req: {
143-
token: 't',
144-
session: sessionName,
145-
command: 'find',
146-
positionals: ['Increment', 'click'],
147-
flags: {},
148-
},
149-
sessionName,
150-
logPath: '/tmp/test.log',
151-
sessionStore,
152-
invoke: async (req) => {
153-
invokeCalls.push(req);
154-
// Simulate runner returning non-deterministic platform data that should not bleed through
155-
return { ok: true, data: { platformSpecificRef: 'XCUIElementTypeApplication', x: 0, y: 0 } };
156-
},
157-
dispatch: async (_device, command) => {
158-
if (command === 'snapshot') {
159-
return { nodes: [INCREMENT_NODE] };
160-
}
161-
return {};
162-
},
163-
});
164-
165-
assert.ok(response, 'expected a response');
166-
assert.ok(response.ok, 'expected success');
167-
const data = response.data as Record<string, unknown>;
168-
169-
// Deterministic matched-target metadata
170-
assert.equal(data.ref, '@e1', 'ref must match the resolved snapshot node');
171-
assert.equal(data.locator, 'any', 'locator must reflect the find strategy');
172-
assert.equal(data.query, 'Increment', 'query must reflect the search term');
173-
assert.equal(data.x, 100, 'x must be derived from the matched node rect center');
174-
assert.equal(data.y, 50, 'y must be derived from the matched node rect center');
175-
176-
// Strict key set — no platform-specific fields may leak through
177-
assert.deepEqual(Object.keys(data).sort(), ['locator', 'query', 'ref', 'x', 'y']);
178-
179-
// invoke was called with the resolved ref
180-
assert.equal(invokeCalls.length, 1);
181-
assert.equal(invokeCalls[0].positionals?.[0], '@e1');
182-
});
183-
184-
test('handleFindCommands click response contains exactly the deterministic key set (fallback: no rect on resolved node)', async () => {
185-
const sessionStore = makeSessionStore();
186-
const sessionName = 'default';
187-
sessionStore.set(sessionName, makeSession(sessionName));
188-
189-
// Parent is hittable but has no rect — resolving through it loses coordinates.
190-
// Child has a rect (satisfies requireRect) but is not hittable, so findNearestHittableAncestor
191-
// walks up to the parent, which has no rect → fallback path: x/y are absent from response.
173+
test('handleFindCommands click returns deterministic metadata across locator variants', async (t: TestContext) => {
192174
const hittableParentNoRect = { index: 0, type: 'View', hittable: true, depth: 0 };
193175
const nonHittableChildWithRect = {
194176
index: 1,
@@ -200,55 +182,67 @@ test('handleFindCommands click response contains exactly the deterministic key s
200182
parentIndex: 0,
201183
};
202184

203-
const response = await handleFindCommands({
204-
req: {
205-
token: 't',
206-
session: sessionName,
207-
command: 'find',
185+
const scenarios: Array<{
186+
label: string;
187+
positionals: string[];
188+
nodes: Array<Record<string, unknown>>;
189+
invoke?: (req: DaemonRequest) => Promise<Record<string, unknown>>;
190+
expectedKeys: string[];
191+
expectedLocator: string;
192+
expectedQuery: string;
193+
expectedCoordinates?: { x: number; y: number };
194+
}> = [
195+
{
196+
label: 'returns deterministic matched-target metadata',
208197
positionals: ['Increment', 'click'],
209-
flags: {},
198+
nodes: [INCREMENT_NODE],
199+
invoke: async () => ({ platformSpecificRef: 'XCUIElementTypeApplication', x: 0, y: 0 }),
200+
expectedKeys: ['locator', 'query', 'ref', 'x', 'y'],
201+
expectedLocator: 'any',
202+
expectedQuery: 'Increment',
203+
expectedCoordinates: { x: 100, y: 50 },
210204
},
211-
sessionName,
212-
logPath: '/tmp/test.log',
213-
sessionStore,
214-
invoke: async () => ({ ok: true, data: { platformSpecificRef: 'XCUIElementTypeView' } }),
215-
dispatch: async (_device, command) => {
216-
if (command === 'snapshot') return { nodes: [hittableParentNoRect, nonHittableChildWithRect] };
217-
return {};
205+
{
206+
label: 'falls back to deterministic key set when resolved node has no rect',
207+
positionals: ['Increment', 'click'],
208+
nodes: [hittableParentNoRect, nonHittableChildWithRect],
209+
invoke: async () => ({ platformSpecificRef: 'XCUIElementTypeView' }),
210+
expectedKeys: ['locator', 'query', 'ref'],
211+
expectedLocator: 'any',
212+
expectedQuery: 'Increment',
218213
},
219-
});
220-
221-
assert.ok(response?.ok);
222-
const data = response!.data as Record<string, unknown>;
223-
assert.deepEqual(Object.keys(data).sort(), ['locator', 'query', 'ref']);
224-
});
225-
226-
test('handleFindCommands click with explicit label locator returns locator in metadata', async () => {
227-
const sessionStore = makeSessionStore();
228-
const sessionName = 'default';
229-
sessionStore.set(sessionName, makeSession(sessionName));
230-
231-
const response = await handleFindCommands({
232-
req: {
233-
token: 't',
234-
session: sessionName,
235-
command: 'find',
214+
{
215+
label: 'keeps explicit label locator in metadata',
236216
positionals: ['label', 'Increment', 'click'],
237-
flags: {},
217+
nodes: [INCREMENT_NODE],
218+
expectedKeys: ['locator', 'query', 'ref', 'x', 'y'],
219+
expectedLocator: 'label',
220+
expectedQuery: 'Increment',
221+
expectedCoordinates: { x: 100, y: 50 },
238222
},
239-
sessionName,
240-
logPath: '/tmp/test.log',
241-
sessionStore,
242-
invoke: async () => ({ ok: true, data: {} }),
243-
dispatch: async (_device, command) => {
244-
if (command === 'snapshot') return { nodes: [INCREMENT_NODE] };
245-
return {};
246-
},
247-
});
223+
];
224+
225+
for (const scenario of scenarios) {
226+
await t.test(scenario.label, async () => {
227+
const { response, invokeCalls } = await runFindClickScenario(scenario);
228+
assert.ok(response.ok, 'expected success');
229+
230+
const data = response.data as Record<string, unknown>;
231+
assert.deepEqual(Object.keys(data).sort(), scenario.expectedKeys);
232+
assert.equal(data.ref, '@e1', 'ref must match the resolved snapshot node');
233+
assert.equal(data.locator, scenario.expectedLocator);
234+
assert.equal(data.query, scenario.expectedQuery);
235+
236+
if (scenario.expectedCoordinates) {
237+
assert.equal(data.x, scenario.expectedCoordinates.x);
238+
assert.equal(data.y, scenario.expectedCoordinates.y);
239+
} else {
240+
assert.equal(Object.hasOwn(data, 'x'), false);
241+
assert.equal(Object.hasOwn(data, 'y'), false);
242+
}
248243

249-
assert.ok(response?.ok);
250-
const data = response!.data as Record<string, unknown>;
251-
assert.deepEqual(Object.keys(data).sort(), ['locator', 'query', 'ref', 'x', 'y']);
252-
assert.equal(data.locator, 'label');
253-
assert.equal(data.query, 'Increment');
244+
assert.equal(invokeCalls.length, 1);
245+
assert.equal(invokeCalls[0].positionals?.[0], '@e1');
246+
});
247+
}
254248
});

0 commit comments

Comments
 (0)