diff --git a/packages/@expo/fingerprint/src/sourcer/__tests__/Expo-test.ts b/packages/@expo/fingerprint/src/sourcer/__tests__/Expo-test.ts index b21ab5348d7b58..af1da632552c14 100644 --- a/packages/@expo/fingerprint/src/sourcer/__tests__/Expo-test.ts +++ b/packages/@expo/fingerprint/src/sourcer/__tests__/Expo-test.ts @@ -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); @@ -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( + (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( - (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'); @@ -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); @@ -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'); @@ -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); @@ -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( + (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( - (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( + (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( - (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 () => { diff --git a/packages/expo-brownfield/CHANGELOG.md b/packages/expo-brownfield/CHANGELOG.md index 9b4b492d934eb8..41dcc0bd052b75 100644 --- a/packages/expo-brownfield/CHANGELOG.md +++ b/packages/expo-brownfield/CHANGELOG.md @@ -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 diff --git a/packages/expo-brownfield/cli/build/commands/ios/build.js b/packages/expo-brownfield/cli/build/commands/ios/build.js index ab61983f692748..7787fa09a1017c 100644 --- a/packages/expo-brownfield/cli/build/commands/ios/build.js +++ b/packages/expo-brownfield/cli/build/commands/ios/build.js @@ -109,17 +109,17 @@ const packageFrameworks = async (config) => { }; const copyHermesFramework = async (config) => { if (config.dryRun) { - console.log(`Copying hermes XCFramework from ${config.hermesFrameworkPath} to ${config.artifacts}/hermes.xcframework`); + console.log(`Copying hermes XCFramework from ${config.hermesFrameworkPath} to ${config.artifacts}/hermesvm.xcframework`); return; } return (0, utils_1.withSpinner)({ - operation: () => promises_1.default.cp(`./ios/${config.hermesFrameworkPath}`, `${config.artifacts}/hermes.xcframework`, { + operation: () => promises_1.default.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, }); }; diff --git a/packages/expo-brownfield/cli/src/commands/ios/build.ts b/packages/expo-brownfield/cli/src/commands/ios/build.ts index 5f206de8309584..e2f34e6e6dd6da 100644 --- a/packages/expo-brownfield/cli/src/commands/ios/build.ts +++ b/packages/expo-brownfield/cli/src/commands/ios/build.ts @@ -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, }); };