Skip to main content
Glama

XC-MCP: XCode CLI wrapper

by conorluddy
device-detection.test.ts6 kB
import { getBootedDevice, resolveDeviceId } from '../../../src/utils/device-detection.js'; import { McpError } from '@modelcontextprotocol/sdk/types.js'; // Mock the command execution jest.mock('../../../src/utils/command.js', () => ({ executeCommand: jest.fn(), })); const { executeCommand } = require('../../../src/utils/command.js'); describe('device-detection', () => { beforeEach(() => { jest.clearAllMocks(); }); describe('getBootedDevice', () => { it('should find booted simulator', async () => { const mockOutput = { devices: { 'com.apple.CoreSimulator.SimRuntime.iOS-18-0': [ { name: 'iPhone 16 Pro', udid: 'ABC-123-DEF', state: 'Booted', isAvailable: true, }, ], }, }; executeCommand.mockResolvedValue({ code: 0, stdout: JSON.stringify(mockOutput), stderr: '', }); const device = await getBootedDevice(); expect(device.name).toBe('iPhone 16 Pro'); expect(device.udid).toBe('ABC-123-DEF'); }); it('should skip unavailable devices', async () => { const mockOutput = { devices: { 'com.apple.CoreSimulator.SimRuntime.iOS-18-0': [ { name: 'iPhone 15', udid: 'UNAVAILABLE-123', state: 'Booted', isAvailable: false, }, { name: 'iPhone 16 Pro', udid: 'AVAILABLE-456', state: 'Booted', isAvailable: true, }, ], }, }; executeCommand.mockResolvedValue({ code: 0, stdout: JSON.stringify(mockOutput), stderr: '', }); const device = await getBootedDevice(); expect(device.udid).toBe('AVAILABLE-456'); }); it('should throw if no booted device found', async () => { const mockOutput = { devices: { 'com.apple.CoreSimulator.SimRuntime.iOS-18-0': [ { name: 'iPhone 16 Pro', udid: 'ABC-123-DEF', state: 'Shutdown', isAvailable: true, }, ], }, }; executeCommand.mockResolvedValue({ code: 0, stdout: JSON.stringify(mockOutput), stderr: '', }); await expect(getBootedDevice()).rejects.toThrow('No booted simulator found'); }); it('should throw if simctl command fails', async () => { executeCommand.mockResolvedValue({ code: 1, stdout: '', stderr: 'Device list error', }); await expect(getBootedDevice()).rejects.toThrow('Failed to list devices'); }); it('should handle multiple runtimes', async () => { const mockOutput = { devices: { 'com.apple.CoreSimulator.SimRuntime.iOS-17-0': [ { name: 'iPhone 15', udid: 'OLD-123', state: 'Shutdown', isAvailable: true, }, ], 'com.apple.CoreSimulator.SimRuntime.iOS-18-0': [ { name: 'iPhone 16 Pro', udid: 'NEW-456', state: 'Booted', isAvailable: true, }, ], }, }; executeCommand.mockResolvedValue({ code: 0, stdout: JSON.stringify(mockOutput), stderr: '', }); const device = await getBootedDevice(); expect(device.udid).toBe('NEW-456'); expect(device.name).toBe('iPhone 16 Pro'); }); }); describe('resolveDeviceId', () => { it('should return provided UDID when given', async () => { const result = await resolveDeviceId('PROVIDED-123'); expect(result).toBe('PROVIDED-123'); expect(executeCommand).not.toHaveBeenCalled(); }); it('should auto-detect when UDID not provided', async () => { const mockOutput = { devices: { 'com.apple.CoreSimulator.SimRuntime.iOS-18-0': [ { name: 'iPhone 16 Pro', udid: 'AUTO-DETECTED-123', state: 'Booted', isAvailable: true, }, ], }, }; executeCommand.mockResolvedValue({ code: 0, stdout: JSON.stringify(mockOutput), stderr: '', }); const result = await resolveDeviceId(); expect(result).toBe('AUTO-DETECTED-123'); expect(executeCommand).toHaveBeenCalled(); }); it('should auto-detect when empty string provided', async () => { const mockOutput = { devices: { 'com.apple.CoreSimulator.SimRuntime.iOS-18-0': [ { name: 'iPhone 16 Pro', udid: 'AUTO-DETECTED-123', state: 'Booted', isAvailable: true, }, ], }, }; executeCommand.mockResolvedValue({ code: 0, stdout: JSON.stringify(mockOutput), stderr: '', }); const result = await resolveDeviceId(''); expect(result).toBe('AUTO-DETECTED-123'); }); it('should throw McpError when auto-detection fails', async () => { const mockOutput = { devices: { 'com.apple.CoreSimulator.SimRuntime.iOS-18-0': [ { name: 'iPhone 16 Pro', udid: 'ABC-123', state: 'Shutdown', isAvailable: true, }, ], }, }; executeCommand.mockResolvedValue({ code: 0, stdout: JSON.stringify(mockOutput), stderr: '', }); await expect(resolveDeviceId()).rejects.toThrow(McpError); }); it('should preserve whitespace in provided UDID', async () => { const result = await resolveDeviceId(' PROVIDED-123 '); expect(result).toBe(' PROVIDED-123 '); expect(executeCommand).not.toHaveBeenCalled(); }); }); });

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/conorluddy/xc-mcp'

If you have feedback or need assistance with the MCP directory API, please join our Discord server