Skip to content
Merged
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
198 changes: 97 additions & 101 deletions packages/@expo/fingerprint/src/sourcer/__tests__/Expo-test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@ jest.mock('../../ExpoResolver');
jest.mock('../../ProjectWorkflow');
jest.mock('../../utils/SpawnIPC');

/** Write a placeholder file to memfs (for `fs.existsSync`) and register a Jest virtual mock (for `require()`). */
function mockConfigFile(filePath: string, factory: () => any) {
vol.writeFileSync(filePath, '');
jest.doMock(filePath, factory, { virtual: true });
}

// NOTE(cedric): this is a workaround to also mock `node:fs`
jest.mock('node:fs', () => require('memfs').fs);

Expand Down Expand Up @@ -410,45 +416,43 @@ describe(`getExpoConfigSourcesAsync - sourceSkips`, () => {
});

it('should not container version when SourceSkips.ExpoConfigVersions', async () => {
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
vol.writeFileSync(
'/app/app.config.js',
`\
export default ({ config }) => {
config.android = { versionCode: 1 };
config.ios = { buildNumber: '1' };
return config;
};`
);
await jest.isolateModulesAsync(async () => {
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
mockConfigFile('/app/app.config.js', () => ({
default: ({ config }: any) => {
config.android = { versionCode: 1 };
config.ios = { buildNumber: '1' };
return config;
},
}));

const options = await normalizeOptionsAsync('/app', {
sourceSkips: SourceSkips.ExpoConfigVersions,
const options = await normalizeOptionsAsync('/app', {
sourceSkips: SourceSkips.ExpoConfigVersions,
});
const { config, loadedModules } = await getExpoConfigAsync('/app', options);
const sources = await getExpoConfigSourcesAsync('/app', config, loadedModules, options);
const expoConfigSource = sources.find<HashSourceContents>(
(source): source is HashSourceContents =>
source.type === 'contents' && source.id === 'expoConfig'
);
const expoConfig = JSON.parse(expoConfigSource?.contents?.toString() ?? 'null');
expect(expoConfig).not.toBeNull();
expect(expoConfig.version).toBeUndefined();
expect(expoConfig.android.versionCode).toBeUndefined();
expect(expoConfig.ios.buildNumber).toBeUndefined();
});
const { config, loadedModules } = await getExpoConfigAsync('/app', options);
const sources = await getExpoConfigSourcesAsync('/app', config, loadedModules, options);
const expoConfigSource = sources.find<HashSourceContents>(
(source): source is HashSourceContents =>
source.type === 'contents' && source.id === 'expoConfig'
);
const expoConfig = JSON.parse(expoConfigSource?.contents?.toString() ?? 'null');
expect(expoConfig).not.toBeNull();
expect(expoConfig.version).toBeUndefined();
expect(expoConfig.android.versionCode).toBeUndefined();
expect(expoConfig.ios.buildNumber).toBeUndefined();
});

it('should support sourceSkips from config', async () => {
await jest.isolateModulesAsync(async () => {
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
vol.writeFileSync(
'/app/app.config.js',
`\
export default ({ config }) => {
config.android = { versionCode: 1, package: 'com.example.app' };
config.ios = { buildNumber: '1', bundleIdentifier: 'com.example.app' };
return config;
};`
);
mockConfigFile('/app/app.config.js', () => ({
default: ({ config }: any) => {
config.android = { versionCode: 1, package: 'com.example.app' };
config.ios = { buildNumber: '1', bundleIdentifier: 'com.example.app' };
return config;
},
}));

const configContents = `\
const { SourceSkips } = require('@expo/fingerprint');
Expand All @@ -458,10 +462,7 @@ const config = {
};
module.exports = config;
`;
vol.writeFileSync('/app/fingerprint.config.js', configContents);
jest.doMock('/app/fingerprint.config.js', () => requireString(configContents), {
virtual: true,
});
mockConfigFile('/app/fingerprint.config.js', () => requireString(configContents));

const options = await normalizeOptionsAsync('/app');
const { config, loadedModules } = await getExpoConfigAsync('/app', options);
Expand All @@ -483,15 +484,13 @@ module.exports = config;
it('should support sourceSkips specified as string array in config', async () => {
await jest.isolateModulesAsync(async () => {
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
vol.writeFileSync(
'/app/app.config.js',
`\
export default ({ config }) => {
config.android = { versionCode: 1, package: 'com.example.app' };
config.ios = { buildNumber: '1', bundleIdentifier: 'com.example.app' };
return config;
};`
);
mockConfigFile('/app/app.config.js', () => ({
default: ({ config }: any) => {
config.android = { versionCode: 1, package: 'com.example.app' };
config.ios = { buildNumber: '1', bundleIdentifier: 'com.example.app' };
return config;
},
}));

const configContents = `\
const { SourceSkips } = require('@expo/fingerprint');
Expand All @@ -501,10 +500,7 @@ const config = {
};
module.exports = config;
`;
vol.writeFileSync('/app/fingerprint.config.js', configContents);
jest.doMock('/app/fingerprint.config.js', () => requireString(configContents), {
virtual: true,
});
mockConfigFile('/app/fingerprint.config.js', () => requireString(configContents));

const options = await normalizeOptionsAsync('/app');
const { config, loadedModules } = await getExpoConfigAsync('/app', options);
Expand All @@ -524,63 +520,63 @@ module.exports = config;
});

it('should not contain runtimeVersion when SourceSkips.ExpoConfigRuntimeVersionIfString and runtime version is a string', async () => {
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
vol.writeFileSync(
'/app/app.config.js',
`\
export default ({ config }) => {
config.runtimeVersion = '1.0.0';
config.ios = { runtimeVersion: '1.0.0' };
config.android = { runtimeVersion: '1.0.0' };
config.web = { runtimeVersion: '1.0.0' };
return config;
};`
);
const options = await normalizeOptionsAsync('/app', {
sourceSkips: SourceSkips.ExpoConfigRuntimeVersionIfString,
await jest.isolateModulesAsync(async () => {
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
mockConfigFile('/app/app.config.js', () => ({
default: ({ config }: any) => {
config.runtimeVersion = '1.0.0';
config.ios = { runtimeVersion: '1.0.0' };
config.android = { runtimeVersion: '1.0.0' };
config.web = { runtimeVersion: '1.0.0' };
return config;
},
}));
const options = await normalizeOptionsAsync('/app', {
sourceSkips: SourceSkips.ExpoConfigRuntimeVersionIfString,
});
const { config, loadedModules } = await getExpoConfigAsync('/app', options);
const sources = await getExpoConfigSourcesAsync('/app', config, loadedModules, options);
const expoConfigSource = sources.find<HashSourceContents>(
(source): source is HashSourceContents =>
source.type === 'contents' && source.id === 'expoConfig'
);
const expoConfig = JSON.parse(expoConfigSource?.contents?.toString() ?? 'null');
expect(expoConfig).not.toBeNull();
expect(expoConfig.runtimeVersion).toBeUndefined();
expect(expoConfig.android.runtimeVersion).toBeUndefined();
expect(expoConfig.ios.runtimeVersion).toBeUndefined();
expect(expoConfig.web.runtimeVersion).toBeUndefined();
});
const { config, loadedModules } = await getExpoConfigAsync('/app', options);
const sources = await getExpoConfigSourcesAsync('/app', config, loadedModules, options);
const expoConfigSource = sources.find<HashSourceContents>(
(source): source is HashSourceContents =>
source.type === 'contents' && source.id === 'expoConfig'
);
const expoConfig = JSON.parse(expoConfigSource?.contents?.toString() ?? 'null');
expect(expoConfig).not.toBeNull();
expect(expoConfig.runtimeVersion).toBeUndefined();
expect(expoConfig.android.runtimeVersion).toBeUndefined();
expect(expoConfig.ios.runtimeVersion).toBeUndefined();
expect(expoConfig.web.runtimeVersion).toBeUndefined();
});

it('should keep runtimeVersion when SourceSkips.ExpoConfigRuntimeVersionIfString and runtime version is a policy', async () => {
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
vol.writeFileSync(
'/app/app.config.js',
`\
export default ({ config }) => {
config.runtimeVersion = { policy: 'test' };
config.ios = { runtimeVersion: { policy: 'test' } };
config.android = { runtimeVersion: { policy: 'test' } };
config.web = { runtimeVersion: { policy: 'test' } };
return config;
};`
);
const options = await normalizeOptionsAsync('/app', {
sourceSkips: SourceSkips.ExpoConfigRuntimeVersionIfString,
await jest.isolateModulesAsync(async () => {
vol.fromJSON(require('./fixtures/ExpoManaged47Project.json'));
mockConfigFile('/app/app.config.js', () => ({
default: ({ config }: any) => {
config.runtimeVersion = { policy: 'test' };
config.ios = { runtimeVersion: { policy: 'test' } };
config.android = { runtimeVersion: { policy: 'test' } };
config.web = { runtimeVersion: { policy: 'test' } };
return config;
},
}));
const options = await normalizeOptionsAsync('/app', {
sourceSkips: SourceSkips.ExpoConfigRuntimeVersionIfString,
});
const { config, loadedModules } = await getExpoConfigAsync('/app', options);
const sources = await getExpoConfigSourcesAsync('/app', config, loadedModules, options);
const expoConfigSource = sources.find<HashSourceContents>(
(source): source is HashSourceContents =>
source.type === 'contents' && source.id === 'expoConfig'
);
const expoConfig = JSON.parse(expoConfigSource?.contents?.toString() ?? 'null');
expect(expoConfig).not.toBeNull();
expect(expoConfig.runtimeVersion).toMatchObject({ policy: 'test' });
expect(expoConfig.android.runtimeVersion).toMatchObject({ policy: 'test' });
expect(expoConfig.ios.runtimeVersion).toMatchObject({ policy: 'test' });
expect(expoConfig.web.runtimeVersion).toMatchObject({ policy: 'test' });
});
const { config, loadedModules } = await getExpoConfigAsync('/app', options);
const sources = await getExpoConfigSourcesAsync('/app', config, loadedModules, options);
const expoConfigSource = sources.find<HashSourceContents>(
(source): source is HashSourceContents =>
source.type === 'contents' && source.id === 'expoConfig'
);
const expoConfig = JSON.parse(expoConfigSource?.contents?.toString() ?? 'null');
expect(expoConfig).not.toBeNull();
expect(expoConfig.runtimeVersion).toMatchObject({ policy: 'test' });
expect(expoConfig.android.runtimeVersion).toMatchObject({ policy: 'test' });
expect(expoConfig.ios.runtimeVersion).toMatchObject({ policy: 'test' });
expect(expoConfig.web.runtimeVersion).toMatchObject({ policy: 'test' });
});

it('should skip external icon files when SourceSkips.ExpoConfigAssets', async () => {
Expand Down
2 changes: 2 additions & 0 deletions packages/expo-brownfield/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

### 🛠 Breaking changes

- [cli] update copied hermes framework name to hermesvm.xcframework ([#43138](https://github.com/expo/expo/pull/43138) by [@pmleczek](https://github.com/pmleczek))

### 🎉 New features

### 🐛 Bug fixes
Expand Down
10 changes: 5 additions & 5 deletions packages/expo-brownfield/cli/build/commands/ios/build.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 5 additions & 5 deletions packages/expo-brownfield/cli/src/commands/ios/build.ts
Original file line number Diff line number Diff line change
Expand Up @@ -135,20 +135,20 @@ const packageFrameworks = async (config: BuildConfigIos) => {
const copyHermesFramework = async (config: BuildConfigIos) => {
if (config.dryRun) {
console.log(
`Copying hermes XCFramework from ${config.hermesFrameworkPath} to ${config.artifacts}/hermes.xcframework`
`Copying hermes XCFramework from ${config.hermesFrameworkPath} to ${config.artifacts}/hermesvm.xcframework`
);
return;
}

return withSpinner({
operation: () =>
fs.cp(`./ios/${config.hermesFrameworkPath}`, `${config.artifacts}/hermes.xcframework`, {
fs.cp(`./ios/${config.hermesFrameworkPath}`, `${config.artifacts}/hermesvm.xcframework`, {
force: true,
recursive: true,
}),
loaderMessage: 'Copying hermes.xcframework to the artifacts directory...',
successMessage: 'Copying hermes.xcframework to the artifacts directory succeeded',
errorMessage: 'Copying hermes.xcframework to the artifacts directory failed',
loaderMessage: 'Copying hermesvm.xcframework to the artifacts directory...',
successMessage: 'Copying hermesvm.xcframework to the artifacts directory succeeded',
errorMessage: 'Copying hermesvm.xcframework to the artifacts directory failed',
verbose: config.verbose,
});
};
Loading