Skip to main content
Glama

MCP Xcode

by Stefan-Nitu
BuildRequest.unit.test.ts8.85 kB
import { describe, it, expect, jest, beforeEach } from '@jest/globals'; import { BuildRequest } from '../../domain/BuildRequest.js'; import { BuildDestination } from '../../domain/BuildDestination.js'; import { existsSync } from 'fs'; // Mock filesystem for ProjectPath validation jest.mock('fs', () => ({ existsSync: jest.fn<(path: string) => boolean>() })); const mockExistsSync = existsSync as jest.MockedFunction<typeof existsSync>; /** * Unit tests for BuildRequest value object * * Testing expected BEHAVIOR: * 1. BuildRequest represents a valid build request * 2. All fields are required and validated * 3. Invalid data is rejected at creation * 4. Object is immutable after creation */ describe('BuildRequest', () => { beforeEach(() => { jest.clearAllMocks(); // Default mock: project exists mockExistsSync.mockReturnValue(true); }); describe('create method', () => { it('should create BuildRequest with all required fields', () => { // Act const request = BuildRequest.create( '/path/to/project.xcodeproj', 'MyApp', BuildDestination.iOSSimulator, 'Debug', '/path/to/DerivedData' ); // Assert expect(request.scheme).toBe('MyApp'); expect(request.destination).toBe(BuildDestination.iOSSimulator); expect(request.configuration).toBe('Debug'); expect(request.derivedDataPath).toBe('/path/to/DerivedData'); expect(request.projectPath.toString()).toBe('/path/to/project.xcodeproj'); }); it('should use Debug as default configuration', () => { // Act const request = BuildRequest.create( '/path/to/project.xcodeproj', 'MyApp', BuildDestination.iOSSimulator, undefined, // Use default '/path/to/DerivedData' ); // Assert expect(request.configuration).toBe('Debug'); }); it('should accept different BuildDestination values', () => { // Arrange const destinations = [ BuildDestination.iOSDevice, BuildDestination.iOSSimulatorUniversal, BuildDestination.tvOSSimulator, BuildDestination.watchOSSimulator, BuildDestination.visionOSSimulator, BuildDestination.macOSUniversal ]; // Act & Assert for (const destination of destinations) { const request = BuildRequest.create( '/path/to/project.xcodeproj', 'MyApp', destination, 'Debug', '/path/to/DerivedData' ); expect(request.destination).toBe(destination); } }); it('should accept .xcworkspace files', () => { // Act const request = BuildRequest.create( '/path/to/project.xcworkspace', 'MyApp', BuildDestination.iOSSimulator, 'Debug', '/path/to/DerivedData' ); // Assert expect(request.projectPath.isWorkspace).toBe(true); expect(request.projectPath.toString()).toBe('/path/to/project.xcworkspace'); }); it('should accept .xcodeproj files', () => { // Act const request = BuildRequest.create( '/path/to/project.xcodeproj', 'MyApp', BuildDestination.iOSSimulator, 'Debug', '/path/to/DerivedData' ); // Assert expect(request.projectPath.isWorkspace).toBe(false); expect(request.projectPath.toString()).toBe('/path/to/project.xcodeproj'); }); }); describe('validation', () => { it('should throw error when projectPath does not exist', () => { // Arrange mockExistsSync.mockReturnValue(false); // Act & Assert expect(() => BuildRequest.create( '/path/to/nonexistent.xcodeproj', 'MyApp', BuildDestination.iOSSimulator, 'Debug', '/path/to/DerivedData' )).toThrow('Project path does not exist'); }); it('should throw error when projectPath is empty', () => { // Act & Assert expect(() => BuildRequest.create( '', 'MyApp', BuildDestination.iOSSimulator, 'Debug', '/path/to/DerivedData' )).toThrow('Project path cannot be empty'); }); it('should throw error when scheme is empty', () => { // Act & Assert expect(() => BuildRequest.create( '/path/to/project.xcodeproj', '', BuildDestination.iOSSimulator, 'Debug', '/path/to/DerivedData' )).toThrow('Scheme cannot be empty'); }); it('should throw error when scheme is only whitespace', () => { // Act & Assert expect(() => BuildRequest.create( '/path/to/project.xcodeproj', ' ', BuildDestination.iOSSimulator, 'Debug', '/path/to/DerivedData' )).toThrow('Scheme cannot be empty'); }); it('should throw error when configuration is empty', () => { // Act & Assert expect(() => BuildRequest.create( '/path/to/project.xcodeproj', 'MyApp', BuildDestination.iOSSimulator, '', '/path/to/DerivedData' )).toThrow('Configuration cannot be empty'); }); it('should throw error when configuration is only whitespace', () => { // Act & Assert expect(() => BuildRequest.create( '/path/to/project.xcodeproj', 'MyApp', BuildDestination.iOSSimulator, ' ', '/path/to/DerivedData' )).toThrow('Configuration cannot be empty'); }); it('should throw error when derivedDataPath is empty', () => { // Act & Assert expect(() => BuildRequest.create( '/path/to/project.xcodeproj', 'MyApp', BuildDestination.iOSSimulator, 'Debug', '' )).toThrow('Derived data path cannot be empty'); }); it('should throw error when derivedDataPath is only whitespace', () => { // Act & Assert expect(() => BuildRequest.create( '/path/to/project.xcodeproj', 'MyApp', BuildDestination.iOSSimulator, 'Debug', ' ' )).toThrow('Derived data path cannot be empty'); }); it('should throw error for invalid project file extensions', () => { // Act & Assert expect(() => BuildRequest.create( '/path/to/project.txt', 'MyApp', BuildDestination.iOSSimulator, 'Debug', '/path/to/DerivedData' )).toThrow('Project path must be an .xcodeproj or .xcworkspace file'); }); }); describe('immutability', () => { it('should have readonly properties', () => { // Arrange const request = BuildRequest.create( '/path/to/project.xcodeproj', 'MyApp', BuildDestination.iOSSimulator, 'Debug', '/path/to/DerivedData' ); // TypeScript compiler enforces readonly, but we can verify at runtime expect(Object.isFrozen(request.projectPath)).toBe(false); // Objects aren't frozen expect(typeof request.scheme).toBe('string'); // Primitives are immutable expect(typeof request.configuration).toBe('string'); expect(typeof request.derivedDataPath).toBe('string'); }); }); describe('edge cases', () => { it('should handle long file paths', () => { // Arrange const longPath = '/very/long/path/'.repeat(50) + 'project.xcodeproj'; // Act const request = BuildRequest.create( longPath, 'MyApp', BuildDestination.iOSSimulator, 'Debug', '/path/to/DerivedData' ); // Assert expect(request.projectPath.toString()).toBe(longPath); }); it('should handle Unicode characters in scheme name', () => { // Act const request = BuildRequest.create( '/path/to/project.xcodeproj', 'MyApp-测试-🚀', BuildDestination.iOSSimulator, 'Debug', '/path/to/DerivedData' ); // Assert expect(request.scheme).toBe('MyApp-测试-🚀'); }); it('should handle spaces in project path', () => { // Arrange const pathWithSpaces = '/path/to/My Project/project.xcodeproj'; // Act const request = BuildRequest.create( pathWithSpaces, 'MyApp', BuildDestination.iOSSimulator, 'Debug', '/path/to/DerivedData' ); // Assert expect(request.projectPath.toString()).toBe(pathWithSpaces); }); it('should handle spaces in derived data path', () => { // Act const request = BuildRequest.create( '/path/to/project.xcodeproj', 'MyApp', BuildDestination.iOSSimulator, 'Debug', '/path/to/Derived Data' ); // Assert expect(request.derivedDataPath).toBe('/path/to/Derived Data'); }); }); });

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/Stefan-Nitu/mcp-xcode'

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