15
15
* limitations under the License.
16
16
*/
17
17
18
- // eslint-disable-next-line import/no-extraneous-dependencies
19
- import { OperationType , UserCredential } from '@firebase/auth-exp' ;
20
- import { expect } from 'chai' ;
21
- import { TestFunction } from './util/auth_driver' ;
18
+ import {
19
+ OperationType ,
20
+ UserCredential ,
21
+ User ,
22
+ OAuthCredential
23
+ // eslint-disable-next-line import/no-extraneous-dependencies
24
+ } from '@firebase/auth-exp' ;
25
+ import { expect , use } from 'chai' ;
22
26
import { IdPPage } from './util/idp_page' ;
27
+ import * as chaiAsPromised from 'chai-as-promised' ;
23
28
import { browserDescribe } from './util/test_runner' ;
29
+ import { AnonFunction , CoreFunction , RedirectFunction } from './util/functions' ;
30
+
31
+ use ( chaiAsPromised ) ;
24
32
25
33
browserDescribe ( 'WebDriver redirect IdP test' , driver => {
26
- it ( 'allows users to sign in' , async ( ) => {
34
+ beforeEach ( async ( ) => {
27
35
await driver . pause ( 200 ) ; // Race condition on auth init
28
- await driver . callNoWait ( TestFunction . IDP_REDIRECT ) ;
36
+ } ) ;
37
+
38
+ it ( 'allows users to sign in' , async ( ) => {
39
+ await driver . callNoWait ( RedirectFunction . IDP_REDIRECT ) ;
29
40
const widget = new IdPPage ( driver . webDriver ) ;
30
41
31
42
// We're now on the widget page; wait for load
@@ -38,16 +49,218 @@ browserDescribe('WebDriver redirect IdP test', driver => {
38
49
await widget . clickSignIn ( ) ;
39
50
40
51
await driver . reinitOnRedirect ( ) ;
41
-
42
52
const currentUser = await driver . getUserSnapshot ( ) ;
43
53
expect ( currentUser . email ) . to . eq ( '[email protected] ' ) ;
44
54
expect ( currentUser . displayName ) . to . eq ( 'Bob Test' ) ;
45
55
expect ( currentUser . photoURL ) . to . eq ( 'http://bob.test/bob.png' ) ;
46
56
47
57
const redirectResult : UserCredential = await driver . call (
48
- TestFunction . REDIRECT_RESULT
58
+ RedirectFunction . REDIRECT_RESULT
49
59
) ;
50
60
expect ( redirectResult . operationType ) . to . eq ( OperationType . SIGN_IN ) ;
51
61
expect ( redirectResult . user ) . to . eql ( currentUser ) ;
52
62
} ) ;
63
+
64
+ it ( 'can link with another account account' , async ( ) => {
65
+ // First, sign in anonymously
66
+ const { user : anonUser } : UserCredential = await driver . call (
67
+ AnonFunction . SIGN_IN_ANONYMOUSLY
68
+ ) ;
69
+
70
+ // Then, link with redirect
71
+ await driver . callNoWait ( RedirectFunction . IDP_LINK_REDIRECT ) ;
72
+ const widget = new IdPPage ( driver . webDriver ) ;
73
+ await widget . pageLoad ( ) ;
74
+ await widget . clickAddAccount ( ) ;
75
+ await widget . fillEmail ( '[email protected] ' ) ;
76
+ await widget . clickSignIn ( ) ;
77
+
78
+ await driver . reinitOnRedirect ( ) ;
79
+ // Back on page; check for the current user matching the anonymous account
80
+ // as well as the new IdP account
81
+ const user : User = await driver . getUserSnapshot ( ) ;
82
+ expect ( user . uid ) . to . eq ( anonUser . uid ) ;
83
+ expect ( user . email ) . to . eq ( '[email protected] ' ) ;
84
+ } ) ;
85
+
86
+ it ( 'can be converted to a credential' , async ( ) => {
87
+ // Start with redirect
88
+ await driver . callNoWait ( RedirectFunction . IDP_REDIRECT ) ;
89
+ const widget = new IdPPage ( driver . webDriver ) ;
90
+ await widget . pageLoad ( ) ;
91
+ await widget . clickAddAccount ( ) ;
92
+ await widget . fillEmail ( '[email protected] ' ) ;
93
+ await widget . clickSignIn ( ) ;
94
+
95
+ // Generate a credential, then store it on the window before logging out
96
+ await driver . reinitOnRedirect ( ) ;
97
+ const first = await driver . getUserSnapshot ( ) ;
98
+ const cred : OAuthCredential = await driver . call (
99
+ RedirectFunction . GENERATE_CREDENTIAL_FROM_RESULT
100
+ ) ;
101
+ expect ( cred . accessToken ) . to . be . a ( 'string' ) ;
102
+ expect ( cred . idToken ) . to . be . a ( 'string' ) ;
103
+ expect ( cred . signInMethod ) . to . eq ( 'google.com' ) ;
104
+
105
+ // We've now generated that credential. Sign out and sign back in using it
106
+ await driver . call ( CoreFunction . SIGN_OUT ) ;
107
+ const { user : second } : UserCredential = await driver . call (
108
+ RedirectFunction . SIGN_IN_WITH_REDIRECT_CREDENTIAL
109
+ ) ;
110
+ expect ( second . uid ) . to . eq ( first . uid ) ;
111
+ expect ( second . providerData ) . to . eql ( first . providerData ) ;
112
+ } ) ;
113
+
114
+ it ( 'handles account exists different credential errors' , async ( ) => {
115
+ // Start with redirect and a verified account
116
+ await driver . callNoWait ( RedirectFunction . IDP_REDIRECT ) ;
117
+ const widget = new IdPPage ( driver . webDriver ) ;
118
+ await widget . pageLoad ( ) ;
119
+ await widget . clickAddAccount ( ) ;
120
+ await widget . fillEmail ( '[email protected] ' ) ;
121
+ await widget . clickSignIn ( ) ;
122
+ await driver . reinitOnRedirect ( ) ;
123
+
124
+ const original = await driver . getUserSnapshot ( ) ;
125
+ expect ( original . emailVerified ) . to . be . true ;
126
+
127
+ // Try to sign in with an unverified Facebook account
128
+ // TODO: Convert this to the widget once unverified accounts work
129
+ // Come back and verify error / prepare for link
130
+ await expect (
131
+ driver . call ( RedirectFunction . TRY_TO_SIGN_IN_UNVERIFIED , '[email protected] ' )
132
+ ) . to . be . rejected . and . eventually . have . property (
133
+ 'code' ,
134
+ 'auth/account-exists-with-different-credential'
135
+ ) ;
136
+
137
+ // Now do the link
138
+ await driver . call ( RedirectFunction . LINK_WITH_ERROR_CREDENTIAL ) ;
139
+
140
+ // Check the user for both providers
141
+ const user = await driver . getUserSnapshot ( ) ;
142
+ expect ( user . uid ) . to . eq ( original . uid ) ;
143
+ expect ( user . providerData . map ( d => d . providerId ) ) . to . have . members ( [
144
+ 'google.com' ,
145
+ 'facebook.com'
146
+ ] ) ;
147
+ } ) ;
148
+
149
+ context ( 'with existing user' , ( ) => {
150
+ let user1 : User ;
151
+ let user2 : User ;
152
+
153
+ beforeEach ( async ( ) => {
154
+ // Create a couple existing users
155
+ let cred : UserCredential = await driver . call (
156
+ RedirectFunction . CREATE_FAKE_GOOGLE_USER ,
157
+
158
+ ) ;
159
+ user1 = cred . user ;
160
+ cred = await driver . call (
161
+ RedirectFunction . CREATE_FAKE_GOOGLE_USER ,
162
+
163
+ ) ;
164
+ user2 = cred . user ;
165
+ await driver . call ( CoreFunction . SIGN_OUT ) ;
166
+ } ) ;
167
+
168
+ it ( 'a user can sign in again' , async ( ) => {
169
+ // Sign in using pre-poulated user
170
+ await driver . callNoWait ( RedirectFunction . IDP_REDIRECT ) ;
171
+
172
+ // This time, select an existing account
173
+ const widget = new IdPPage ( driver . webDriver ) ;
174
+ await widget . pageLoad ( ) ;
175
+ await widget . selectExistingAccountByEmail ( user1 . email ! ) ;
176
+
177
+ // Double check the new sign in matches the old
178
+ await driver . reinitOnRedirect ( ) ;
179
+ const user = await driver . getUserSnapshot ( ) ;
180
+ expect ( user . uid ) . to . eq ( user1 . uid ) ;
181
+ expect ( user . email ) . to . eq ( user1 . email ) ;
182
+ } ) ;
183
+
184
+ it ( 'reauthenticate works for the correct user' , async ( ) => {
185
+ // Sign in using pre-poulated user
186
+ await driver . callNoWait ( RedirectFunction . IDP_REDIRECT ) ;
187
+
188
+ const widget = new IdPPage ( driver . webDriver ) ;
189
+ await widget . pageLoad ( ) ;
190
+ await widget . selectExistingAccountByEmail ( user1 . email ! ) ;
191
+
192
+ // Double check the new sign in matches the old
193
+ await driver . reinitOnRedirect ( ) ;
194
+ let user = await driver . getUserSnapshot ( ) ;
195
+ expect ( user . uid ) . to . eq ( user1 . uid ) ;
196
+ expect ( user . email ) . to . eq ( user1 . email ) ;
197
+
198
+ // Reauthenticate specifically
199
+ await driver . callNoWait ( RedirectFunction . IDP_REAUTH_REDIRECT ) ;
200
+ await widget . pageLoad ( ) ;
201
+ await widget . selectExistingAccountByEmail ( user1 . email ! ) ;
202
+
203
+ await driver . reinitOnRedirect ( ) ;
204
+ user = await driver . getUserSnapshot ( ) ;
205
+ expect ( user . uid ) . to . eq ( user1 . uid ) ;
206
+ expect ( user . email ) . to . eq ( user1 . email ) ;
207
+ } ) ;
208
+
209
+ it ( 'reauthenticate throws for wrong user' , async ( ) => {
210
+ // Sign in using pre-poulated user
211
+ await driver . callNoWait ( RedirectFunction . IDP_REDIRECT ) ;
212
+
213
+ const widget = new IdPPage ( driver . webDriver ) ;
214
+ await widget . pageLoad ( ) ;
215
+ await widget . selectExistingAccountByEmail ( user1 . email ! ) ;
216
+
217
+ // Immediately reauth but with the wrong user
218
+ await driver . reinitOnRedirect ( ) ;
219
+ await driver . callNoWait ( RedirectFunction . IDP_REAUTH_REDIRECT ) ;
220
+ await widget . pageLoad ( ) ;
221
+ await widget . selectExistingAccountByEmail ( user2 . email ! ) ;
222
+
223
+ await driver . reinitOnRedirect ( ) ;
224
+ await expect (
225
+ driver . call ( RedirectFunction . REDIRECT_RESULT )
226
+ ) . to . be . rejected . and . eventually . have . property (
227
+ 'code' ,
228
+ 'auth/user-mismatch'
229
+ ) ;
230
+ } ) ;
231
+
232
+ it ( 'handles aborted sign ins' , async ( ) => {
233
+ await driver . callNoWait ( RedirectFunction . IDP_REDIRECT ) ;
234
+ const widget = new IdPPage ( driver . webDriver ) ;
235
+
236
+ // Don't actually sign in; go back to the previous page
237
+ await widget . pageLoad ( ) ;
238
+ await driver . goToTestPage ( ) ;
239
+ await driver . reinitOnRedirect ( ) ;
240
+ expect ( await driver . getUserSnapshot ( ) ) . to . be . null ;
241
+
242
+ // Now do sign in
243
+ await driver . callNoWait ( RedirectFunction . IDP_REDIRECT ) ;
244
+ // Use user1
245
+ await widget . pageLoad ( ) ;
246
+ await widget . selectExistingAccountByEmail ( user1 . email ! ) ;
247
+
248
+ // Ensure the user was signed in...
249
+ await driver . reinitOnRedirect ( ) ;
250
+ let user = await driver . getUserSnapshot ( ) ;
251
+ expect ( user . uid ) . to . eq ( user1 . uid ) ;
252
+ expect ( user . email ) . to . eq ( user1 . email ) ;
253
+
254
+ // Now open another sign in, but return
255
+ await driver . callNoWait ( RedirectFunction . IDP_REAUTH_REDIRECT ) ;
256
+ await widget . pageLoad ( ) ;
257
+ await driver . goToTestPage ( ) ;
258
+ await driver . reinitOnRedirect ( ) ;
259
+
260
+ // Make sure state remained
261
+ user = await driver . getUserSnapshot ( ) ;
262
+ expect ( user . uid ) . to . eq ( user1 . uid ) ;
263
+ expect ( user . email ) . to . eq ( user1 . email ) ;
264
+ } ) ;
265
+ } ) ;
53
266
} ) ;
0 commit comments