1import fs from 'fs'; 2import { vol } from 'memfs'; 3import path from 'path'; 4 5import * as Updates from '../Updates'; 6import { getPbxproj } from '../utils/Xcodeproj'; 7 8const fsReal = jest.requireActual('fs') as typeof fs; 9jest.mock('fs'); 10jest.mock('resolve-from'); 11 12const { silent } = require('resolve-from'); 13 14const fixturesPath = path.resolve(__dirname, 'fixtures'); 15const sampleCodeSigningCertificatePath = path.resolve(fixturesPath, 'codeSigningCertificate.pem'); 16 17describe('iOS Updates config', () => { 18 beforeEach(() => { 19 const resolveFrom = require('resolve-from'); 20 resolveFrom.silent = silent; 21 vol.reset(); 22 }); 23 24 it('sets the correct values in Expo.plist', () => { 25 vol.fromJSON({ 26 '/app/hello': fsReal.readFileSync(sampleCodeSigningCertificatePath, 'utf-8'), 27 }); 28 29 expect( 30 Updates.setUpdatesConfig( 31 '/app', 32 { 33 sdkVersion: '37.0.0', 34 slug: 'my-app', 35 owner: 'owner', 36 updates: { 37 enabled: false, 38 fallbackToCacheTimeout: 2000, 39 checkAutomatically: 'ON_ERROR_RECOVERY', 40 codeSigningCertificate: 'hello', 41 codeSigningMetadata: { 42 alg: 'rsa-v1_5-sha256', 43 keyid: 'test', 44 }, 45 requestHeaders: { 46 'expo-channel-name': 'test', 47 testheader: 'test', 48 }, 49 }, 50 }, 51 {} as any, 52 '0.11.0' 53 ) 54 ).toMatchObject({ 55 EXUpdatesEnabled: false, 56 EXUpdatesCheckOnLaunch: 'ERROR_RECOVERY_ONLY', 57 EXUpdatesLaunchWaitMs: 2000, 58 EXUpdatesSDKVersion: '37.0.0', 59 EXUpdatesCodeSigningCertificate: fsReal.readFileSync( 60 sampleCodeSigningCertificatePath, 61 'utf-8' 62 ), 63 EXUpdatesCodeSigningMetadata: { alg: 'rsa-v1_5-sha256', keyid: 'test' }, 64 EXUpdatesRequestHeaders: { 'expo-channel-name': 'test', testheader: 'test' }, 65 }); 66 }); 67 68 describe(Updates.ensureBundleReactNativePhaseContainsConfigurationScript, () => { 69 beforeEach(() => { 70 vol.reset(); 71 const resolveFrom = require('resolve-from'); 72 resolveFrom.silent = silent; 73 }); 74 75 it("adds create-manifest-ios.sh line to the 'Bundle React Native code and images' build phase ", () => { 76 vol.fromJSON( 77 { 78 'ios/testproject.xcodeproj/project.pbxproj': fsReal.readFileSync( 79 path.join(__dirname, 'fixtures/project-without-create-manifest-ios.pbxproj'), 80 'utf-8' 81 ), 82 'node_modules/expo-updates/scripts/create-manifest-ios.sh': 'whatever', 83 }, 84 '/app' 85 ); 86 87 const xcodeProject = getPbxproj('/app'); 88 Updates.ensureBundleReactNativePhaseContainsConfigurationScript('/app', xcodeProject); 89 const bundleReactNative = Updates.getBundleReactNativePhase(xcodeProject); 90 expect(bundleReactNative.shellScript).toMatchSnapshot(); 91 }); 92 93 it('fixes the path to create-manifest-ios.sh in case of a monorepo', () => { 94 // Pseudo node module resolution since actually mocking it could prove challenging. 95 // In a yarn workspace, resolve-from would be able to locate a module in any node_module folder if properly linked. 96 const resolveFrom = require('resolve-from'); 97 resolveFrom.silent = (p, a) => { 98 return silent(path.join(p, '..'), a); 99 }; 100 101 vol.fromJSON( 102 { 103 'workspace/ios/testproject.xcodeproj/project.pbxproj': fsReal.readFileSync( 104 path.join( 105 __dirname, 106 'fixtures/project-with-incorrect-create-manifest-ios-path.pbxproj' 107 ), 108 'utf-8' 109 ), 110 'node_modules/expo-updates/scripts/create-manifest-ios.sh': 'whatever', 111 }, 112 '/app' 113 ); 114 const xcodeProject = getPbxproj('/app/workspace'); 115 Updates.ensureBundleReactNativePhaseContainsConfigurationScript( 116 '/app/workspace', 117 xcodeProject 118 ); 119 const bundleReactNative = Updates.getBundleReactNativePhase(xcodeProject); 120 expect(bundleReactNative.shellScript).toMatchSnapshot(); 121 }); 122 }); 123}); 124