1import { ExpoConfig } from '@expo/config-types'; 2import { fs as memfs, vol } from 'memfs'; 3import path from 'path'; 4 5import rnFixture from '../../plugins/__tests__/fixtures/react-native-project'; 6import { 7 getBundleIdentifier, 8 getBundleIdentifierFromPbxproj, 9 setBundleIdentifier, 10 setBundleIdentifierForPbxproj, 11} from '../BundleIdentifier'; 12 13const baseExpoConfig: ExpoConfig = { 14 name: 'testproject', 15 slug: 'testproject', 16 platforms: ['ios'], 17 version: '1.0.0', 18}; 19 20jest.mock('fs'); 21 22const originalFs = jest.requireActual('fs'); 23 24describe('BundleIdentifier module', () => { 25 describe(getBundleIdentifier, () => { 26 it('returns null if no bundleIdentifier is provided', () => { 27 expect(getBundleIdentifier(baseExpoConfig)).toBe(null); 28 }); 29 30 it('returns the bundleIdentifier if provided', () => { 31 expect( 32 getBundleIdentifier({ ...baseExpoConfig, ios: { bundleIdentifier: 'com.example.xyz' } }) 33 ).toBe('com.example.xyz'); 34 }); 35 }); 36 37 describe(getBundleIdentifierFromPbxproj, () => { 38 const projectRoot = '/testproject'; 39 40 afterEach(() => vol.reset()); 41 42 it('returns null if no project.pbxproj exists', () => { 43 vol.mkdirpSync(projectRoot); 44 const bundleId = getBundleIdentifierFromPbxproj(projectRoot, { targetName: 'testproject' }); 45 expect(bundleId).toBeNull(); 46 }); 47 48 it('returns the bundle identifier defined in project.pbxproj', () => { 49 vol.fromJSON( 50 { 51 'ios/HelloWorld.xcodeproj/project.pbxproj': 52 rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'], 53 }, 54 projectRoot 55 ); 56 const bundleId = getBundleIdentifierFromPbxproj(projectRoot, { targetName: 'HelloWorld' }); 57 expect(bundleId).toBe('org.name.HelloWorld'); 58 }); 59 60 describe('multi-target project', () => { 61 it('returns correct bundle identifier for the default build configuration (Release)', () => { 62 vol.fromJSON( 63 { 64 'ios/testproject.xcodeproj/project.pbxproj': originalFs.readFileSync( 65 path.join(__dirname, 'fixtures/project-multitarget.pbxproj'), 66 'utf-8' 67 ), 68 'ios/testproject.xcodeproj/xcshareddata/xcschemes/multitarget.xcscheme': 69 originalFs.readFileSync( 70 path.join(__dirname, 'fixtures/multitarget.xcscheme'), 71 'utf-8' 72 ), 73 }, 74 projectRoot 75 ); 76 const bundleId = getBundleIdentifierFromPbxproj(projectRoot, { 77 targetName: 'multitarget', 78 }); 79 expect(bundleId).toBe('com.swmansion.dominik.multitarget'); 80 }); 81 82 it('returns correct bundle identifier for Debug build configuration', () => { 83 vol.fromJSON( 84 { 85 'ios/testproject.xcodeproj/project.pbxproj': originalFs.readFileSync( 86 path.join(__dirname, 'fixtures/project-multitarget.pbxproj'), 87 'utf-8' 88 ), 89 'ios/testproject.xcodeproj/xcshareddata/xcschemes/multitarget.xcscheme': 90 originalFs.readFileSync( 91 path.join(__dirname, 'fixtures/multitarget.xcscheme'), 92 'utf-8' 93 ), 94 }, 95 projectRoot 96 ); 97 const bundleId = getBundleIdentifierFromPbxproj(projectRoot, { 98 targetName: 'multitarget', 99 buildConfiguration: 'Debug', 100 }); 101 expect(bundleId).toBe('com.swmansion.dominik.multitarget.debug'); 102 }); 103 }); 104 }); 105 106 describe(setBundleIdentifier, () => { 107 it('sets the CFBundleShortVersionString if bundleIdentifier is given', () => { 108 expect( 109 setBundleIdentifier( 110 { ...baseExpoConfig, ios: { bundleIdentifier: 'host.exp.exponent' } }, 111 {} 112 ) 113 ).toMatchObject({ 114 CFBundleIdentifier: 'host.exp.exponent', 115 }); 116 }); 117 118 it('makes no changes to the infoPlist no bundleIdentifier is provided', () => { 119 expect(setBundleIdentifier(baseExpoConfig, {})).toMatchObject({}); 120 }); 121 }); 122 123 describe(setBundleIdentifierForPbxproj, () => { 124 const projectRoot = '/testproject'; 125 const pbxProjPath = 'ios/testproject.xcodeproj/project.pbxproj'; 126 const otherPbxProjPath = 'ios/otherproject.xcodeproj/project.pbxproj'; 127 128 beforeEach(() => { 129 vol.fromJSON( 130 { 131 [pbxProjPath]: rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'], 132 [otherPbxProjPath]: rnFixture['ios/HelloWorld.xcodeproj/project.pbxproj'], 133 }, 134 projectRoot 135 ); 136 }); 137 afterEach(() => vol.reset()); 138 139 it('sets the bundle identifier in the pbxproj file', () => { 140 setBundleIdentifierForPbxproj(projectRoot, 'com.swmansion.dominik.abcd.v2'); 141 const pbxprojContents = memfs.readFileSync(path.join(projectRoot, pbxProjPath), 'utf-8'); 142 const otherPbxprojContents = memfs.readFileSync( 143 path.join(projectRoot, otherPbxProjPath), 144 'utf-8' 145 ); 146 expect(pbxprojContents).toMatchSnapshot(); 147 // Ensure all paths are modified 148 expect(pbxprojContents).toBe(otherPbxprojContents); 149 }); 150 }); 151}); 152