@@ -25,13 +25,15 @@ import { SingletonInstantiator } from '../../core/util/instantiator';
25
25
import {
26
26
AuthEvent ,
27
27
AuthEventType ,
28
+ EventManager ,
28
29
PopupRedirectResolver
29
30
} from '../../model/popup_redirect' ;
30
- import { cordovaPopupRedirectResolver } from './popup_redirect' ;
31
+ import { CordovaAuthEventManager , cordovaPopupRedirectResolver } from './popup_redirect' ;
31
32
import { GoogleAuthProvider } from '../../core/providers/google' ;
32
33
import * as utils from './utils' ;
33
34
import * as events from './events' ;
34
35
import { FirebaseError } from '@firebase/util' ;
36
+ import { stubSingleTimeout , TimerTripFn } from '../../../test/helpers/timeout_stub' ;
35
37
36
38
use ( chaiAsPromised ) ;
37
39
use ( sinonChai ) ;
@@ -85,6 +87,164 @@ describe('platform_cordova/popup_redirect/popup_redirect', () => {
85
87
} ) ;
86
88
} ) ;
87
89
90
+ describe ( '_initialize' , ( ) => {
91
+ const NO_EVENT_TIMER_ID = 10001 ;
92
+ const PACKAGE_NAME = 'my.package' ;
93
+ const NOT_PACKAGE_NAME = 'not.my.package' ;
94
+ let universalLinksCb : ( ( eventData : Record < string , string > | null ) => unknown ) | null ;
95
+ let tripNoEventTimer : TimerTripFn ;
96
+
97
+ beforeEach ( ( ) => {
98
+ tripNoEventTimer = stubSingleTimeout ( NO_EVENT_TIMER_ID ) ;
99
+ window . universalLinks = {
100
+ subscribe ( _unused , cb ) {
101
+ universalLinksCb = cb ;
102
+ } ,
103
+ } ;
104
+ window . BuildInfo = {
105
+ packageName : PACKAGE_NAME ,
106
+ displayName : '' ,
107
+ } ;
108
+ sinon . stub ( window , 'clearTimeout' ) ;
109
+ } ) ;
110
+
111
+ afterEach ( ( ) => {
112
+ universalLinksCb = null ;
113
+ } ) ;
114
+
115
+ function event ( manager : EventManager ) : Promise < AuthEvent > {
116
+ return new Promise ( resolve => {
117
+ ( manager as CordovaAuthEventManager ) . addPassiveListener ( resolve ) ;
118
+ } ) ;
119
+ }
120
+
121
+ context ( 'when no event is present' , ( ) => {
122
+ it ( 'clears local storage and dispatches no-event event' , async ( ) => {
123
+ const promise = event ( await resolver . _initialize ( auth ) ) ;
124
+ tripNoEventTimer ( ) ;
125
+ const { error, ...rest } = await promise ;
126
+
127
+ expect ( error ) . to . be . instanceOf ( FirebaseError ) . with . property ( 'code' , 'auth/no-auth-event' ) ;
128
+ expect ( rest ) . to . eql ( {
129
+ type : AuthEventType . UNKNOWN ,
130
+ eventId : null ,
131
+ sessionId : null ,
132
+ urlResponse : null ,
133
+ postBody : null ,
134
+ tenantId : null ,
135
+ } ) ;
136
+ expect ( events . _getAndRemoveEvent ) . to . have . been . called ;
137
+ } ) ;
138
+ } ) ;
139
+
140
+ context ( 'when an event is present' , ( ) => {
141
+ it ( 'clears the no event timeout' , async ( ) => {
142
+ await resolver . _initialize ( auth ) ;
143
+ await universalLinksCb ! ( { } ) ;
144
+ expect ( window . clearTimeout ) . to . have . been . calledWith ( NO_EVENT_TIMER_ID ) ;
145
+ } ) ;
146
+
147
+ it ( 'signals no event if no url in event data' , async ( ) => {
148
+ const promise = event ( await resolver . _initialize ( auth ) ) ;
149
+ await universalLinksCb ! ( { } ) ;
150
+ const { error, ...rest } = await promise ;
151
+
152
+ expect ( error ) . to . be . instanceOf ( FirebaseError ) . with . property ( 'code' , 'auth/no-auth-event' ) ;
153
+ expect ( rest ) . to . eql ( {
154
+ type : AuthEventType . UNKNOWN ,
155
+ eventId : null ,
156
+ sessionId : null ,
157
+ urlResponse : null ,
158
+ postBody : null ,
159
+ tenantId : null ,
160
+ } ) ;
161
+ } ) ;
162
+
163
+ it ( 'signals no event if partial parse turns up null' , async ( ) => {
164
+ const promise = event ( await resolver . _initialize ( auth ) ) ;
165
+ eventsStubs . _eventFromPartialAndUrl . returns ( null ) ;
166
+ eventsStubs . _getAndRemoveEvent . returns ( Promise . resolve ( {
167
+ type : AuthEventType . REAUTH_VIA_REDIRECT ,
168
+ } as AuthEvent ) ) ;
169
+ await universalLinksCb ! ( { url : 'foo-bar' } ) ;
170
+ const { error, ...rest } = await promise ;
171
+
172
+ expect ( error ) . to . be . instanceOf ( FirebaseError ) . with . property ( 'code' , 'auth/no-auth-event' ) ;
173
+ expect ( rest ) . to . eql ( {
174
+ type : AuthEventType . UNKNOWN ,
175
+ eventId : null ,
176
+ sessionId : null ,
177
+ urlResponse : null ,
178
+ postBody : null ,
179
+ tenantId : null ,
180
+ } ) ;
181
+ } ) ;
182
+
183
+ it ( 'signals the final event if partial expansion success' , async ( ) => {
184
+ const finalEvent = {
185
+ type : AuthEventType . REAUTH_VIA_REDIRECT ,
186
+ postBody : 'foo' ,
187
+ } ;
188
+ eventsStubs . _getAndRemoveEvent . returns ( Promise . resolve ( {
189
+ type : AuthEventType . REAUTH_VIA_REDIRECT ,
190
+ } as AuthEvent ) ) ;
191
+
192
+ const promise = event ( await resolver . _initialize ( auth ) ) ;
193
+ eventsStubs . _eventFromPartialAndUrl . returns ( finalEvent as AuthEvent ) ;
194
+ await universalLinksCb ! ( { url : 'foo-bar' } ) ;
195
+ expect ( await promise ) . to . eq ( finalEvent ) ;
196
+ expect ( events . _eventFromPartialAndUrl ) . to . have . been . calledWith (
197
+ { type : AuthEventType . REAUTH_VIA_REDIRECT } ,
198
+ 'foo-bar'
199
+ ) ;
200
+ } ) ;
201
+ } ) ;
202
+
203
+ context ( 'when using global handleOpenUrl callback' , ( ) => {
204
+ it ( 'ignores inbound callbacks that are not for this app' , async ( ) => {
205
+ await resolver . _initialize ( auth ) ;
206
+ handleOpenUrl ( `${ NOT_PACKAGE_NAME } ://foo` ) ;
207
+
208
+ // Clear timeout is called in the handler so we can check that
209
+ expect ( window . clearTimeout ) . not . to . have . been . called ;
210
+ } ) ;
211
+
212
+ it ( 'passes through callback if package name matches' , async ( ) => {
213
+ await resolver . _initialize ( auth ) ;
214
+ handleOpenUrl ( `${ PACKAGE_NAME } ://foo` ) ;
215
+ expect ( window . clearTimeout ) . to . have . been . calledWith ( NO_EVENT_TIMER_ID ) ;
216
+ } ) ;
217
+
218
+ it ( 'signals the final event if partial expansion success' , async ( ) => {
219
+ const finalEvent = {
220
+ type : AuthEventType . REAUTH_VIA_REDIRECT ,
221
+ postBody : 'foo' ,
222
+ } ;
223
+ eventsStubs . _getAndRemoveEvent . returns ( Promise . resolve ( {
224
+ type : AuthEventType . REAUTH_VIA_REDIRECT ,
225
+ } as AuthEvent ) ) ;
226
+
227
+ const promise = event ( await resolver . _initialize ( auth ) ) ;
228
+ eventsStubs . _eventFromPartialAndUrl . returns ( finalEvent as AuthEvent ) ;
229
+ handleOpenUrl ( `${ PACKAGE_NAME } ://foo` ) ;
230
+ expect ( await promise ) . to . eq ( finalEvent ) ;
231
+ expect ( events . _eventFromPartialAndUrl ) . to . have . been . calledWith (
232
+ { type : AuthEventType . REAUTH_VIA_REDIRECT } ,
233
+ `${ PACKAGE_NAME } ://foo`
234
+ ) ;
235
+ } ) ;
236
+
237
+ it ( 'calls the dev existing handleOpenUrl function' , async ( ) => {
238
+ const oldHandleOpenUrl = sinon . stub ( ) ;
239
+ window . handleOpenUrl = oldHandleOpenUrl ;
240
+
241
+ await resolver . _initialize ( auth ) ;
242
+ handleOpenUrl ( `${ PACKAGE_NAME } ://foo` ) ;
243
+ expect ( oldHandleOpenUrl ) . to . have . been . calledWith ( `${ PACKAGE_NAME } ://foo` ) ;
244
+ } ) ;
245
+ } ) ;
246
+ } ) ;
247
+
88
248
describe ( '_openPopup' , ( ) => {
89
249
it ( 'throws an error' , ( ) => {
90
250
expect ( ( ) =>
0 commit comments