1import { ExecutionEnvironment } from 'expo-constants'; 2import { mockLinking, mockProperty, unmockAllProperties } from 'jest-expo'; 3 4import { describeManifestTypes, mockConstants } from './ManifestTestUtils'; 5 6function mockOpenAuthSessionAsync(webBrowserModule, openBrowserFn) { 7 mockProperty(webBrowserModule, 'openAuthSessionAsync', jest.fn(openBrowserFn)); 8} 9 10beforeEach(() => { 11 unmockAllProperties(); 12 jest.resetModules(); 13 jest.resetAllMocks(); 14}); 15 16describeManifestTypes( 17 { 18 id: '@example/abc', 19 originalFullName: '@example/abc', 20 }, 21 { 22 extra: { 23 expoClient: { 24 name: 'wat', 25 slug: 'wat', 26 originalFullName: '@example/abc', 27 }, 28 }, 29 } 30)((manifestObj) => { 31 beforeEach(() => { 32 mockConstants( 33 { 34 executionEnvironment: ExecutionEnvironment.Standalone, 35 }, 36 manifestObj 37 ); 38 }); 39 40 it(`returns correct redirect URL from getRedirectUrl`, () => { 41 const { getRedirectUrl } = require('../AuthSession'); 42 expect(getRedirectUrl()).toEqual('https://auth.expo.io/@example/abc'); 43 }); 44 45 it(`opens WebBrowser startAsync to the start URL`, async () => { 46 const authUrl = 'abcd.com'; 47 const returnUrl = 'efgh.com'; 48 49 const { startAsync } = require('../AuthSession'); 50 const WebBrowser = require('expo-web-browser'); 51 52 mockOpenAuthSessionAsync(WebBrowser, async () => ({ type: 'cancel' })); 53 await startAsync({ authUrl, returnUrl }); 54 55 const sessionUrlProvider = require('../SessionUrlProvider').default; 56 expect(WebBrowser.openAuthSessionAsync).toHaveBeenCalledWith( 57 sessionUrlProvider.getStartUrl(authUrl, returnUrl), 58 returnUrl, 59 { showInRecents: false } 60 ); 61 }); 62 63 it(`only lets you call startAsync once at a time`, async () => { 64 const authUrl = 'abcd.com'; 65 const returnUrl = 'efgh.com'; 66 const normalResponse = { type: 'cancel' }; 67 const lockedResponse = { type: 'locked' }; 68 69 mockProperty(console, 'warn', jest.fn()); 70 71 const { startAsync } = require('../AuthSession'); 72 const WebBrowser = require('expo-web-browser'); 73 74 mockOpenAuthSessionAsync(WebBrowser, () => { 75 return new Promise((resolve) => { 76 setTimeout(() => resolve(normalResponse), 0); 77 }); 78 }); 79 const parallelStartAsyncCalls = Promise.all([ 80 startAsync({ authUrl, returnUrl }), 81 startAsync({ authUrl, returnUrl }), 82 ]); 83 84 const [first, second] = await parallelStartAsyncCalls; 85 expect(first).toEqual(normalResponse); 86 expect(second).toEqual(lockedResponse); 87 expect(console.warn).toHaveBeenCalledWith(expect.stringMatching(/Only one AuthSession/)); 88 }); 89 90 it(`returns success with params on redirect`, async () => { 91 const emitLinkingEvent = mockLinking(); 92 const authUrl = 'http://example.io'; 93 const returnUrl = 'https://example-return.io/+'; 94 const returnUrlWithParams = `${returnUrl}?id=42#token=abc123`; 95 96 const { startAsync } = require('../AuthSession'); 97 const authSessionPromise = startAsync({ 98 authUrl, 99 returnUrl, 100 }); 101 emitLinkingEvent('url', { url: returnUrlWithParams }); 102 const result = await authSessionPromise; 103 104 expect(result.type).toEqual('success'); 105 expect((result as any).params).toEqual({ token: 'abc123', id: '42' }); 106 }); 107 108 it(`returns error when errorCode is present`, async () => { 109 const emitLinkingEvent = mockLinking(); 110 111 const authUrl = 'http://example.io'; 112 const returnUrl = 'https://example-return.io/+'; 113 114 const { startAsync } = require('../AuthSession'); 115 const authSessionPromise = startAsync({ 116 authUrl, 117 returnUrl, 118 }); 119 120 const returnUrlWithParams = `${returnUrl}?errorCode=nope&id=42`; 121 emitLinkingEvent('url', { url: returnUrlWithParams }); 122 123 const result = await authSessionPromise; 124 expect(result.type).toEqual('error'); 125 expect((result as any).errorCode).toEqual('nope'); 126 expect((result as any).params).toEqual({ id: '42' }); 127 }); 128 129 it(`throws from AuthSession.startAsync if authUrl is falsy`, async () => { 130 expect.assertions(1); 131 try { 132 const { startAsync } = require('../AuthSession'); 133 await startAsync({ 134 authUrl: null as any, 135 }); 136 } catch (e) { 137 expect(e).toMatchSnapshot(); 138 } 139 }); 140 141 it(`lets us call AuthSession.startAsync after param validation throws`, async () => { 142 const { startAsync } = require('../AuthSession'); 143 try { 144 await startAsync({ authUrl: null as any }); 145 } catch {} 146 147 const emitLinkingEvent = mockLinking(); 148 const authUrl = 'http://example.io'; 149 const returnUrl = 'https://example-return.io/+'; 150 const returnUrlWithParams = `${returnUrl}?id=42#token=abc123`; 151 152 const authSessionPromise = startAsync({ 153 authUrl, 154 returnUrl, 155 }); 156 emitLinkingEvent('url', { url: returnUrlWithParams }); 157 158 const result = await authSessionPromise; 159 160 expect(result.type).not.toEqual('locked'); 161 }); 162}); 163 164describeManifestTypes( 165 { 166 id: '@anonymous/abc', 167 originalFullName: undefined, 168 }, 169 { 170 extra: { 171 expoClient: { 172 name: 'wat', 173 slug: 'wat', 174 originalFullName: '@anonymous/abc', 175 }, 176 }, 177 } 178)((manifestObj) => { 179 it(`warns if user is @anonymous in getRedirectUrl`, () => { 180 mockConstants( 181 { 182 executionEnvironment: ExecutionEnvironment.Standalone, 183 }, 184 manifestObj 185 ); 186 187 mockProperty(console, 'warn', jest.fn()); 188 const { getRedirectUrl } = require('../AuthSession'); 189 getRedirectUrl(); 190 expect((console.warn as jest.Mock).mock.calls).toMatchSnapshot(); 191 }); 192}); 193