Skip to content

Commit 713a2dc

Browse files
cameroncookeclaude
andcommitted
ref: Remove text fallback from simulator listing and simplify snapshot tests
Drop the text-based simctl parsing fallback in list_sims, relying solely on JSON output. Simplify snapshot tests to use real harness invocation instead of importing internal modules directly. Replace the mock MCP test harness with a real stdio MCP client. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 14915c1 commit 713a2dc

File tree

12 files changed

+130
-570
lines changed

12 files changed

+130
-570
lines changed

src/mcp/resources/__tests__/simulators.test.ts

Lines changed: 8 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,7 @@
11
import { describe, it, expect } from 'vitest';
22

33
import { simulatorsResourceLogic } from '../simulators.ts';
4-
import {
5-
createMockCommandResponse,
6-
createMockExecutor,
7-
} from '../../../test-utils/mock-executors.ts';
4+
import { createMockExecutor } from '../../../test-utils/mock-executors.ts';
85

96
describe('simulators resource', () => {
107
describe('Handler Functionality', () => {
@@ -48,34 +45,17 @@ describe('simulators resource', () => {
4845
expect(result.contents[0].text).toContain('Command failed');
4946
});
5047

51-
it('should handle JSON parsing errors and fall back to text parsing', async () => {
52-
const mockTextOutput = `== Devices ==
53-
-- iOS 17.0 --
54-
iPhone 15 (test-uuid-123) (Shutdown)`;
55-
56-
const mockExecutor = async (command: string[]) => {
57-
if (command.includes('--json')) {
58-
return createMockCommandResponse({
59-
success: true,
60-
output: 'invalid json',
61-
error: undefined,
62-
});
63-
}
64-
65-
return createMockCommandResponse({
66-
success: true,
67-
output: mockTextOutput,
68-
error: undefined,
69-
});
70-
};
48+
it('should handle JSON parsing errors', async () => {
49+
const mockExecutor = createMockExecutor({
50+
success: true,
51+
output: 'invalid json',
52+
error: undefined,
53+
});
7154

7255
const result = await simulatorsResourceLogic(mockExecutor);
7356

7457
expect(result.contents).toHaveLength(1);
75-
const text = result.contents[0].text;
76-
expect(text).toContain('iPhone 15');
77-
expect(text).toContain('test-uuid-123');
78-
expect(text).toContain('iOS 17.0');
58+
expect(result.contents[0].text).toContain('Failed to list simulators');
7959
});
8060

8161
it('should handle spawn errors', async () => {

src/mcp/tools/simulator/__tests__/list_sims.test.ts

Lines changed: 40 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -50,32 +50,22 @@ describe('list_sims tool', () => {
5050

5151
describe('Handler Behavior (Complete Literal Returns)', () => {
5252
it('returns structured simulator records for setup flows', async () => {
53-
const mockExecutor = async (command: string[]) => {
54-
if (command.includes('--json')) {
55-
return createMockCommandResponse({
56-
success: true,
57-
output: JSON.stringify({
58-
devices: {
59-
'iOS 17.0': [
60-
{
61-
name: 'iPhone 15',
62-
udid: 'test-uuid-123',
63-
isAvailable: true,
64-
state: 'Shutdown',
65-
},
66-
],
53+
const mockExecutor = createMockExecutor({
54+
success: true,
55+
output: JSON.stringify({
56+
devices: {
57+
'iOS 17.0': [
58+
{
59+
name: 'iPhone 15',
60+
udid: 'test-uuid-123',
61+
isAvailable: true,
62+
state: 'Shutdown',
6763
},
68-
}),
69-
error: undefined,
70-
});
71-
}
72-
73-
return createMockCommandResponse({
74-
success: true,
75-
output: `== Devices ==\n-- iOS 17.0 --\n iPhone 15 (test-uuid-123) (Shutdown)`,
76-
error: undefined,
77-
});
78-
};
64+
],
65+
},
66+
}),
67+
error: undefined,
68+
});
7969

8070
const simulators = await listSimulators(mockExecutor);
8171
expect(simulators).toEqual([
@@ -102,10 +92,6 @@ describe('list_sims tool', () => {
10292
},
10393
});
10494

105-
const mockTextOutput = `== Devices ==
106-
-- iOS 17.0 --
107-
iPhone 15 (test-uuid-123) (Shutdown)`;
108-
10995
const mockExecutor = async (
11096
command: string[],
11197
logPrefix?: string,
@@ -116,33 +102,19 @@ describe('list_sims tool', () => {
116102
callHistory.push({ command, logPrefix, useShell, env: opts?.env });
117103
void detached;
118104

119-
if (command.includes('--json')) {
120-
return createMockCommandResponse({
121-
success: true,
122-
output: mockJsonOutput,
123-
error: undefined,
124-
});
125-
}
126-
127105
return createMockCommandResponse({
128106
success: true,
129-
output: mockTextOutput,
107+
output: mockJsonOutput,
130108
error: undefined,
131109
});
132110
};
133111

134112
const result = await runListSimsLogic({ enabled: true }, mockExecutor);
135113

136-
expect(callHistory).toHaveLength(2);
114+
expect(callHistory).toHaveLength(1);
137115
expect(callHistory[0]).toEqual({
138116
command: ['xcrun', 'simctl', 'list', 'devices', '--json'],
139-
logPrefix: 'List Simulators (JSON)',
140-
useShell: false,
141-
env: undefined,
142-
});
143-
expect(callHistory[1]).toEqual({
144-
command: ['xcrun', 'simctl', 'list', 'devices'],
145-
logPrefix: 'List Simulators (Text)',
117+
logPrefix: 'List Simulators',
146118
useShell: false,
147119
env: undefined,
148120
});
@@ -166,38 +138,23 @@ describe('list_sims tool', () => {
166138
});
167139

168140
it('should handle successful listing with booted simulator', async () => {
169-
const mockJsonOutput = JSON.stringify({
170-
devices: {
171-
'iOS 17.0': [
172-
{
173-
name: 'iPhone 15',
174-
udid: 'test-uuid-123',
175-
isAvailable: true,
176-
state: 'Booted',
177-
},
178-
],
179-
},
141+
const mockExecutor = createMockExecutor({
142+
success: true,
143+
output: JSON.stringify({
144+
devices: {
145+
'iOS 17.0': [
146+
{
147+
name: 'iPhone 15',
148+
udid: 'test-uuid-123',
149+
isAvailable: true,
150+
state: 'Booted',
151+
},
152+
],
153+
},
154+
}),
155+
error: undefined,
180156
});
181157

182-
const mockTextOutput = `== Devices ==
183-
-- iOS 17.0 --
184-
iPhone 15 (test-uuid-123) (Booted)`;
185-
186-
const mockExecutor = async (command: string[]) => {
187-
if (command.includes('--json')) {
188-
return createMockCommandResponse({
189-
success: true,
190-
output: mockJsonOutput,
191-
error: undefined,
192-
});
193-
}
194-
return createMockCommandResponse({
195-
success: true,
196-
output: mockTextOutput,
197-
error: undefined,
198-
});
199-
};
200-
201158
const result = await runListSimsLogic({ enabled: true }, mockExecutor);
202159

203160
const text = result.content.map((c) => c.text).join('\n');
@@ -218,62 +175,6 @@ describe('list_sims tool', () => {
218175
});
219176
});
220177

221-
it('should merge devices from text that are missing from JSON', async () => {
222-
const mockJsonOutput = JSON.stringify({
223-
devices: {
224-
'iOS 18.6': [
225-
{
226-
name: 'iPhone 15',
227-
udid: 'json-uuid-123',
228-
isAvailable: true,
229-
state: 'Shutdown',
230-
},
231-
],
232-
},
233-
});
234-
235-
const mockTextOutput = `== Devices ==
236-
-- iOS 18.6 --
237-
iPhone 15 (json-uuid-123) (Shutdown)
238-
-- iOS 26.0 --
239-
iPhone 17 Pro (text-uuid-456) (Shutdown)`;
240-
241-
const mockExecutor = async (command: string[]) => {
242-
if (command.includes('--json')) {
243-
return createMockCommandResponse({
244-
success: true,
245-
output: mockJsonOutput,
246-
error: undefined,
247-
});
248-
}
249-
return createMockCommandResponse({
250-
success: true,
251-
output: mockTextOutput,
252-
error: undefined,
253-
});
254-
};
255-
256-
const result = await runListSimsLogic({ enabled: true }, mockExecutor);
257-
258-
const text = result.content.map((c) => c.text).join('\n');
259-
expect(text).toContain('iOS 18.6');
260-
expect(text).toContain('iPhone 15');
261-
expect(text).toContain('json-uuid-123');
262-
expect(text).toContain('iOS 26.0');
263-
expect(text).toContain('iPhone 17 Pro');
264-
expect(text).toContain('text-uuid-456');
265-
expect(result.nextStepParams).toEqual({
266-
boot_sim: { simulatorId: 'UUID_FROM_ABOVE' },
267-
open_sim: {},
268-
build_sim: { scheme: 'YOUR_SCHEME', simulatorId: 'UUID_FROM_ABOVE' },
269-
get_sim_app_path: {
270-
scheme: 'YOUR_SCHEME',
271-
platform: 'iOS Simulator',
272-
simulatorId: 'UUID_FROM_ABOVE',
273-
},
274-
});
275-
});
276-
277178
it('should handle command failure', async () => {
278179
const mockExecutor = createMockExecutor({
279180
success: false,
@@ -289,43 +190,17 @@ describe('list_sims tool', () => {
289190
expect(text).toContain('Command failed');
290191
});
291192

292-
it('should handle JSON parse failure and fall back to text parsing', async () => {
293-
const mockTextOutput = `== Devices ==
294-
-- iOS 17.0 --
295-
iPhone 15 (test-uuid-456) (Shutdown)`;
296-
297-
const mockExecutor = async (command: string[]) => {
298-
if (command.includes('--json')) {
299-
return createMockCommandResponse({
300-
success: true,
301-
output: 'invalid json',
302-
error: undefined,
303-
});
304-
}
305-
306-
return createMockCommandResponse({
307-
success: true,
308-
output: mockTextOutput,
309-
error: undefined,
310-
});
311-
};
193+
it('should handle JSON parse failure', async () => {
194+
const mockExecutor = createMockExecutor({
195+
success: true,
196+
output: 'invalid json',
197+
error: undefined,
198+
});
312199

313200
const result = await runListSimsLogic({ enabled: true }, mockExecutor);
314201

315202
const text = result.content.map((c) => c.text).join('\n');
316-
expect(text).toContain('iOS 17.0');
317-
expect(text).toContain('iPhone 15');
318-
expect(text).toContain('test-uuid-456');
319-
expect(result.nextStepParams).toEqual({
320-
boot_sim: { simulatorId: 'UUID_FROM_ABOVE' },
321-
open_sim: {},
322-
build_sim: { scheme: 'YOUR_SCHEME', simulatorId: 'UUID_FROM_ABOVE' },
323-
get_sim_app_path: {
324-
scheme: 'YOUR_SCHEME',
325-
platform: 'iOS Simulator',
326-
simulatorId: 'UUID_FROM_ABOVE',
327-
},
328-
});
203+
expect(text).toContain('Failed to list simulators');
329204
});
330205

331206
it('should handle exception with Error object', async () => {

0 commit comments

Comments
 (0)