15
15
* limitations under the License.
16
16
*/
17
17
18
- import { FirebaseError } from '@firebase/util' ;
19
- import { expect } from 'chai' ;
18
+ import * as sinonChai from 'sinon-chai' ;
19
+ import * as sinon from 'sinon' ;
20
+ import { FirebaseError , querystring } from '@firebase/util' ;
21
+ import { expect , use } from 'chai' ;
20
22
import { testAuth , TestAuth } from '../../../test/helpers/mock_auth' ;
21
- import { AuthEventType } from '../../model/popup_redirect' ;
22
- import { _generateNewEvent } from './events' ;
23
+ import { AuthEvent , AuthEventType } from '../../model/popup_redirect' ;
24
+ import {
25
+ _eventFromPartialAndUrl ,
26
+ _generateNewEvent ,
27
+ _getAndRemoveEvent ,
28
+ _getDeepLinkFromCallback ,
29
+ _savePartialEvent
30
+ } from './events' ;
31
+ import { _createError } from '../../core/util/assert' ;
32
+ import { AuthErrorCode } from '../../core/errors' ;
33
+
34
+ use ( sinonChai ) ;
23
35
24
36
describe ( 'platform_cordova/popup_redirect/events' , ( ) => {
25
37
let auth : TestAuth ;
38
+ let storageStub : sinon . SinonStubbedInstance < typeof localStorage > ;
26
39
27
40
beforeEach ( async ( ) => {
28
41
auth = await testAuth ( ) ;
42
+ storageStub = sinon . stub ( localStorage ) ;
43
+ } ) ;
44
+
45
+ afterEach ( ( ) => {
46
+ sinon . restore ( ) ;
29
47
} ) ;
30
48
31
49
describe ( '_generateNewEvent' , ( ) => {
@@ -51,4 +69,127 @@ describe('platform_cordova/popup_redirect/events', () => {
51
69
. with . property ( 'code' , 'auth/no-auth-event' ) ;
52
70
} ) ;
53
71
} ) ;
72
+
73
+ describe ( '_savePartialEvent' , ( ) => {
74
+ it ( 'sets the event' , async ( ) => {
75
+ const event = _generateNewEvent ( auth , AuthEventType . REAUTH_VIA_REDIRECT ) ;
76
+ await _savePartialEvent ( auth , event ) ;
77
+ expect ( storageStub . setItem ) . to . have . been . calledWith (
78
+ 'firebase:authEvent:test-api-key:test-app' ,
79
+ JSON . stringify ( event )
80
+ ) ;
81
+ } ) ;
82
+ } ) ;
83
+
84
+ describe ( '_getAndRemoveEvent' , ( ) => {
85
+ it ( 'returns null if no event is present' , async ( ) => {
86
+ storageStub . getItem . returns ( null ) ;
87
+ expect ( await _getAndRemoveEvent ( auth ) ) . to . be . null ;
88
+ } ) ;
89
+
90
+ it ( 'returns the event and deletes the key if present' , async ( ) => {
91
+ const event = JSON . stringify (
92
+ _generateNewEvent ( auth , AuthEventType . REAUTH_VIA_REDIRECT )
93
+ ) ;
94
+ storageStub . getItem . returns ( event ) ;
95
+ expect ( await _getAndRemoveEvent ( auth ) ) . to . eql ( JSON . parse ( event ) ) ;
96
+ expect ( storageStub . removeItem ) . to . have . been . calledWith (
97
+ 'firebase:authEvent:test-api-key:test-app'
98
+ ) ;
99
+ } ) ;
100
+ } ) ;
101
+
102
+ describe ( '_eventFromPartialAndUrl' , ( ) => {
103
+ let partialEvent : AuthEvent ;
104
+ beforeEach ( ( ) => {
105
+ partialEvent = _generateNewEvent (
106
+ auth ,
107
+ AuthEventType . REAUTH_VIA_REDIRECT ,
108
+ 'id'
109
+ ) ;
110
+ } ) ;
111
+
112
+ function generateCallbackUrl ( params : Record < string , string > ) : string {
113
+ const deepLink = `http://foo/__/auth/callback?${ querystring ( params ) } ` ;
114
+ return `http://outer-app?link=${ encodeURIComponent ( deepLink ) } ` ;
115
+ }
116
+
117
+ it ( 'returns the proper event if everything is correct w/ no error' , ( ) => {
118
+ const url = generateCallbackUrl ( { } ) ;
119
+ expect ( _eventFromPartialAndUrl ( partialEvent , url ) ) . to . eql ( {
120
+ type : AuthEventType . REAUTH_VIA_REDIRECT ,
121
+ eventId : 'id' ,
122
+ tenantId : null ,
123
+ sessionId : partialEvent . sessionId ,
124
+ urlResponse : 'http://foo/__/auth/callback?' ,
125
+ postBody : null
126
+ } ) ;
127
+ } ) ;
128
+
129
+ it ( 'returns null if the callback url has no link' , ( ) => {
130
+ expect ( _eventFromPartialAndUrl ( partialEvent , 'http://foo' ) ) . to . be . null ;
131
+ } ) ;
132
+
133
+ it ( 'generates an error if the callback has an error' , ( ) => {
134
+ const handlerError = _createError ( AuthErrorCode . INTERNAL_ERROR ) ;
135
+ const url = generateCallbackUrl ( {
136
+ 'firebaseError' : JSON . stringify ( handlerError )
137
+ } ) ;
138
+ const { error, ...rest } = _eventFromPartialAndUrl ( partialEvent , url ) ! ;
139
+
140
+ expect ( error )
141
+ . to . be . instanceOf ( FirebaseError )
142
+ . with . property ( 'code' , 'auth/internal-error' ) ;
143
+ expect ( rest ) . to . eql ( {
144
+ type : AuthEventType . REAUTH_VIA_REDIRECT ,
145
+ eventId : 'id' ,
146
+ tenantId : null ,
147
+ urlResponse : null ,
148
+ sessionId : null ,
149
+ postBody : null
150
+ } ) ;
151
+ } ) ;
152
+ } ) ;
153
+
154
+ describe ( '_getDeepLinkFromCallback' , ( ) => {
155
+ it ( 'returns the iOS double deep link preferentially' , ( ) => {
156
+ expect (
157
+ _getDeepLinkFromCallback (
158
+ 'https://foo?link=http%3A%2F%2Ffoo%3Flink%3DdoubleDeep' +
159
+ '&deep_link_id=http%3A%2F%2Ffoo%3Flink%3DdoubleDeepIos'
160
+ )
161
+ ) . to . eq ( 'doubleDeepIos' ) ;
162
+ } ) ;
163
+
164
+ it ( 'returns the iOS deep link preferentially' , ( ) => {
165
+ expect (
166
+ _getDeepLinkFromCallback (
167
+ 'https://foo?link=http%3A%2F%2Ffoo%3Flink%3DdoubleDeep' +
168
+ '&deep_link_id=http%3A%2F%2FfooIOS'
169
+ )
170
+ ) . to . eq ( 'http://fooIOS' ) ;
171
+ } ) ;
172
+
173
+ it ( 'returns double deep link preferentially' , ( ) => {
174
+ expect (
175
+ _getDeepLinkFromCallback (
176
+ 'https://foo?link=http%3A%2F%2Ffoo%3Flink%3DdoubleDeep'
177
+ )
178
+ ) . to . eq ( 'doubleDeep' ) ;
179
+ } ) ;
180
+
181
+ it ( 'returns the deep link preferentially' , ( ) => {
182
+ expect (
183
+ _getDeepLinkFromCallback (
184
+ 'https://foo?link=http%3A%2F%2Ffoo%3Funrelated%3Dyeah'
185
+ )
186
+ ) . to . eq ( 'http://foo?unrelated=yeah' ) ;
187
+ } ) ;
188
+
189
+ it ( 'returns the passed-in url when all else fails' , ( ) => {
190
+ expect ( _getDeepLinkFromCallback ( 'https://foo?bar=baz' ) ) . to . eq (
191
+ 'https://foo?bar=baz'
192
+ ) ;
193
+ } ) ;
194
+ } ) ;
54
195
} ) ;
0 commit comments