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