xref: /expo/apps/test-suite/tests/Linking.js (revision f10e66fc)
1import { Platform } from 'react-native';
2import { Constants, Linking, WebBrowser } from 'expo';
3
4import { waitFor } from './helpers';
5
6const validHttpUrl = 'http://expo.io/';
7const validHttpsUrl = 'https://expo.io/';
8const validExpUrl = 'exp://expo.io/@community/native-component-list';
9const redirectingBackendUrl = 'https://backend-xxswjknyfi.now.sh/?linkingUri=';
10
11export const name = 'Linking';
12
13export function test(t) {
14  t.describe('Linking', () => {
15    t.describe('canOpenUrl', () => {
16      t.it('can open exp:// URLs', async () => {
17        t.expect(await Linking.canOpenURL(validExpUrl)).toBe(true);
18      });
19
20      t.it('can open its own URLs', async () => {
21        t.expect(await Linking.canOpenURL(Constants.linkingUri)).toBe(true);
22      });
23
24      t.it('can open http:// URLs', async () => {
25        t.expect(await Linking.canOpenURL(validHttpUrl)).toBe(true);
26      });
27
28      t.it('can open https:// URLs', async () => {
29        t.expect(await Linking.canOpenURL(validHttpsUrl)).toBe(true);
30      });
31    });
32
33    t.describe('addListener', () => {
34      let previousInterval = 0;
35      t.beforeAll(() => {
36        previousInterval = t.jasmine.DEFAULT_TIMEOUT_INTERVAL;
37        t.jasmine.DEFAULT_TIMEOUT_INTERVAL = 10000;
38      });
39      t.afterAll(() => {
40        t.jasmine.DEFAULT_TIMEOUT_INTERVAL = previousInterval;
41      });
42
43      if (Platform.OS === 'android') {
44        // We can't run this test on iOS since iOS it fails with an exception
45        // "The specified URL has an unsupported scheme. Only HTTP and HTTPS URLs are supported."
46        t.it('listener gets called with a proper URL when opened from a web modal', async () => {
47          let handlerCalled = false;
48          // we add two pluses here so test-suite knows to ignore the deep link content (see index.js line 92)
49          const testUrl = Linking.makeUrl('++message=hello');
50          const handler = ({ url }) => {
51            t.expect(url).toEqual(testUrl);
52            handlerCalled = true;
53          };
54          Linking.addEventListener('url', handler);
55          await WebBrowser.openBrowserAsync(testUrl);
56          t.expect(handlerCalled).toBe(true);
57          Linking.removeListener('url', handler);
58        });
59
60        // We can't run this test on iOS since iOS asks "whether to open this link in Expo"
61        // and we can't programmatically tap "Open".
62        t.it('listener gets called with a proper URL when opened from a web browser', async () => {
63          let handlerCalled = false;
64          const handler = ({ url }) => {
65            t.expect(url).toEqual(Linking.makeUrl('++message=Redirected automatically by timer'));
66            handlerCalled = true;
67          };
68          Linking.addEventListener('url', handler);
69          await Linking.openURL(`${redirectingBackendUrl}${Linking.makeUrl('++')}`);
70          await waitFor(8000);
71          t.expect(handlerCalled).toBe(true);
72          Linking.removeListener('url', handler);
73        });
74      }
75
76      t.it('listener gets called with a proper URL when opened from a web modal', async () => {
77        let handlerCalled = false;
78        const handler = ({ url }) => {
79          t.expect(url).toEqual(Linking.makeUrl('++message=Redirected automatically by timer'));
80          handlerCalled = true;
81          WebBrowser.dismissBrowser();
82        };
83        Linking.addEventListener('url', handler);
84        await WebBrowser.openBrowserAsync(`${redirectingBackendUrl}${Linking.makeUrl('++')}`);
85        await waitFor(1000);
86        t.expect(handlerCalled).toBe(true);
87        Linking.removeListener('url', handler);
88      });
89
90      t.it('listener gets called with a proper URL when opened with Linking.openURL', async () => {
91        let handlerCalled = false;
92        const handler = ({ url }) => {
93          handlerCalled = true;
94        };
95        Linking.addEventListener('url', handler);
96        await Linking.openURL(Linking.makeUrl('++'));
97        await waitFor(500);
98        t.expect(handlerCalled).toBe(true);
99        Linking.removeListener('url', handler);
100      });
101
102      t.it('listener parses out deep link information correctly', async () => {
103        let handlerCalled = false;
104        const handler = ({ url }) => {
105          let { path, queryParams } = Linking.parse(url);
106          // ignore +'s on the front of path,
107          // since there may be one or two depending on how test-suite is being served
108          t.expect(path.replace(/\+/g, '')).toEqual('test/path');
109          t.expect(queryParams.query).toEqual('param');
110          handlerCalled = true;
111        };
112        Linking.addEventListener('url', handler);
113        await Linking.openURL(Linking.makeUrl('++test/path?query=param'));
114        await waitFor(500);
115        t.expect(handlerCalled).toBe(true);
116        Linking.removeListener('url', handler);
117      });
118    });
119  });
120}
121