1import { ExpoConfig } from '@expo/config-types'; 2import * as fs from 'fs'; 3import { vol } from 'memfs'; 4import * as path from 'path'; 5 6import * as WarningAggregator from '../../utils/warnings'; 7import { 8 formatDeviceFamilies, 9 getDeviceFamilies, 10 getIsTabletOnly, 11 getSupportsTablet, 12 setDeviceFamily, 13} from '../DeviceFamily'; 14import { getPbxproj } from '../utils/Xcodeproj'; 15 16const fsReal = jest.requireActual('fs') as typeof fs; 17 18jest.mock('fs'); 19jest.mock('../../utils/warnings'); 20 21const TABLET_AND_PHONE_SUPPORTED = [1, 2]; 22const ONLY_PHONE_SUPPORTED = [1]; 23const ONLY_TABLET_SUPPORTED = [2]; 24 25describe(getDeviceFamilies, () => { 26 it(`warns about invalid config`, () => { 27 getDeviceFamilies({ ios: { isTabletOnly: true, supportsTablet: false } } as any); 28 expect(WarningAggregator.addWarningIOS).toHaveBeenLastCalledWith( 29 'ios.supportsTablet', 30 'Found contradictory values: `{ ios: { isTabletOnly: true, supportsTablet: false } }`. Using `{ isTabletOnly: true }`.' 31 ); 32 }); 33}); 34 35describe('device family', () => { 36 it(`returns false ios.isTabletOnly is not provided`, () => { 37 expect(getIsTabletOnly({ ios: {} })).toBe(false); 38 }); 39 40 it(`returns true ios.isTabletOnly is provided`, () => { 41 expect(getIsTabletOnly({ ios: { isTabletOnly: true } })).toBe(true); 42 }); 43 44 it(`returns false ios.supportsTablet is provided`, () => { 45 expect(getSupportsTablet({ ios: {} })).toBe(false); 46 }); 47 48 it(`returns true ios.supportsTablet is provided`, () => { 49 expect(getSupportsTablet({ ios: { supportsTablet: true } })).toBe(true); 50 }); 51 52 it(`supports tablet and mobile if supportsTablet is true`, () => { 53 expect(getDeviceFamilies({ ios: { supportsTablet: true } })).toEqual( 54 TABLET_AND_PHONE_SUPPORTED 55 ); 56 }); 57 58 it(`supports only mobile if supportsTablet is blank/false and isTabletOnly is blank/false`, () => { 59 expect(getDeviceFamilies({ ios: {} })).toEqual(ONLY_PHONE_SUPPORTED); 60 expect(getDeviceFamilies({ ios: { supportsTablet: false, isTabletOnly: false } })).toEqual( 61 ONLY_PHONE_SUPPORTED 62 ); 63 }); 64 65 it(`supports only tablet if isTabletOnly is true`, () => { 66 expect(getDeviceFamilies({ ios: { isTabletOnly: true } })).toEqual(ONLY_TABLET_SUPPORTED); 67 }); 68 69 // It's important that this format is always correct. 70 // Otherwise the xcode parser will throw `Expected ".", "/*", ";", or [0-9] but "," found.` when we attempt to write to it. 71 it(`formats the families correctly`, () => { 72 expect(formatDeviceFamilies([1])).toEqual(`"1"`); 73 expect(formatDeviceFamilies([1, 2, 3])).toEqual(`"1,2,3"`); 74 }); 75 76 // TODO: update tests to run against pbxproj 77 // it(`sets to phone only if no value is provided`, () => { 78 // expect(setDeviceFamily({}, {})).toMatchObject({ UIDeviceFamily: ONLY_PHONE_SUPPORTED }); 79 // }); 80 81 // it(`sets to given config when provided`, () => { 82 // expect(setDeviceFamily({ ios: { supportsTablet: true } }, {})).toMatchObject({ 83 // UIDeviceFamily: TABLET_AND_PHONE_SUPPORTED, 84 // }); 85 // }); 86}); 87 88describe(setDeviceFamily, () => { 89 const projectRoot = '/tablet'; 90 beforeAll(async () => { 91 vol.fromJSON( 92 { 93 'ios/testproject.xcodeproj/project.pbxproj': fsReal.readFileSync( 94 path.join(__dirname, 'fixtures/project.pbxproj'), 95 'utf-8' 96 ), 97 'ios/testproject/AppDelegate.m': '', 98 }, 99 projectRoot 100 ); 101 }); 102 103 afterAll(() => { 104 vol.reset(); 105 }); 106 107 it('updates device families without throwing', async () => { 108 setDeviceFamilyForRoot({ name: '', slug: '', ios: {} }, projectRoot); 109 setDeviceFamilyForRoot({ name: '', slug: '', ios: { supportsTablet: true } }, projectRoot); 110 setDeviceFamilyForRoot({ name: '', slug: '', ios: { isTabletOnly: true } }, projectRoot); 111 }); 112}); 113 114function setDeviceFamilyForRoot(config: ExpoConfig, projectRoot: string) { 115 let project = getPbxproj(projectRoot); 116 project = setDeviceFamily(config, { project }); 117 fs.writeFileSync(project.filepath, project.writeSync()); 118} 119