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 'user', 53 '0.11.0' 54 ) 55 ).toMatchObject({ 56 EXUpdatesEnabled: false, 57 EXUpdatesCheckOnLaunch: 'ERROR_RECOVERY_ONLY', 58 EXUpdatesLaunchWaitMs: 2000, 59 EXUpdatesSDKVersion: '37.0.0', 60 EXUpdatesCodeSigningCertificate: fsReal.readFileSync( 61 sampleCodeSigningCertificatePath, 62 'utf-8' 63 ), 64 EXUpdatesCodeSigningMetadata: { alg: 'rsa-v1_5-sha256', keyid: 'test' }, 65 EXUpdatesRequestHeaders: { 'expo-channel-name': 'test', testheader: 'test' }, 66 }); 67 }); 68 69 it('sets the correct values in Expo.plist for useClassicUpdates', () => { 70 vol.fromJSON({ 71 '/app/hello': fsReal.readFileSync(sampleCodeSigningCertificatePath, 'utf-8'), 72 }); 73 74 expect( 75 Updates.setUpdatesConfig( 76 '/app', 77 { 78 sdkVersion: '37.0.0', 79 slug: 'my-app', 80 owner: 'owner', 81 updates: { 82 useClassicUpdates: true, 83 }, 84 }, 85 {} as any, 86 'user', 87 '0.11.0' 88 ) 89 ).toMatchObject({ 90 EXUpdatesEnabled: true, 91 EXUpdatesURL: 'https://exp.host/@owner/my-app', 92 }); 93 }); 94 95 describe(Updates.ensureBundleReactNativePhaseContainsConfigurationScript, () => { 96 beforeEach(() => { 97 vol.reset(); 98 const resolveFrom = require('resolve-from'); 99 resolveFrom.silent = silent; 100 }); 101 102 it("adds create-manifest-ios.sh line to the 'Bundle React Native code and images' build phase ", () => { 103 vol.fromJSON( 104 { 105 'ios/testproject.xcodeproj/project.pbxproj': fsReal.readFileSync( 106 path.join(__dirname, 'fixtures/project-without-create-manifest-ios.pbxproj'), 107 'utf-8' 108 ), 109 'node_modules/expo-updates/scripts/create-manifest-ios.sh': 'whatever', 110 }, 111 '/app' 112 ); 113 114 const xcodeProject = getPbxproj('/app'); 115 Updates.ensureBundleReactNativePhaseContainsConfigurationScript('/app', xcodeProject); 116 const bundleReactNative = Updates.getBundleReactNativePhase(xcodeProject); 117 expect(bundleReactNative.shellScript).toMatchSnapshot(); 118 }); 119 120 it('fixes the path to create-manifest-ios.sh in case of a monorepo', () => { 121 // Pseudo node module resolution since actually mocking it could prove challenging. 122 // In a yarn workspace, resolve-from would be able to locate a module in any node_module folder if properly linked. 123 const resolveFrom = require('resolve-from'); 124 resolveFrom.silent = (p, a) => { 125 return silent(path.join(p, '..'), a); 126 }; 127 128 vol.fromJSON( 129 { 130 'workspace/ios/testproject.xcodeproj/project.pbxproj': fsReal.readFileSync( 131 path.join( 132 __dirname, 133 'fixtures/project-with-incorrect-create-manifest-ios-path.pbxproj' 134 ), 135 'utf-8' 136 ), 137 'node_modules/expo-updates/scripts/create-manifest-ios.sh': 'whatever', 138 }, 139 '/app' 140 ); 141 const xcodeProject = getPbxproj('/app/workspace'); 142 Updates.ensureBundleReactNativePhaseContainsConfigurationScript( 143 '/app/workspace', 144 xcodeProject 145 ); 146 const bundleReactNative = Updates.getBundleReactNativePhase(xcodeProject); 147 expect(bundleReactNative.shellScript).toMatchSnapshot(); 148 }); 149 }); 150}); 151