Skip to content

Commit b44d4b4

Browse files
cipolleschimeta-codesync[bot]
authored andcommitted
Add function to coordinate the headers preparation for the app (#53677)
Summary: Pull Request resolved: #53677 ## Context When configuring an app to build with SwiftPM from source, there is a sequence of operations we need to run in order to prepare the project correctly. ## Changed Add a function that runs `prepareHeaders` that configures the headers for React Native and Codegen targets. ## Changelog: [Internal] - Reviewed By: cortinico Differential Revision: D81778440 fbshipit-source-id: 26b973c07e82f30663e51c4a8e0e72f54765115e
1 parent 2ea9fd6 commit b44d4b4

2 files changed

Lines changed: 377 additions & 0 deletions

File tree

packages/react-native/scripts/swiftpm/__tests__/prepare-app-utils-test.js

Lines changed: 318 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const {
1515
createHardlinks,
1616
findXcodeProjectDirectory,
1717
generateCodegenArtifacts,
18+
prepareHeaders,
1819
runIosPrebuild,
1920
runPodDeintegrate,
2021
setBuildFromSource,
@@ -364,6 +365,323 @@ describe('generateCodegenArtifacts', () => {
364365
});
365366
});
366367

368+
describe('prepareHeaders', () => {
369+
let mockPrepareAppDependenciesHeaders;
370+
let mockPath;
371+
let mockConsoleLog;
372+
373+
beforeEach(() => {
374+
// Setup mocks
375+
const prepareAppDependenciesHeadersModule = require('../prepare-app-dependencies-headers');
376+
mockPrepareAppDependenciesHeaders =
377+
prepareAppDependenciesHeadersModule.prepareAppDependenciesHeaders;
378+
379+
mockPath = require('path');
380+
mockConsoleLog = console.log;
381+
382+
// Clear and reset all mocks completely
383+
jest.clearAllMocks();
384+
jest.resetAllMocks();
385+
386+
// Set up fresh mock implementations
387+
mockPrepareAppDependenciesHeaders.mockImplementation(() => {});
388+
389+
// Mock path.join to return realistic paths
390+
mockPath.join.mockImplementation((...args) => args.join('/'));
391+
});
392+
393+
it('should prepare all three types of headers successfully', async () => {
394+
// Setup
395+
const reactNativePath = '/path/to/react-native';
396+
const appIosPath = '/path/to/app/ios';
397+
398+
mockPrepareAppDependenciesHeaders.mockImplementation(() => {});
399+
400+
// Execute
401+
await prepareHeaders(reactNativePath, appIosPath);
402+
403+
// Assert
404+
const expectedOutputFolder =
405+
'/path/to/app/ios/build/generated/ios/ReactAppDependencyProvider';
406+
const expectedCodegenOutputFolder =
407+
'/path/to/app/ios/build/generated/ios/ReactCodegen';
408+
409+
// Verify all three calls with correct parameters
410+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenCalledTimes(3);
411+
412+
// 1. Codegen headers
413+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenNthCalledWith(
414+
1,
415+
reactNativePath,
416+
appIosPath,
417+
expectedOutputFolder,
418+
'codegen',
419+
);
420+
421+
// 2. React Native headers
422+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenNthCalledWith(
423+
2,
424+
reactNativePath,
425+
appIosPath,
426+
expectedCodegenOutputFolder,
427+
'react-native',
428+
);
429+
430+
// 3. Third-party dependencies headers
431+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenNthCalledWith(
432+
3,
433+
reactNativePath,
434+
appIosPath,
435+
expectedCodegenOutputFolder,
436+
'third-party-dependencies',
437+
);
438+
439+
// Verify console output
440+
expect(mockConsoleLog).toHaveBeenCalledWith('Preparing codegen headers...');
441+
expect(mockConsoleLog).toHaveBeenCalledWith('✓ Codegen headers prepared');
442+
expect(mockConsoleLog).toHaveBeenCalledWith(
443+
'Preparing react-native headers...',
444+
);
445+
expect(mockConsoleLog).toHaveBeenCalledWith(
446+
'✓ React Native headers prepared',
447+
);
448+
expect(mockConsoleLog).toHaveBeenCalledWith(
449+
'Preparing third-party dependencies headers...',
450+
);
451+
expect(mockConsoleLog).toHaveBeenCalledWith(
452+
'✓ Third-party dependencies headers prepared',
453+
);
454+
});
455+
456+
it('should throw error when codegen header preparation fails', async () => {
457+
// Setup
458+
const reactNativePath = '/path/to/react-native';
459+
const appIosPath = '/path/to/app/ios';
460+
const originalError = new Error('Codegen header preparation failed');
461+
462+
mockPrepareAppDependenciesHeaders.mockImplementationOnce(() => {
463+
throw originalError;
464+
});
465+
466+
// Execute & Assert
467+
await expect(prepareHeaders(reactNativePath, appIosPath)).rejects.toThrow(
468+
'Header preparation failed: Codegen header preparation failed',
469+
);
470+
471+
const expectedOutputFolder =
472+
'/path/to/app/ios/build/generated/ios/ReactAppDependencyProvider';
473+
474+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenCalledTimes(1);
475+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenCalledWith(
476+
reactNativePath,
477+
appIosPath,
478+
expectedOutputFolder,
479+
'codegen',
480+
);
481+
482+
expect(mockConsoleLog).toHaveBeenCalledWith('Preparing codegen headers...');
483+
expect(mockConsoleLog).not.toHaveBeenCalledWith(
484+
'✓ Codegen headers prepared',
485+
);
486+
});
487+
488+
it('should throw error when react-native header preparation fails', async () => {
489+
// Setup
490+
const reactNativePath = '/path/to/react-native';
491+
const appIosPath = '/path/to/app/ios';
492+
const originalError = new Error('React Native header preparation failed');
493+
494+
mockPrepareAppDependenciesHeaders
495+
.mockImplementationOnce(() => {}) // First call succeeds
496+
.mockImplementationOnce(() => {
497+
// Second call fails
498+
throw originalError;
499+
});
500+
501+
// Execute & Assert
502+
await expect(prepareHeaders(reactNativePath, appIosPath)).rejects.toThrow(
503+
'Header preparation failed: React Native header preparation failed',
504+
);
505+
506+
const expectedOutputFolder =
507+
'/path/to/app/ios/build/generated/ios/ReactAppDependencyProvider';
508+
const expectedCodegenOutputFolder =
509+
'/path/to/app/ios/build/generated/ios/ReactCodegen';
510+
511+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenCalledTimes(2);
512+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenNthCalledWith(
513+
1,
514+
reactNativePath,
515+
appIosPath,
516+
expectedOutputFolder,
517+
'codegen',
518+
);
519+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenNthCalledWith(
520+
2,
521+
reactNativePath,
522+
appIosPath,
523+
expectedCodegenOutputFolder,
524+
'react-native',
525+
);
526+
527+
expect(mockConsoleLog).toHaveBeenCalledWith('Preparing codegen headers...');
528+
expect(mockConsoleLog).toHaveBeenCalledWith('✓ Codegen headers prepared');
529+
expect(mockConsoleLog).toHaveBeenCalledWith(
530+
'Preparing react-native headers...',
531+
);
532+
expect(mockConsoleLog).not.toHaveBeenCalledWith(
533+
'✓ React Native headers prepared',
534+
);
535+
});
536+
537+
it('should throw error when third-party dependencies header preparation fails', async () => {
538+
// Setup
539+
const reactNativePath = '/path/to/react-native';
540+
const appIosPath = '/path/to/app/ios';
541+
const originalError = new Error(
542+
'Third-party dependencies header preparation failed',
543+
);
544+
545+
mockPrepareAppDependenciesHeaders
546+
.mockImplementationOnce(() => {}) // First call succeeds
547+
.mockImplementationOnce(() => {}) // Second call succeeds
548+
.mockImplementationOnce(() => {
549+
// Third call fails
550+
throw originalError;
551+
});
552+
553+
// Execute & Assert
554+
await expect(prepareHeaders(reactNativePath, appIosPath)).rejects.toThrow(
555+
'Header preparation failed: Third-party dependencies header preparation failed',
556+
);
557+
558+
const expectedOutputFolder =
559+
'/path/to/app/ios/build/generated/ios/ReactAppDependencyProvider';
560+
const expectedCodegenOutputFolder =
561+
'/path/to/app/ios/build/generated/ios/ReactCodegen';
562+
563+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenCalledTimes(3);
564+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenNthCalledWith(
565+
1,
566+
reactNativePath,
567+
appIosPath,
568+
expectedOutputFolder,
569+
'codegen',
570+
);
571+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenNthCalledWith(
572+
2,
573+
reactNativePath,
574+
appIosPath,
575+
expectedCodegenOutputFolder,
576+
'react-native',
577+
);
578+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenNthCalledWith(
579+
3,
580+
reactNativePath,
581+
appIosPath,
582+
expectedCodegenOutputFolder,
583+
'third-party-dependencies',
584+
);
585+
586+
expect(mockConsoleLog).toHaveBeenCalledWith('Preparing codegen headers...');
587+
expect(mockConsoleLog).toHaveBeenCalledWith('✓ Codegen headers prepared');
588+
expect(mockConsoleLog).toHaveBeenCalledWith(
589+
'Preparing react-native headers...',
590+
);
591+
expect(mockConsoleLog).toHaveBeenCalledWith(
592+
'✓ React Native headers prepared',
593+
);
594+
expect(mockConsoleLog).toHaveBeenCalledWith(
595+
'Preparing third-party dependencies headers...',
596+
);
597+
expect(mockConsoleLog).not.toHaveBeenCalledWith(
598+
'✓ Third-party dependencies headers prepared',
599+
);
600+
});
601+
602+
it('should handle different paths correctly', async () => {
603+
// Setup
604+
const reactNativePath = '/Users/developer/react-native';
605+
const appIosPath = '/Users/developer/MyApp/ios';
606+
607+
mockPrepareAppDependenciesHeaders.mockImplementation(() => {});
608+
609+
// Execute
610+
await prepareHeaders(reactNativePath, appIosPath);
611+
612+
// Assert
613+
const expectedOutputFolder =
614+
'/Users/developer/MyApp/ios/build/generated/ios/ReactAppDependencyProvider';
615+
const expectedCodegenOutputFolder =
616+
'/Users/developer/MyApp/ios/build/generated/ios/ReactCodegen';
617+
618+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenCalledTimes(3);
619+
620+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenNthCalledWith(
621+
1,
622+
reactNativePath,
623+
appIosPath,
624+
expectedOutputFolder,
625+
'codegen',
626+
);
627+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenNthCalledWith(
628+
2,
629+
reactNativePath,
630+
appIosPath,
631+
expectedCodegenOutputFolder,
632+
'react-native',
633+
);
634+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenNthCalledWith(
635+
3,
636+
reactNativePath,
637+
appIosPath,
638+
expectedCodegenOutputFolder,
639+
'third-party-dependencies',
640+
);
641+
});
642+
643+
it('should handle paths with spaces correctly', async () => {
644+
// Setup
645+
const reactNativePath = '/path/to/react native';
646+
const appIosPath = '/path/to/my app/ios folder';
647+
648+
mockPrepareAppDependenciesHeaders.mockImplementation(() => {});
649+
650+
// Execute
651+
await prepareHeaders(reactNativePath, appIosPath);
652+
653+
// Assert
654+
const expectedOutputFolder =
655+
'/path/to/my app/ios folder/build/generated/ios/ReactAppDependencyProvider';
656+
const expectedCodegenOutputFolder =
657+
'/path/to/my app/ios folder/build/generated/ios/ReactCodegen';
658+
659+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenCalledTimes(3);
660+
661+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenNthCalledWith(
662+
1,
663+
reactNativePath,
664+
appIosPath,
665+
expectedOutputFolder,
666+
'codegen',
667+
);
668+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenNthCalledWith(
669+
2,
670+
reactNativePath,
671+
appIosPath,
672+
expectedCodegenOutputFolder,
673+
'react-native',
674+
);
675+
expect(mockPrepareAppDependenciesHeaders).toHaveBeenNthCalledWith(
676+
3,
677+
reactNativePath,
678+
appIosPath,
679+
expectedCodegenOutputFolder,
680+
'third-party-dependencies',
681+
);
682+
});
683+
});
684+
367685
// Mock console methods - disable React Native's strict console checking
368686
const originalConsole = global.console;
369687

0 commit comments

Comments
 (0)