1082815dcSEvan Baconimport { ExpoConfig } from '@expo/config-types'; 2*42d6b312SCedric van Puttenimport glob from 'glob'; 3082815dcSEvan Baconimport { vol } from 'memfs'; 4*42d6b312SCedric van Puttenimport path from 'path'; 5082815dcSEvan Bacon 6082815dcSEvan Baconimport { withEntitlementsPlist, withInfoPlist } from '../ios-plugins'; 7082815dcSEvan Baconimport { evalModsAsync } from '../mod-compiler'; 8*42d6b312SCedric van Puttenimport { getIosModFileProviders, withIosBaseMods } from '../withIosBaseMods'; 9082815dcSEvan Bacon 10082815dcSEvan Baconjest.mock('fs'); 11*42d6b312SCedric van Puttenjest.mock('glob'); 12082815dcSEvan Bacon 13082815dcSEvan Bacondescribe('entitlements', () => { 14082815dcSEvan Bacon afterEach(() => { 15082815dcSEvan Bacon vol.reset(); 16082815dcSEvan Bacon }); 17082815dcSEvan Bacon 18082815dcSEvan Bacon it(`evaluates in dry run mode`, async () => { 19082815dcSEvan Bacon // Ensure this test runs in a blank file system 20082815dcSEvan Bacon vol.fromJSON({}); 21082815dcSEvan Bacon let config: ExpoConfig = { name: 'bacon', slug: 'bacon' }; 22082815dcSEvan Bacon config = withEntitlementsPlist(config, (config) => { 23082815dcSEvan Bacon config.modResults['haha'] = 'bet'; 24082815dcSEvan Bacon return config; 25082815dcSEvan Bacon }); 26082815dcSEvan Bacon 27082815dcSEvan Bacon // base mods must be added last 28082815dcSEvan Bacon config = withIosBaseMods(config, { 29082815dcSEvan Bacon saveToInternal: true, 30082815dcSEvan Bacon providers: { 31082815dcSEvan Bacon entitlements: { 32082815dcSEvan Bacon getFilePath() { 33082815dcSEvan Bacon return ''; 34082815dcSEvan Bacon }, 35082815dcSEvan Bacon async read() { 36082815dcSEvan Bacon return {}; 37082815dcSEvan Bacon }, 38082815dcSEvan Bacon async write() {}, 39082815dcSEvan Bacon }, 40082815dcSEvan Bacon }, 41082815dcSEvan Bacon }); 42082815dcSEvan Bacon config = await evalModsAsync(config, { projectRoot: '/', platforms: ['ios'] }); 43082815dcSEvan Bacon 44082815dcSEvan Bacon expect(config.ios?.entitlements).toStrictEqual({ 45082815dcSEvan Bacon haha: 'bet', 46082815dcSEvan Bacon }); 47082815dcSEvan Bacon // @ts-ignore: mods are untyped 48082815dcSEvan Bacon expect(config.mods.ios.entitlements).toBeDefined(); 49082815dcSEvan Bacon 50082815dcSEvan Bacon expect(config._internal.modResults.ios.entitlements).toBeDefined(); 51082815dcSEvan Bacon 52082815dcSEvan Bacon // Ensure no files were written 53082815dcSEvan Bacon expect(vol.toJSON()).toStrictEqual({}); 54082815dcSEvan Bacon }); 55*42d6b312SCedric van Putten 56*42d6b312SCedric van Putten it('uses local entitlement files by default', async () => { 57*42d6b312SCedric van Putten // Create a fake project that can load entitlements 58*42d6b312SCedric van Putten vol.fromJSON({ 59*42d6b312SCedric van Putten '/ios/HelloWorld/AppDelegate.mm': 'Fake AppDelegate.mm', 60*42d6b312SCedric van Putten '/ios/HelloWorld.xcodeproj/project.pbxproj': jest 61*42d6b312SCedric van Putten .requireActual<typeof import('fs')>('fs') 62*42d6b312SCedric van Putten .readFileSync( 63*42d6b312SCedric van Putten path.resolve(__dirname, './fixtures/project-files/ios/project.pbxproj'), 64*42d6b312SCedric van Putten 'utf-8' 65*42d6b312SCedric van Putten ), 66*42d6b312SCedric van Putten '/ios/HelloWorld/HelloWorld.entitlements': jest 67*42d6b312SCedric van Putten .requireActual<typeof import('fs')>('fs') 68*42d6b312SCedric van Putten .readFileSync( 69*42d6b312SCedric van Putten path.resolve(__dirname, './fixtures/project-files/ios/project.entitlements'), 70*42d6b312SCedric van Putten 'utf-8' 71*42d6b312SCedric van Putten ), 72*42d6b312SCedric van Putten }); 73*42d6b312SCedric van Putten 74*42d6b312SCedric van Putten // Mock glob response to "find" the memfs files 75*42d6b312SCedric van Putten jest.mocked(glob.sync).mockImplementation((pattern) => { 76*42d6b312SCedric van Putten if (pattern === 'ios/**/*.xcodeproj') return ['/ios/HelloWorld.xcodeproj']; 77*42d6b312SCedric van Putten if (pattern === 'ios/*/AppDelegate.@(m|mm|swift)') return ['/ios/HelloWorld/AppDelegate.mm']; 78*42d6b312SCedric van Putten throw new Error('Unexpected glob pattern used in test'); 79*42d6b312SCedric van Putten }); 80*42d6b312SCedric van Putten 81*42d6b312SCedric van Putten // Create simple project config and config plugin chain 82*42d6b312SCedric van Putten let config: ExpoConfig = { name: 'bacon', slug: 'bacon' }; 83*42d6b312SCedric van Putten config = withEntitlementsPlist(config, (config) => { 84*42d6b312SCedric van Putten config.modResults['haha'] = 'yes'; 85*42d6b312SCedric van Putten return config; 86*42d6b312SCedric van Putten }); 87*42d6b312SCedric van Putten 88*42d6b312SCedric van Putten // Base mod must be added last 89*42d6b312SCedric van Putten config = withIosBaseMods(config, { 90*42d6b312SCedric van Putten saveToInternal: true, 91*42d6b312SCedric van Putten providers: { 92*42d6b312SCedric van Putten // Use the default mod provider, that's the one we need to test 93*42d6b312SCedric van Putten entitlements: getIosModFileProviders().entitlements, 94*42d6b312SCedric van Putten }, 95*42d6b312SCedric van Putten }); 96*42d6b312SCedric van Putten config = await evalModsAsync(config, { 97*42d6b312SCedric van Putten projectRoot: '/', 98*42d6b312SCedric van Putten platforms: ['ios'], 99*42d6b312SCedric van Putten }); 100*42d6b312SCedric van Putten 101*42d6b312SCedric van Putten // Check if the generated entitlements are merged with local entitlements 102*42d6b312SCedric van Putten expect(config.ios?.entitlements).toMatchInlineSnapshot(` 103*42d6b312SCedric van Putten { 104*42d6b312SCedric van Putten "aps-environment": "development", 105*42d6b312SCedric van Putten "com.apple.developer.applesignin": [ 106*42d6b312SCedric van Putten "Default", 107*42d6b312SCedric van Putten ], 108*42d6b312SCedric van Putten "com.apple.developer.associated-domains": [ 109*42d6b312SCedric van Putten "applinks:acme.com", 110*42d6b312SCedric van Putten ], 111*42d6b312SCedric van Putten "com.apple.developer.icloud-container-identifiers": [ 112*42d6b312SCedric van Putten "iCloud.$(CFBundleIdentifier)", 113*42d6b312SCedric van Putten ], 114*42d6b312SCedric van Putten "com.apple.developer.icloud-services": [ 115*42d6b312SCedric van Putten "CloudDocuments", 116*42d6b312SCedric van Putten ], 117*42d6b312SCedric van Putten "com.apple.developer.ubiquity-container-identifiers": [ 118*42d6b312SCedric van Putten "iCloud.$(CFBundleIdentifier)", 119*42d6b312SCedric van Putten ], 120*42d6b312SCedric van Putten "com.apple.developer.ubiquity-kvstore-identifier": "$(TeamIdentifierPrefix)$(CFBundleIdentifier)", 121*42d6b312SCedric van Putten "haha": "yes", 122*42d6b312SCedric van Putten } 123*42d6b312SCedric van Putten `); 124*42d6b312SCedric van Putten }); 125*42d6b312SCedric van Putten 126*42d6b312SCedric van Putten it('skips local entitlements files when ignoring existing native files', async () => { 127*42d6b312SCedric van Putten // Create a fake project that can load entitlements 128*42d6b312SCedric van Putten vol.fromJSON({ 129*42d6b312SCedric van Putten '/ios/HelloWorld/AppDelegate.mm': 'Fake AppDelegate.mm', 130*42d6b312SCedric van Putten '/ios/HelloWorld.xcodeproj/project.pbxproj': jest 131*42d6b312SCedric van Putten .requireActual<typeof import('fs')>('fs') 132*42d6b312SCedric van Putten .readFileSync( 133*42d6b312SCedric van Putten path.resolve(__dirname, './fixtures/project-files/ios/project.pbxproj'), 134*42d6b312SCedric van Putten 'utf-8' 135*42d6b312SCedric van Putten ), 136*42d6b312SCedric van Putten '/ios/HelloWorld/HelloWorld.entitlements': jest 137*42d6b312SCedric van Putten .requireActual<typeof import('fs')>('fs') 138*42d6b312SCedric van Putten .readFileSync( 139*42d6b312SCedric van Putten path.resolve(__dirname, './fixtures/project-files/ios/project.entitlements'), 140*42d6b312SCedric van Putten 'utf-8' 141*42d6b312SCedric van Putten ), 142*42d6b312SCedric van Putten }); 143*42d6b312SCedric van Putten 144*42d6b312SCedric van Putten // Mock glob response to "find" the memfs files 145*42d6b312SCedric van Putten jest.mocked(glob.sync).mockImplementation((pattern) => { 146*42d6b312SCedric van Putten if (pattern === 'ios/**/*.xcodeproj') return ['/ios/HelloWorld.xcodeproj']; 147*42d6b312SCedric van Putten if (pattern === 'ios/*/AppDelegate.@(m|mm|swift)') return ['/ios/HelloWorld/AppDelegate.mm']; 148*42d6b312SCedric van Putten throw new Error('Unexpected glob pattern used in test'); 149*42d6b312SCedric van Putten }); 150*42d6b312SCedric van Putten 151*42d6b312SCedric van Putten // Create simple project config and config plugin chain 152*42d6b312SCedric van Putten let config: ExpoConfig = { name: 'bacon', slug: 'bacon' }; 153*42d6b312SCedric van Putten config = withEntitlementsPlist(config, (config) => { 154*42d6b312SCedric van Putten config.modResults['haha'] = 'yes'; 155*42d6b312SCedric van Putten return config; 156*42d6b312SCedric van Putten }); 157*42d6b312SCedric van Putten 158*42d6b312SCedric van Putten // Base mod must be added last 159*42d6b312SCedric van Putten config = withIosBaseMods(config, { 160*42d6b312SCedric van Putten saveToInternal: true, 161*42d6b312SCedric van Putten providers: { 162*42d6b312SCedric van Putten // Use the default mod provider, that's the one we need to test 163*42d6b312SCedric van Putten entitlements: getIosModFileProviders().entitlements, 164*42d6b312SCedric van Putten }, 165*42d6b312SCedric van Putten }); 166*42d6b312SCedric van Putten config = await evalModsAsync(config, { 167*42d6b312SCedric van Putten projectRoot: '/', 168*42d6b312SCedric van Putten platforms: ['ios'], 169*42d6b312SCedric van Putten ignoreExistingNativeFiles: true, 170*42d6b312SCedric van Putten }); 171*42d6b312SCedric van Putten 172*42d6b312SCedric van Putten // Check if the generated entitlements are NOT merged with local entitlements 173*42d6b312SCedric van Putten expect(config.ios?.entitlements).toMatchInlineSnapshot(` 174*42d6b312SCedric van Putten { 175*42d6b312SCedric van Putten "haha": "yes", 176*42d6b312SCedric van Putten } 177*42d6b312SCedric van Putten `); 178*42d6b312SCedric van Putten }); 179082815dcSEvan Bacon}); 180082815dcSEvan Bacon 181082815dcSEvan Bacondescribe('infoPlist', () => { 182082815dcSEvan Bacon afterEach(() => { 183082815dcSEvan Bacon vol.reset(); 184082815dcSEvan Bacon }); 185082815dcSEvan Bacon 186082815dcSEvan Bacon it(`evaluates in dry run mode`, async () => { 187082815dcSEvan Bacon // Ensure this test runs in a blank file system 188082815dcSEvan Bacon vol.fromJSON({}); 189082815dcSEvan Bacon let config: ExpoConfig = { name: 'bacon', slug: 'bacon' }; 190082815dcSEvan Bacon config = withInfoPlist(config, (config) => { 191082815dcSEvan Bacon config.modResults['haha'] = 'bet'; 192082815dcSEvan Bacon return config; 193082815dcSEvan Bacon }); 194082815dcSEvan Bacon 195082815dcSEvan Bacon // base mods must be added last 196082815dcSEvan Bacon config = withIosBaseMods(config, { 197082815dcSEvan Bacon saveToInternal: true, 198082815dcSEvan Bacon providers: { 199082815dcSEvan Bacon infoPlist: { 200082815dcSEvan Bacon getFilePath() { 201082815dcSEvan Bacon return ''; 202082815dcSEvan Bacon }, 203082815dcSEvan Bacon async read() { 204082815dcSEvan Bacon return {}; 205082815dcSEvan Bacon }, 206082815dcSEvan Bacon async write() {}, 207082815dcSEvan Bacon }, 208082815dcSEvan Bacon }, 209082815dcSEvan Bacon }); 210082815dcSEvan Bacon config = await evalModsAsync(config, { projectRoot: '/', platforms: ['ios'] }); 211082815dcSEvan Bacon 212082815dcSEvan Bacon expect(config.ios?.infoPlist).toStrictEqual({ 213082815dcSEvan Bacon haha: 'bet', 214082815dcSEvan Bacon }); 215082815dcSEvan Bacon // @ts-ignore: mods are untyped 216082815dcSEvan Bacon expect(config.mods.ios.infoPlist).toBeDefined(); 217082815dcSEvan Bacon 218082815dcSEvan Bacon expect(config._internal.modResults.ios.infoPlist).toBeDefined(); 219082815dcSEvan Bacon 220082815dcSEvan Bacon // Ensure no files were written 221082815dcSEvan Bacon expect(vol.toJSON()).toStrictEqual({}); 222082815dcSEvan Bacon }); 223082815dcSEvan Bacon}); 224