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