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