1082815dcSEvan Baconimport { resolve } from 'path'; 2082815dcSEvan Bacon 3*ed3bd27bSEvan Baconimport rnFixture from '../../plugins/__tests__/fixtures/react-native-project'; 4*ed3bd27bSEvan Baconimport * as XML from '../../utils/XML'; 5*ed3bd27bSEvan Baconimport { AndroidManifest, getMainActivity, readAndroidManifestAsync } from '../Manifest'; 6082815dcSEvan Baconimport { 7082815dcSEvan Bacon appendScheme, 8082815dcSEvan Bacon ensureManifestHasValidIntentFilter, 9082815dcSEvan Bacon getScheme, 10082815dcSEvan Bacon getSchemesFromManifest, 11082815dcSEvan Bacon hasScheme, 12082815dcSEvan Bacon removeScheme, 13082815dcSEvan Bacon setScheme, 14082815dcSEvan Bacon} from '../Scheme'; 15082815dcSEvan Bacon 16*ed3bd27bSEvan Baconasync function getFixtureManifestAsync() { 17*ed3bd27bSEvan Bacon return (await XML.parseXMLAsync( 18*ed3bd27bSEvan Bacon rnFixture['android/app/src/main/AndroidManifest.xml'] 19*ed3bd27bSEvan Bacon )) as AndroidManifest; 20*ed3bd27bSEvan Bacon} 21*ed3bd27bSEvan Bacon 22082815dcSEvan Baconconst fixturesPath = resolve(__dirname, 'fixtures'); 23082815dcSEvan Baconconst sampleManifestWithHostPath = resolve( 24082815dcSEvan Bacon fixturesPath, 25082815dcSEvan Bacon 'react-native-AndroidManifest-with-host.xml' 26082815dcSEvan Bacon); 27082815dcSEvan Bacon 28082815dcSEvan Bacondescribe('scheme', () => { 29082815dcSEvan Bacon it(`returns empty array if no scheme is provided`, () => { 30082815dcSEvan Bacon expect(getScheme({})).toStrictEqual([]); 31082815dcSEvan Bacon }); 32082815dcSEvan Bacon 33082815dcSEvan Bacon it(`returns the scheme if provided`, () => { 34082815dcSEvan Bacon expect(getScheme({ scheme: 'myapp' })).toStrictEqual(['myapp']); 35082815dcSEvan Bacon expect(getScheme({ scheme: ['other', 'myapp'] })).toStrictEqual(['other', 'myapp']); 36082815dcSEvan Bacon expect( 37082815dcSEvan Bacon getScheme({ 38*ed3bd27bSEvan Bacon scheme: [ 39*ed3bd27bSEvan Bacon 'other', 40*ed3bd27bSEvan Bacon 'myapp', 41*ed3bd27bSEvan Bacon // @ts-expect-error 42*ed3bd27bSEvan Bacon null, 43*ed3bd27bSEvan Bacon ], 44082815dcSEvan Bacon }) 45082815dcSEvan Bacon ).toStrictEqual(['other', 'myapp']); 46082815dcSEvan Bacon }); 47082815dcSEvan Bacon 48082815dcSEvan Bacon it('does not add scheme if none provided', async () => { 49*ed3bd27bSEvan Bacon let androidManifestJson = await getFixtureManifestAsync(); 50082815dcSEvan Bacon androidManifestJson = await setScheme({}, androidManifestJson); 51082815dcSEvan Bacon 52082815dcSEvan Bacon expect(androidManifestJson).toEqual(androidManifestJson); 53082815dcSEvan Bacon }); 54082815dcSEvan Bacon 55082815dcSEvan Bacon it('adds scheme to android manifest', async () => { 56*ed3bd27bSEvan Bacon let androidManifestJson = await getFixtureManifestAsync(); 57082815dcSEvan Bacon androidManifestJson = await setScheme( 58082815dcSEvan Bacon { 59082815dcSEvan Bacon scheme: 'myapp', 60082815dcSEvan Bacon android: { 61082815dcSEvan Bacon // @ts-ignore 62082815dcSEvan Bacon scheme: ['android-only'], 63082815dcSEvan Bacon package: 'com.demo.value', 64082815dcSEvan Bacon }, 65082815dcSEvan Bacon ios: { scheme: 'ios-only' }, 66082815dcSEvan Bacon }, 67082815dcSEvan Bacon androidManifestJson 68082815dcSEvan Bacon ); 69082815dcSEvan Bacon 70082815dcSEvan Bacon const mainActivity = getMainActivity(androidManifestJson); 71*ed3bd27bSEvan Bacon const intentFilters = mainActivity!['intent-filter']!; 72082815dcSEvan Bacon 73*ed3bd27bSEvan Bacon const schemeIntent: string[] = []; 74082815dcSEvan Bacon 75082815dcSEvan Bacon for (const intent of intentFilters) { 76082815dcSEvan Bacon if ('data' in intent) { 77*ed3bd27bSEvan Bacon for (const dataFilter of intent.data!) { 78082815dcSEvan Bacon const possibleScheme = dataFilter.$['android:scheme']; 79082815dcSEvan Bacon if (possibleScheme) { 80082815dcSEvan Bacon schemeIntent.push(possibleScheme); 81082815dcSEvan Bacon } 82082815dcSEvan Bacon } 83082815dcSEvan Bacon } 84082815dcSEvan Bacon } 85082815dcSEvan Bacon 86082815dcSEvan Bacon expect(schemeIntent).toStrictEqual(['myapp', 'android-only', 'com.demo.value']); 87082815dcSEvan Bacon }); 88082815dcSEvan Bacon}); 89082815dcSEvan Bacon 90082815dcSEvan Baconfunction removeSingleTaskFromActivities(manifest) { 91082815dcSEvan Bacon for (const application of manifest.manifest.application) { 92082815dcSEvan Bacon for (const activity of application.activity) { 93082815dcSEvan Bacon if (activity.$['android:launchMode'] === 'singleTask') { 94082815dcSEvan Bacon delete activity.$['android:launchMode']; 95082815dcSEvan Bacon } 96082815dcSEvan Bacon } 97082815dcSEvan Bacon } 98082815dcSEvan Bacon 99082815dcSEvan Bacon return manifest; 100082815dcSEvan Bacon} 101082815dcSEvan Bacon 102082815dcSEvan Bacondescribe('Schemes', () => { 103082815dcSEvan Bacon it(`ensure manifest has valid intent filter added`, async () => { 104*ed3bd27bSEvan Bacon const manifest = await getFixtureManifestAsync(); 105082815dcSEvan Bacon const manifestHasValidIntentFilter = ensureManifestHasValidIntentFilter(manifest); 106082815dcSEvan Bacon expect(manifestHasValidIntentFilter).toBe(true); 107082815dcSEvan Bacon }); 108082815dcSEvan Bacon 109082815dcSEvan Bacon it(`detect if no singleTask Activity exists`, async () => { 110*ed3bd27bSEvan Bacon const manifest = await getFixtureManifestAsync(); 111082815dcSEvan Bacon removeSingleTaskFromActivities(manifest); 112082815dcSEvan Bacon 113082815dcSEvan Bacon expect(ensureManifestHasValidIntentFilter(manifest)).toBe(false); 114082815dcSEvan Bacon }); 115082815dcSEvan Bacon 116082815dcSEvan Bacon it(`adds and removes a new scheme`, async () => { 117*ed3bd27bSEvan Bacon const manifest = await getFixtureManifestAsync(); 118082815dcSEvan Bacon ensureManifestHasValidIntentFilter(manifest); 119082815dcSEvan Bacon 120082815dcSEvan Bacon const modifiedManifest = appendScheme('myapp.test', manifest); 121082815dcSEvan Bacon const schemes = getSchemesFromManifest(modifiedManifest); 122082815dcSEvan Bacon expect(schemes).toContain('myapp.test'); 123082815dcSEvan Bacon const removedManifest = removeScheme('myapp.test', manifest); 124082815dcSEvan Bacon expect(getSchemesFromManifest(removedManifest)).not.toContain('myapp.test'); 125082815dcSEvan Bacon }); 126082815dcSEvan Bacon 127082815dcSEvan Bacon it(`get all schemes for the host`, async () => { 128082815dcSEvan Bacon const manifest = await readAndroidManifestAsync(sampleManifestWithHostPath); 129082815dcSEvan Bacon ensureManifestHasValidIntentFilter(manifest); 130082815dcSEvan Bacon expect(hasScheme('longestschemewiththehost', manifest)).toBe(true); 131082815dcSEvan Bacon 132082815dcSEvan Bacon const modifiedManifest = appendScheme('myapp.test', manifest); 133082815dcSEvan Bacon let schemes = getSchemesFromManifest(modifiedManifest, 'any-host'); 134082815dcSEvan Bacon expect(schemes).toContain('myapp.test'); 135082815dcSEvan Bacon expect(schemes).not.toContain('longestschemewiththehost'); 136082815dcSEvan Bacon 137082815dcSEvan Bacon schemes = getSchemesFromManifest(modifiedManifest, 'expo-development-client'); 138082815dcSEvan Bacon expect(schemes).toContain('myapp.test'); 139082815dcSEvan Bacon expect(schemes).toContain('longestschemewiththehost'); 140082815dcSEvan Bacon }); 141082815dcSEvan Bacon 142082815dcSEvan Bacon it(`detect when a duplicate might be added`, async () => { 143*ed3bd27bSEvan Bacon const manifest = await getFixtureManifestAsync(); 144082815dcSEvan Bacon ensureManifestHasValidIntentFilter(manifest); 145082815dcSEvan Bacon 146082815dcSEvan Bacon const modifiedManifest = appendScheme('myapp.test', manifest); 147082815dcSEvan Bacon expect(hasScheme('myapp.test', modifiedManifest)).toBe(true); 148082815dcSEvan Bacon }); 149082815dcSEvan Bacon 150082815dcSEvan Bacon it(`detect a non-existent scheme`, async () => { 151*ed3bd27bSEvan Bacon const manifest = await getFixtureManifestAsync(); 152082815dcSEvan Bacon 153082815dcSEvan Bacon expect(hasScheme('myapp.test', manifest)).toBe(false); 154082815dcSEvan Bacon }); 155082815dcSEvan Bacon}); 156