Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
import xcodeEnv from '../xcodeEnv';
import {NoopLoader} from '@react-native-community/cli-tools';
import {findPodfilePaths} from '@react-native-community/cli-platform-apple';
import fs from 'fs';

jest.mock('@react-native-community/cli-platform-apple', () => ({
findPodfilePaths: jest.fn(),
}));

jest.mock('@react-native-community/cli-tools', () => {
const actual = jest.requireActual('@react-native-community/cli-tools');
return {
...actual,
findProjectRoot: jest.fn(() => '/project'),
resolveNodeModuleDir: jest.fn(
() => '/project/node_modules/react-native/template/ios',
),
};
});

jest.mock('fs', () => ({
existsSync: jest.fn(() => false),
copyFile: jest.fn(),
}));

const config: any = {
root: '/project',
project: {ios: {sourceDir: '/project/ios'}},
};

describe('xcodeEnv healthcheck runAutomaticFix', () => {
beforeEach(() => {
jest.clearAllMocks();
(fs.existsSync as jest.Mock).mockReturnValue(false);
});

it('waits for every .xcode.env copy to finish before reporting success', async () => {
(findPodfilePaths as jest.Mock).mockReturnValue([
'Podfile',
'nested/Podfile',
]);

const completed: string[] = [];
(fs.copyFile as unknown as jest.Mock).mockImplementation(
(_src: string, dest: string, callback: (err: Error | null) => void) => {
setTimeout(() => {
completed.push(dest);
callback(null);
}, 10);
},
);

const loader = new NoopLoader();
const succeed = jest.spyOn(loader, 'succeed');

await xcodeEnv.runAutomaticFix({loader, config} as any);

// Both copies must have actually finished by the time the fix resolves.
expect(completed).toHaveLength(2);
expect(succeed).toHaveBeenCalled();
});

it('fails the loader when a copy rejects instead of reporting success', async () => {
(findPodfilePaths as jest.Mock).mockReturnValue(['Podfile']);

(fs.copyFile as unknown as jest.Mock).mockImplementation(
(_src: string, _dest: string, callback: (err: Error | null) => void) => {
setTimeout(() => callback(new Error('EACCES: permission denied')), 10);
},
);

const loader = new NoopLoader();
const succeed = jest.spyOn(loader, 'succeed');
const fail = jest.spyOn(loader, 'fail');

await xcodeEnv.runAutomaticFix({loader, config} as any);

expect(fail).toHaveBeenCalled();
expect(succeed).not.toHaveBeenCalled();
});

it('does not copy over an existing .xcode.env file', async () => {
(findPodfilePaths as jest.Mock).mockReturnValue([
'Podfile',
'nested/Podfile',
]);
(fs.existsSync as jest.Mock).mockImplementation((p: string) =>
p.startsWith('/project/ios/nested'),
);
(fs.copyFile as unknown as jest.Mock).mockImplementation(
(_src: string, _dest: string, callback: (err: Error | null) => void) =>
callback(null),
);

const loader = new NoopLoader();
await xcodeEnv.runAutomaticFix({loader, config} as any);

expect(fs.copyFile).toHaveBeenCalledTimes(1);
expect((fs.copyFile as unknown as jest.Mock).mock.calls[0][1]).toBe(
'/project/ios/.xcode.env',
);
});
});
22 changes: 12 additions & 10 deletions packages/cli-doctor/src/tools/healthchecks/xcodeEnv.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,18 @@ export default {

const iosFolderPath = config?.project.ios?.sourceDir ?? '';

findPodfilePaths(iosFolderPath)
.map((podfilePath) =>
removeLastPathComponent(path.join(iosFolderPath, podfilePath)),
)
// avoid overriding existing .xcode.env
.filter(pathDoesNotHaveXcodeEnvFile)
.forEach(async (pathString: string) => {
const destFilePath = path.join(pathString, xcodeEnvFile);
await copyFileAsync(src, destFilePath);
});
await Promise.all(
findPodfilePaths(iosFolderPath)
.map((podfilePath) =>
removeLastPathComponent(path.join(iosFolderPath, podfilePath)),
)
// avoid overriding existing .xcode.env
.filter(pathDoesNotHaveXcodeEnvFile)
.map((pathString: string) => {
const destFilePath = path.join(pathString, xcodeEnvFile);
return copyFileAsync(src, destFilePath);
}),
);
loader.succeed('.xcode.env file have been created!');
} catch (e) {
loader.fail(e as any);
Expand Down
Loading