Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 17 additions & 21 deletions src/mcp/tools/simulator-management/__tests__/erase_sims.test.ts
Original file line number Diff line number Diff line change
@@ -1,41 +1,37 @@
import { describe, it, expect } from 'vitest';
import * as z from 'zod';
import { schema, erase_simsLogic } from '../erase_sims.ts';
import { createMockExecutor } from '../../../../test-utils/mock-executors.ts';
import { allText, runLogic } from '../../../../test-utils/test-helpers.ts';


describe('erase_sims tool (single simulator)', () => {
describe('Schema Validation', () => {
it('should validate schema fields (shape only)', () => {
const schemaObj = z.object(schema);
expect(schemaObj.safeParse({ shutdownFirst: true }).success).toBe(true);
expect(schemaObj.safeParse({}).success).toBe(true);
describe('Plugin Structure', () => {
it('should expose schema', () => {
expect(schema).toBeDefined();
});
});

describe('Single mode', () => {
it('erases a simulator successfully', async () => {
const mock = createMockExecutor({ success: true, output: 'OK' });
const res = await erase_simsLogic({ simulatorId: 'UD1' }, mock);
expect(res).toEqual({
content: [{ type: 'text', text: 'Successfully erased simulator UD1' }],
});
const res = await runLogic(() => erase_simsLogic({ simulatorId: 'UD1' }, mock));
expect(res.isError).toBeFalsy();
});

it('returns failure when erase fails', async () => {
const mock = createMockExecutor({ success: false, error: 'Booted device' });
const res = await erase_simsLogic({ simulatorId: 'UD1' }, mock);
expect(res).toEqual({
content: [{ type: 'text', text: 'Failed to erase simulator: Booted device' }],
});
const res = await runLogic(() => erase_simsLogic({ simulatorId: 'UD1' }, mock));
expect(res.isError).toBe(true);
});

it('adds tool hint when booted error occurs without shutdownFirst', async () => {
const bootedError =
'An error was encountered processing the command (domain=com.apple.CoreSimulator.SimError, code=405):\nUnable to erase contents and settings in current state: Booted\n';
const mock = createMockExecutor({ success: false, error: bootedError });
const res = await erase_simsLogic({ simulatorId: 'UD1' }, mock);
expect((res.content?.[1] as any).text).toContain('Tool hint');
expect((res.content?.[1] as any).text).toContain('shutdownFirst: true');
const res = await runLogic(() => erase_simsLogic({ simulatorId: 'UD1' }, mock));
const text = allText(res);
expect(text).toContain('shutdownFirst: true');
expect(res.isError).toBe(true);
});

it('performs shutdown first when shutdownFirst=true', async () => {
Expand All @@ -44,14 +40,14 @@ describe('erase_sims tool (single simulator)', () => {
calls.push(cmd);
return { success: true, output: 'OK', error: '', process: { pid: 1 } as any };
};
const res = await erase_simsLogic({ simulatorId: 'UD1', shutdownFirst: true }, exec as any);
const res = await runLogic(() =>
erase_simsLogic({ simulatorId: 'UD1', shutdownFirst: true }, exec as any),
);
expect(calls).toEqual([
['xcrun', 'simctl', 'shutdown', 'UD1'],
['xcrun', 'simctl', 'erase', 'UD1'],
]);
expect(res).toEqual({
content: [{ type: 'text', text: 'Successfully erased simulator UD1' }],
});
expect(res.isError).toBeFalsy();
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { describe, it, expect } from 'vitest';
import * as z from 'zod';
import { schema, reset_sim_locationLogic } from '../reset_sim_location.ts';
import { createMockExecutor } from '../../../../test-utils/mock-executors.ts';
import { runLogic } from '../../../../test-utils/test-helpers.ts';


describe('reset_sim_location plugin', () => {
describe('Schema Validation', () => {
Expand All @@ -23,21 +25,16 @@ describe('reset_sim_location plugin', () => {
output: 'Location reset successfully',
});

const result = await reset_sim_locationLogic(
{
simulatorId: 'test-uuid-123',
},
mockExecutor,
);

expect(result).toEqual({
content: [
const result = await runLogic(() =>
reset_sim_locationLogic(
{
type: 'text',
text: 'Successfully reset simulator test-uuid-123 location.',
simulatorId: 'test-uuid-123',
},
],
});
mockExecutor,
),
);

expect(result.isError).toBeFalsy();
});

it('should handle command failure', async () => {
Expand All @@ -46,41 +43,31 @@ describe('reset_sim_location plugin', () => {
error: 'Command failed',
});

const result = await reset_sim_locationLogic(
{
simulatorId: 'test-uuid-123',
},
mockExecutor,
);

expect(result).toEqual({
content: [
const result = await runLogic(() =>
reset_sim_locationLogic(
{
type: 'text',
text: 'Failed to reset simulator location: Command failed',
simulatorId: 'test-uuid-123',
},
],
});
mockExecutor,
),
);

expect(result.isError).toBe(true);
});

it('should handle exception during execution', async () => {
const mockExecutor = createMockExecutor(new Error('Network error'));

const result = await reset_sim_locationLogic(
{
simulatorId: 'test-uuid-123',
},
mockExecutor,
);

expect(result).toEqual({
content: [
const result = await runLogic(() =>
reset_sim_locationLogic(
{
type: 'text',
text: 'Failed to reset simulator location: Network error',
simulatorId: 'test-uuid-123',
},
],
});
mockExecutor,
),
);

expect(result.isError).toBe(true);
});

it('should call correct command', async () => {
Expand All @@ -92,18 +79,19 @@ describe('reset_sim_location plugin', () => {
output: 'Location reset successfully',
});

// Create a wrapper to capture the command arguments
const capturingExecutor = async (command: string[], logPrefix?: string) => {
capturedCommand = command;
capturedLogPrefix = logPrefix;
return mockExecutor(command, logPrefix);
};

await reset_sim_locationLogic(
{
simulatorId: 'test-uuid-123',
},
capturingExecutor,
await runLogic(() =>
reset_sim_locationLogic(
{
simulatorId: 'test-uuid-123',
},
capturingExecutor,
),
);

expect(capturedCommand).toEqual(['xcrun', 'simctl', 'location', 'test-uuid-123', 'clear']);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import { describe, it, expect } from 'vitest';
import * as z from 'zod';
import { schema, handler, set_sim_appearanceLogic } from '../set_sim_appearance.ts';
import { runLogic } from '../../../../test-utils/test-helpers.ts';


import {
createMockCommandResponse,
createMockExecutor,
Expand Down Expand Up @@ -33,22 +36,17 @@ describe('set_sim_appearance plugin', () => {
error: '',
});

const result = await set_sim_appearanceLogic(
{
simulatorId: 'test-uuid-123',
mode: 'dark',
},
mockExecutor,
);

expect(result).toEqual({
content: [
const result = await runLogic(() =>
set_sim_appearanceLogic(
{
type: 'text',
text: 'Successfully set simulator test-uuid-123 appearance to dark mode',
simulatorId: 'test-uuid-123',
mode: 'dark',
},
],
});
mockExecutor,
),
);

expect(result.isError).toBeFalsy();
});

it('should handle appearance change failure', async () => {
Expand All @@ -57,52 +55,42 @@ describe('set_sim_appearance plugin', () => {
error: 'Invalid device: invalid-uuid',
});

const result = await set_sim_appearanceLogic(
{
simulatorId: 'invalid-uuid',
mode: 'light',
},
mockExecutor,
);

expect(result).toEqual({
content: [
const result = await runLogic(() =>
set_sim_appearanceLogic(
{
type: 'text',
text: 'Failed to set simulator appearance: Invalid device: invalid-uuid',
simulatorId: 'invalid-uuid',
mode: 'light',
},
],
});
mockExecutor,
),
);

expect(result.isError).toBe(true);
});

it('should surface session default requirement when simulatorId is missing', async () => {
const result = await handler({ mode: 'dark' });

const message = result.content?.[0]?.text ?? '';
expect(message).toContain('Error: Missing required session defaults');
expect(message).toContain('Missing required session defaults');
expect(message).toContain('simulatorId is required');
expect(result.isError).toBe(true);
});

it('should handle exception during execution', async () => {
const mockExecutor = createMockExecutor(new Error('Network error'));

const result = await set_sim_appearanceLogic(
{
simulatorId: 'test-uuid-123',
mode: 'dark',
},
mockExecutor,
);

expect(result).toEqual({
content: [
const result = await runLogic(() =>
set_sim_appearanceLogic(
{
type: 'text',
text: 'Failed to set simulator appearance: Network error',
simulatorId: 'test-uuid-123',
mode: 'dark',
},
],
});
mockExecutor,
),
);

expect(result.isError).toBe(true);
});

it('should call correct command', async () => {
Expand All @@ -118,20 +106,21 @@ describe('set_sim_appearance plugin', () => {
);
};

await set_sim_appearanceLogic(
{
simulatorId: 'test-uuid-123',
mode: 'dark',
},
mockExecutor,
await runLogic(() =>
set_sim_appearanceLogic(
{
simulatorId: 'test-uuid-123',
mode: 'dark',
},
mockExecutor,
),
);

expect(commandCalls).toEqual([
[
['xcrun', 'simctl', 'ui', 'test-uuid-123', 'appearance', 'dark'],
'Set Simulator Appearance',
false,
undefined,
],
]);
});
Expand Down
Loading