1import { ExpoConfig } from '@expo/config-types'; 2import { vol } from 'memfs'; 3 4import { addWarningIOS } from '../../utils/warnings'; 5import { createInfoPlistPluginWithPropertyGuard } from '../ios-plugins'; 6import { evalModsAsync } from '../mod-compiler'; 7import { getIosModFileProviders, withIosBaseMods } from '../withIosBaseMods'; 8import rnFixture from './fixtures/react-native-project'; 9 10jest.mock('../../utils/warnings', () => ({ 11 addWarningIOS: jest.fn(), 12})); 13 14jest.mock('fs'); 15 16export const asMock = <T extends (...args: any[]) => any>(fn: T): jest.MockedFunction<T> => 17 fn as jest.MockedFunction<T>; 18describe(createInfoPlistPluginWithPropertyGuard, () => { 19 const projectRoot = '/app'; 20 21 beforeEach(async () => { 22 asMock(addWarningIOS).mockClear(); 23 vol.fromJSON(rnFixture, projectRoot); 24 }); 25 26 afterEach(() => { 27 vol.reset(); 28 }); 29 30 it(`respects info plist manual values`, async () => { 31 const setter = jest.fn(); 32 const withPlugin = createInfoPlistPluginWithPropertyGuard(setter, { 33 infoPlistProperty: 'CFFakeValue', 34 // Supports nesting 35 expoConfigProperty: 'ios.appStoreUrl', 36 }); 37 38 let config: ExpoConfig = { 39 name: 'hey', 40 slug: '', 41 ios: { 42 appStoreUrl: 'underlying', 43 infoPlist: { 44 CFFakeValue: false, 45 }, 46 }, 47 }; 48 49 config = withPlugin(config); 50 51 config = withIosBaseMods(config, { 52 providers: { 53 infoPlist: getIosModFileProviders().infoPlist, 54 }, 55 }); 56 57 const results = await evalModsAsync(config, { 58 projectRoot, 59 platforms: ['ios'], 60 introspect: true, 61 assertMissingModProviders: true, 62 }); 63 64 expect(results.ios.infoPlist.CFFakeValue).toEqual(false); 65 66 expect(setter).not.toBeCalled(); 67 expect(addWarningIOS).toBeCalledWith( 68 'ios.appStoreUrl', 69 '"ios.infoPlist.CFFakeValue" is set in the config. Ignoring abstract property "ios.appStoreUrl": underlying' 70 ); 71 }); 72 73 it(`does not warn about info plist overrides if the abstract value is not defined`, async () => { 74 const setter = jest.fn(); 75 const withPlugin = createInfoPlistPluginWithPropertyGuard(setter, { 76 infoPlistProperty: 'CFFakeValue', 77 expoConfigProperty: 'foobar', 78 }); 79 80 let config: ExpoConfig = { 81 name: 'hey', 82 slug: '', 83 ios: { 84 infoPlist: { 85 CFFakeValue: false, 86 }, 87 }, 88 }; 89 90 config = withPlugin(config); 91 92 config = withIosBaseMods(config, { 93 providers: { 94 infoPlist: getIosModFileProviders().infoPlist, 95 }, 96 }); 97 98 const results = await evalModsAsync(config, { 99 projectRoot, 100 platforms: ['ios'], 101 introspect: true, 102 assertMissingModProviders: true, 103 }); 104 105 expect(results.ios.infoPlist.CFFakeValue).toEqual(false); 106 107 expect(setter).not.toBeCalled(); 108 expect(addWarningIOS).not.toBeCalled(); 109 }); 110 111 it(`uses default behavior when not overwritten`, async () => { 112 const setter = jest.fn(); 113 const withPlugin = createInfoPlistPluginWithPropertyGuard(setter, { 114 infoPlistProperty: 'CFFakeValue', 115 expoConfigProperty: 'name', 116 }); 117 118 let config: ExpoConfig = { 119 name: 'hey', 120 slug: '', 121 ios: { 122 infoPlist: {}, 123 }, 124 }; 125 126 config = withPlugin(config); 127 128 config = withIosBaseMods(config, { 129 providers: { 130 infoPlist: getIosModFileProviders().infoPlist, 131 }, 132 }); 133 134 await evalModsAsync(config, { 135 projectRoot, 136 platforms: ['ios'], 137 introspect: true, 138 assertMissingModProviders: true, 139 }); 140 141 expect(setter).toBeCalled(); 142 expect(addWarningIOS).not.toBeCalled(); 143 }); 144}); 145