77 * Plugin location: plugins/utilities/scaffold_ios_project.js
88 */
99
10- import { describe , it , expect , beforeEach } from 'vitest' ;
10+ import { describe , it , expect , beforeEach , afterEach } from 'vitest' ;
1111import { z } from 'zod' ;
1212import scaffoldIosProject from '../scaffold_ios_project.ts' ;
1313import { createMockExecutor , createMockFileSystemExecutor } from '../../../utils/index.js' ;
1414
1515describe ( 'scaffold_ios_project plugin' , ( ) => {
1616 let mockCommandExecutor : any ;
1717 let mockFileSystemExecutor : any ;
18+ let originalEnv : string | undefined ;
1819
1920 beforeEach ( ( ) => {
20- // Create mock executors
21- mockCommandExecutor = createMockExecutor ( {
22- success : true ,
23- output : 'Command executed successfully' ,
24- } ) ;
21+ // Create mock executor that handles curl/unzip commands properly
22+ mockCommandExecutor = (
23+ command : string [ ] ,
24+ logPrefix ?: string ,
25+ useShell ?: boolean ,
26+ env ?: Record < string , string > ,
27+ ) => {
28+ const cmdString = command . join ( ' ' ) ;
29+
30+ if ( cmdString . includes ( 'curl' ) ) {
31+ // Mock successful download
32+ return Promise . resolve ( {
33+ success : true ,
34+ output : 'Downloaded successfully' ,
35+ process : { pid : 123 } as any ,
36+ } ) ;
37+ } else if ( cmdString . includes ( 'unzip' ) ) {
38+ // Mock successful extraction
39+ return Promise . resolve ( {
40+ success : true ,
41+ output : 'Extracted successfully' ,
42+ process : { pid : 123 } as any ,
43+ } ) ;
44+ }
45+
46+ // Default success for other commands
47+ return Promise . resolve ( {
48+ success : true ,
49+ output : 'Command executed successfully' ,
50+ process : { pid : 123 } as any ,
51+ } ) ;
52+ } ;
2553
2654 mockFileSystemExecutor = createMockFileSystemExecutor ( {
2755 existsSync : ( path ) => {
28- // Return true for template directories, false for project files
56+ // Mock template directories exist but project files don't
2957 return (
30- path . includes ( 'xcodebuild-mcp-template' ) || path . includes ( 'XcodeBuildMCP-iOS-Template' )
58+ path . includes ( 'xcodebuild-mcp-template' ) ||
59+ path . includes ( 'XcodeBuildMCP-iOS-Template' ) ||
60+ path . includes ( '/template' ) ||
61+ path . endsWith ( 'template' ) ||
62+ path . includes ( 'extracted' )
3163 ) ;
3264 } ,
3365 readFile : async ( ) => 'template content with MyProject placeholder' ,
3466 readdir : async ( ) => [
3567 { name : 'Package.swift' , isDirectory : ( ) => false , isFile : ( ) => true } as any ,
3668 { name : 'MyProject.swift' , isDirectory : ( ) => false , isFile : ( ) => true } as any ,
3769 ] ,
70+ mkdir : async ( ) => { } ,
71+ rm : async ( ) => { } ,
72+ cp : async ( ) => { } ,
73+ writeFile : async ( ) => { } ,
74+ stat : async ( ) => ( { isDirectory : ( ) => true } ) ,
3875 } ) ;
76+
77+ // Store original environment for cleanup
78+ originalEnv = process . env . XCODEBUILDMCP_IOS_TEMPLATE_PATH ;
79+ // Don't set local template path - let it use mocked download
80+ delete process . env . XCODEBUILDMCP_IOS_TEMPLATE_PATH ;
81+ } ) ;
82+
83+ afterEach ( ( ) => {
84+ // Restore original environment
85+ if ( originalEnv !== undefined ) {
86+ process . env . XCODEBUILDMCP_IOS_TEMPLATE_PATH = originalEnv ;
87+ } else {
88+ delete process . env . XCODEBUILDMCP_IOS_TEMPLATE_PATH ;
89+ }
3990 } ) ;
4091
4192 describe ( 'Export Field Validation (Literal)' , ( ) => {
@@ -306,18 +357,39 @@ describe('scaffold_ios_project plugin', () => {
306357 } ) ;
307358
308359 it ( 'should return error response for template download failure' , async ( ) => {
309- // Mock command executor to fail for template download
310- mockCommandExecutor = createMockExecutor ( {
311- success : false ,
312- error : 'Template download failed' ,
313- } ) ;
360+ // Mock command executor to fail for curl commands
361+ const failingMockCommandExecutor = (
362+ command : string [ ] ,
363+ logPrefix ?: string ,
364+ useShell ?: boolean ,
365+ env ?: Record < string , string > ,
366+ ) => {
367+ const cmdString = command . join ( ' ' ) ;
368+
369+ if ( cmdString . includes ( 'curl' ) ) {
370+ // Mock download failure
371+ return Promise . resolve ( {
372+ success : false ,
373+ output : '' ,
374+ error : 'Template download failed' ,
375+ process : { pid : 123 } as any ,
376+ } ) ;
377+ }
378+
379+ // Other commands succeed
380+ return Promise . resolve ( {
381+ success : true ,
382+ output : 'Command executed successfully' ,
383+ process : { pid : 123 } as any ,
384+ } ) ;
385+ } ;
314386
315387 const result = await scaffoldIosProject . handler (
316388 {
317389 projectName : 'TestIOSApp' ,
318390 outputPath : '/tmp/test-projects' ,
319391 } ,
320- mockCommandExecutor ,
392+ failingMockCommandExecutor ,
321393 mockFileSystemExecutor ,
322394 ) ;
323395
@@ -341,37 +413,46 @@ describe('scaffold_ios_project plugin', () => {
341413 } ) ;
342414
343415 it ( 'should return error response for template extraction failure' , async ( ) => {
344- // Manual call tracking for multi-step command execution
345- let callCount = 0 ;
346- const executorCalls : Array < { command : string ; args : string [ ] } > = [ ] ;
347-
348- // Create custom executor stub that succeeds for download but fails for extraction
349- const customExecutor = ( command : string , args : string [ ] = [ ] ) => {
350- executorCalls . push ( { command, args } ) ;
351- callCount ++ ;
352- if ( callCount === 1 ) {
353- // First call (download) succeeds
416+ // Mock command executor to fail for unzip commands
417+ const failingMockCommandExecutor = (
418+ command : string [ ] ,
419+ logPrefix ?: string ,
420+ useShell ?: boolean ,
421+ env ?: Record < string , string > ,
422+ ) => {
423+ const cmdString = command . join ( ' ' ) ;
424+
425+ if ( cmdString . includes ( 'curl' ) ) {
426+ // Mock download success
354427 return Promise . resolve ( {
355428 success : true ,
356429 output : 'Downloaded successfully' ,
357- error : '' ,
430+ process : { pid : 123 } as any ,
358431 } ) ;
359- } else {
360- // Second call (extract) fails
432+ } else if ( cmdString . includes ( 'unzip' ) ) {
433+ // Mock extraction failure
361434 return Promise . resolve ( {
362435 success : false ,
363436 output : '' ,
364437 error : 'Extraction failed' ,
438+ process : { pid : 123 } as any ,
365439 } ) ;
366440 }
441+
442+ // Other commands succeed
443+ return Promise . resolve ( {
444+ success : true ,
445+ output : 'Command executed successfully' ,
446+ process : { pid : 123 } as any ,
447+ } ) ;
367448 } ;
368449
369450 const result = await scaffoldIosProject . handler (
370451 {
371452 projectName : 'TestIOSApp' ,
372453 outputPath : '/tmp/test-projects' ,
373454 } ,
374- customExecutor ,
455+ failingMockCommandExecutor ,
375456 mockFileSystemExecutor ,
376457 ) ;
377458
0 commit comments