1import { resolve } from 'path'; 2 3import rnFixture from '../../plugins/__tests__/fixtures/react-native-project'; 4import * as XML from '../../utils/XML'; 5import { AndroidManifest, getMainActivity, readAndroidManifestAsync } from '../Manifest'; 6import { 7 appendScheme, 8 ensureManifestHasValidIntentFilter, 9 getScheme, 10 getSchemesFromManifest, 11 hasScheme, 12 removeScheme, 13 setScheme, 14} from '../Scheme'; 15 16async function getFixtureManifestAsync() { 17 return (await XML.parseXMLAsync( 18 rnFixture['android/app/src/main/AndroidManifest.xml'] 19 )) as AndroidManifest; 20} 21 22const fixturesPath = resolve(__dirname, 'fixtures'); 23const sampleManifestWithHostPath = resolve( 24 fixturesPath, 25 'react-native-AndroidManifest-with-host.xml' 26); 27 28describe('scheme', () => { 29 it(`returns empty array if no scheme is provided`, () => { 30 expect(getScheme({})).toStrictEqual([]); 31 }); 32 33 it(`returns the scheme if provided`, () => { 34 expect(getScheme({ scheme: 'myapp' })).toStrictEqual(['myapp']); 35 expect(getScheme({ scheme: ['other', 'myapp'] })).toStrictEqual(['other', 'myapp']); 36 expect( 37 getScheme({ 38 scheme: [ 39 'other', 40 'myapp', 41 // @ts-expect-error 42 null, 43 ], 44 }) 45 ).toStrictEqual(['other', 'myapp']); 46 }); 47 48 it('does not add scheme if none provided', async () => { 49 let androidManifestJson = await getFixtureManifestAsync(); 50 androidManifestJson = await setScheme({}, androidManifestJson); 51 52 expect(androidManifestJson).toEqual(androidManifestJson); 53 }); 54 55 it('adds scheme to android manifest', async () => { 56 let androidManifestJson = await getFixtureManifestAsync(); 57 androidManifestJson = await setScheme( 58 { 59 scheme: 'myapp', 60 android: { 61 // @ts-ignore 62 scheme: ['android-only'], 63 package: 'com.demo.value', 64 }, 65 ios: { scheme: 'ios-only' }, 66 }, 67 androidManifestJson 68 ); 69 70 const mainActivity = getMainActivity(androidManifestJson); 71 const intentFilters = mainActivity!['intent-filter']!; 72 73 const schemeIntent: string[] = []; 74 75 for (const intent of intentFilters) { 76 if ('data' in intent) { 77 for (const dataFilter of intent.data!) { 78 const possibleScheme = dataFilter.$['android:scheme']; 79 if (possibleScheme) { 80 schemeIntent.push(possibleScheme); 81 } 82 } 83 } 84 } 85 86 expect(schemeIntent).toStrictEqual(['myapp', 'android-only', 'com.demo.value']); 87 }); 88}); 89 90function removeSingleTaskFromActivities(manifest) { 91 for (const application of manifest.manifest.application) { 92 for (const activity of application.activity) { 93 if (activity.$['android:launchMode'] === 'singleTask') { 94 delete activity.$['android:launchMode']; 95 } 96 } 97 } 98 99 return manifest; 100} 101 102describe('Schemes', () => { 103 it(`ensure manifest has valid intent filter added`, async () => { 104 const manifest = await getFixtureManifestAsync(); 105 const manifestHasValidIntentFilter = ensureManifestHasValidIntentFilter(manifest); 106 expect(manifestHasValidIntentFilter).toBe(true); 107 }); 108 109 it(`detect if no singleTask Activity exists`, async () => { 110 const manifest = await getFixtureManifestAsync(); 111 removeSingleTaskFromActivities(manifest); 112 113 expect(ensureManifestHasValidIntentFilter(manifest)).toBe(false); 114 }); 115 116 it(`adds and removes a new scheme`, async () => { 117 const manifest = await getFixtureManifestAsync(); 118 ensureManifestHasValidIntentFilter(manifest); 119 120 const modifiedManifest = appendScheme('myapp.test', manifest); 121 const schemes = getSchemesFromManifest(modifiedManifest); 122 expect(schemes).toContain('myapp.test'); 123 const removedManifest = removeScheme('myapp.test', manifest); 124 expect(getSchemesFromManifest(removedManifest)).not.toContain('myapp.test'); 125 }); 126 127 it(`get all schemes for the host`, async () => { 128 const manifest = await readAndroidManifestAsync(sampleManifestWithHostPath); 129 ensureManifestHasValidIntentFilter(manifest); 130 expect(hasScheme('longestschemewiththehost', manifest)).toBe(true); 131 132 const modifiedManifest = appendScheme('myapp.test', manifest); 133 let schemes = getSchemesFromManifest(modifiedManifest, 'any-host'); 134 expect(schemes).toContain('myapp.test'); 135 expect(schemes).not.toContain('longestschemewiththehost'); 136 137 schemes = getSchemesFromManifest(modifiedManifest, 'expo-development-client'); 138 expect(schemes).toContain('myapp.test'); 139 expect(schemes).toContain('longestschemewiththehost'); 140 }); 141 142 it(`detect when a duplicate might be added`, async () => { 143 const manifest = await getFixtureManifestAsync(); 144 ensureManifestHasValidIntentFilter(manifest); 145 146 const modifiedManifest = appendScheme('myapp.test', manifest); 147 expect(hasScheme('myapp.test', modifiedManifest)).toBe(true); 148 }); 149 150 it(`detect a non-existent scheme`, async () => { 151 const manifest = await getFixtureManifestAsync(); 152 153 expect(hasScheme('myapp.test', manifest)).toBe(false); 154 }); 155}); 156