import { describe, it, expect, beforeAll, afterAll, beforeEach } from 'vitest';
import { createMcpTestHarness, type McpTestHarness } from '../mcp-test-harness.ts';
import { extractText, expectContent } from '../test-helpers.ts';
let harness: McpTestHarness;
beforeAll(async () => {
harness = await createMcpTestHarness({
commandResponses: {
xcodebuild: { success: true, output: 'Build Succeeded' },
'simctl list devices': {
success: true,
output: JSON.stringify({
devices: {
'com.apple.CoreSimulator.SimRuntime.iOS-18-0': [
{
name: 'iPhone 16 Pro',
udid: 'AAAAAAAA-1111-2222-3333-444444444444',
state: 'Shutdown',
isAvailable: true,
},
],
},
}),
},
},
});
}, 30_000);
afterAll(async () => {
await harness.cleanup();
});
beforeEach(async () => {
// Clear defaults before each test
await harness.client.callTool({
name: 'session_clear_defaults',
arguments: { all: true },
});
});
describe('MCP Session Management (e2e)', () => {
it('session_set_defaults stores scheme', async () => {
const result = await harness.client.callTool({
name: 'session_set_defaults',
arguments: { scheme: 'MyApp' },
});
expect(result).toBeDefined();
const text = extractText(result);
expect(text).toContain('scheme');
});
it('session_show_defaults returns the set defaults', async () => {
// Set some defaults
await harness.client.callTool({
name: 'session_set_defaults',
arguments: { scheme: 'TestApp', projectPath: '/path/to/project' },
});
// Show defaults
const result = await harness.client.callTool({
name: 'session_show_defaults',
arguments: {},
});
const text = extractText(result);
expect(text).toContain('TestApp');
expect(text).toContain('/path/to/project');
});
it('session_clear_defaults clears all defaults', async () => {
// Set defaults
await harness.client.callTool({
name: 'session_set_defaults',
arguments: { scheme: 'ClearMeScheme', projectPath: '/clear-me-proj' },
});
// Clear all
await harness.client.callTool({
name: 'session_clear_defaults',
arguments: { all: true },
});
// Show should be empty
const result = await harness.client.callTool({
name: 'session_show_defaults',
arguments: {},
});
const text = extractText(result);
// Should not contain the previously set values
expect(text).not.toContain('ClearMeScheme');
expect(text).not.toContain('/clear-me-proj');
});
it('session_clear_defaults clears specific keys', async () => {
// Set multiple defaults
await harness.client.callTool({
name: 'session_set_defaults',
arguments: { scheme: 'KeepThis', projectPath: '/clear/this' },
});
// Clear only projectPath
await harness.client.callTool({
name: 'session_clear_defaults',
arguments: { keys: ['projectPath'] },
});
// Show defaults
const result = await harness.client.callTool({
name: 'session_show_defaults',
arguments: {},
});
const text = extractText(result);
expect(text).toContain('KeepThis');
expect(text).not.toContain('/clear/this');
});
it('session defaults flow into tool invocations', async () => {
// Set session defaults
await harness.client.callTool({
name: 'session_set_defaults',
arguments: {
scheme: 'SessionScheme',
projectPath: '/session/project.xcodeproj',
simulatorId: 'AAAAAAAA-1111-2222-3333-444444444444',
},
});
// Invoke build_sim without explicit scheme/project (should use session defaults)
harness.resetCapturedCommands();
const result = await harness.client.callTool({
name: 'build_sim',
arguments: {},
});
expectContent(result);
// The captured commands should include the session default scheme
const commandStrs = harness.capturedCommands.map((c) => c.command.join(' '));
const buildCommand = commandStrs.find((c) => c.includes('xcodebuild') && c.includes('-scheme'));
expect(buildCommand).toBeDefined();
expect(buildCommand).toContain('SessionScheme');
});
it('updating session defaults changes subsequent tool behavior', async () => {
// Set initial defaults
await harness.client.callTool({
name: 'session_set_defaults',
arguments: {
scheme: 'FirstScheme',
projectPath: '/first/project.xcodeproj',
simulatorId: 'AAAAAAAA-1111-2222-3333-444444444444',
},
});
// Update scheme via session_set_defaults
await harness.client.callTool({
name: 'session_set_defaults',
arguments: {
scheme: 'UpdatedScheme',
},
});
// Invoke build_sim - should use the updated scheme
harness.resetCapturedCommands();
const result = await harness.client.callTool({
name: 'build_sim',
arguments: {},
});
expect(result).toBeDefined();
const commandStrs = harness.capturedCommands.map((c) => c.command.join(' '));
const buildCommand = commandStrs.find((c) => c.includes('xcodebuild') && c.includes('-scheme'));
expect(buildCommand).toBeDefined();
expect(buildCommand).toContain('UpdatedScheme');
});
});