18
18
// eslint-disable-next-line import/no-extraneous-dependencies
19
19
import { UserCredential } from '@firebase/auth-exp' ;
20
20
import { expect } from 'chai' ;
21
+ import { User } from '../../../internal' ;
22
+ import { createAnonAccount } from '../../helpers/integration/emulator_rest_helpers' ;
21
23
import { API_KEY } from '../../helpers/integration/settings' ;
22
- import { AnonFunction , PersistenceFunction } from './util/functions' ;
24
+ import {
25
+ AnonFunction ,
26
+ CoreFunction ,
27
+ PersistenceFunction
28
+ } from './util/functions' ;
23
29
import { browserDescribe } from './util/test_runner' ;
24
30
31
+ // eslint-disable-next-line @typescript-eslint/explicit-function-return-type
32
+ async function testPersistedUser ( ) {
33
+ const account = await createAnonAccount ( ) ;
34
+ return {
35
+ uid : account . localId ,
36
+ emailVerified : false ,
37
+ isAnonymous : true ,
38
+ providerData : [ ] ,
39
+ stsTokenManager : {
40
+ refreshToken : account . refreshToken ,
41
+ accessToken : account . idToken ,
42
+ expirationTime : Date . now ( ) + 3600 * 1000
43
+ } ,
44
+ createdAt : Date . now ( ) . toString ( ) ,
45
+ lastLoginAt : Date . now ( ) . toString ( )
46
+ } ;
47
+ }
48
+
25
49
browserDescribe ( 'WebDriver persistence test' , driver => {
50
+ const fullPersistenceKey = `firebase:authUser:${ API_KEY } :[DEFAULT]` ;
26
51
context ( 'default persistence hierarchy (indexedDB > localStorage)' , ( ) => {
27
52
it ( 'stores user in indexedDB by default' , async ( ) => {
28
53
const cred : UserCredential = await driver . call (
@@ -39,9 +64,7 @@ browserDescribe('WebDriver persistence test', driver => {
39
64
) . to . eql ( { } ) ;
40
65
41
66
const snap = await driver . call ( PersistenceFunction . INDEXED_DB_SNAP ) ;
42
- expect ( snap )
43
- . to . have . property ( `firebase:authUser:${ API_KEY } :[DEFAULT]` )
44
- . that . contains ( { uid } ) ;
67
+ expect ( snap ) . to . have . property ( fullPersistenceKey ) . that . contains ( { uid } ) ;
45
68
46
69
// Persistence should survive a refresh:
47
70
await driver . webDriver . navigate ( ) . refresh ( ) ;
@@ -71,9 +94,7 @@ browserDescribe('WebDriver persistence test', driver => {
71
94
) . to . eql ( { } ) ;
72
95
73
96
const snap = await driver . call ( PersistenceFunction . INDEXED_DB_SNAP ) ;
74
- expect ( snap )
75
- . to . have . property ( `firebase:authUser:${ API_KEY } :[DEFAULT]` )
76
- . that . contains ( { uid } ) ;
97
+ expect ( snap ) . to . have . property ( fullPersistenceKey ) . that . contains ( { uid } ) ;
77
98
78
99
// Persistence should survive a refresh:
79
100
await driver . webDriver . navigate ( ) . refresh ( ) ;
@@ -100,9 +121,7 @@ browserDescribe('WebDriver persistence test', driver => {
100
121
) . to . eql ( { } ) ;
101
122
102
123
const snap = await driver . call ( PersistenceFunction . LOCAL_STORAGE_SNAP ) ;
103
- expect ( snap )
104
- . to . have . property ( `firebase:authUser:${ API_KEY } :[DEFAULT]` )
105
- . that . contains ( { uid } ) ;
124
+ expect ( snap ) . to . have . property ( fullPersistenceKey ) . that . contains ( { uid } ) ;
106
125
107
126
// Persistence should survive a refresh:
108
127
await driver . webDriver . navigate ( ) . refresh ( ) ;
@@ -139,9 +158,84 @@ browserDescribe('WebDriver persistence test', driver => {
139
158
await driver . waitForAuthInit ( ) ;
140
159
expect ( await driver . getUserSnapshot ( ) ) . to . equal ( null ) ;
141
160
} ) ;
142
- } ) ;
143
161
144
- // TODO: Upgrade tests (e.g. migrate user from localStorage to indexedDB).
162
+ it ( 'migrate stored user from localStorage if indexedDB is available' , async ( ) => {
163
+ const persistedUser = await testPersistedUser ( ) ;
164
+ await driver . webDriver . navigate ( ) . refresh ( ) ;
165
+ await driver . call ( PersistenceFunction . LOCAL_STORAGE_SET , {
166
+ [ fullPersistenceKey ] : persistedUser
167
+ } ) ;
168
+ await driver . injectConfigAndInitAuth ( ) ;
169
+ await driver . waitForAuthInit ( ) ;
170
+
171
+ // User from localStorage should be picked up.
172
+ const user = await driver . call < User > ( CoreFunction . USER_SNAPSHOT ) ;
173
+ expect ( user . uid ) . eql ( persistedUser . uid ) ;
174
+
175
+ // User should be migrated to indexedDB, and the key in localStorage should be deleted.
176
+ const snap = await driver . call ( PersistenceFunction . INDEXED_DB_SNAP ) ;
177
+ expect ( snap )
178
+ . to . have . property ( fullPersistenceKey )
179
+ . that . contains ( { uid : persistedUser . uid } ) ;
180
+ expect ( await driver . call ( PersistenceFunction . LOCAL_STORAGE_SNAP ) ) . to . eql (
181
+ { }
182
+ ) ;
183
+ } ) ;
184
+
185
+ it ( 'migrate stored user to localStorage if indexedDB is readonly' , async ( ) => {
186
+ // Sign in first, which gets persisted in indexedDB.
187
+ const cred : UserCredential = await driver . call (
188
+ AnonFunction . SIGN_IN_ANONYMOUSLY
189
+ ) ;
190
+ const uid = cred . user . uid ;
191
+
192
+ await driver . webDriver . navigate ( ) . refresh ( ) ;
193
+ await driver . call ( PersistenceFunction . MAKE_INDEXED_DB_READONLY ) ;
194
+ await driver . injectConfigAndInitAuth ( ) ;
195
+ await driver . waitForAuthInit ( ) ;
196
+
197
+ // User from indexedDB should be picked up.
198
+ const user = await driver . call < User > ( CoreFunction . USER_SNAPSHOT ) ;
199
+ expect ( user . uid ) . eql ( uid ) ;
200
+
201
+ // User should be migrated to localStorage, and the key in indexedDB should be deleted.
202
+ const snap = await driver . call ( PersistenceFunction . LOCAL_STORAGE_SNAP ) ;
203
+ expect ( snap ) . to . have . property ( fullPersistenceKey ) . that . contains ( { uid } ) ;
204
+ expect ( await driver . call ( PersistenceFunction . INDEXED_DB_SNAP ) ) . to . eql ( { } ) ;
205
+ } ) ;
206
+
207
+ it ( 'use in-memory and clear all persistences if indexedDB and localStorage are both broken' , async ( ) => {
208
+ const persistedUser = await testPersistedUser ( ) ;
209
+ await driver . webDriver . navigate ( ) . refresh ( ) ;
210
+ await driver . call ( PersistenceFunction . LOCAL_STORAGE_SET , {
211
+ [ fullPersistenceKey ] : persistedUser
212
+ } ) ;
213
+ // Simulate browsers that do not support indexedDB.
214
+ await driver . webDriver . executeScript ( 'delete window.indexedDB;' ) ;
215
+ // Simulate browsers denying writes to localStorage (e.g. Safari private browsing).
216
+ await driver . webDriver . executeScript (
217
+ 'Storage.prototype.setItem = () => { throw new Error("setItem disabled for testing"); };'
218
+ ) ;
219
+ await driver . injectConfigAndInitAuth ( ) ;
220
+ await driver . waitForAuthInit ( ) ;
221
+
222
+ // User from localStorage should be picked up.
223
+ const user = await driver . call < User > ( CoreFunction . USER_SNAPSHOT ) ;
224
+ expect ( user . uid ) . eql ( persistedUser . uid ) ;
225
+
226
+ // Both storage should be cleared.
227
+ expect ( await driver . call ( PersistenceFunction . LOCAL_STORAGE_SNAP ) ) . to . eql (
228
+ { }
229
+ ) ;
230
+ expect ( await driver . call ( PersistenceFunction . INDEXED_DB_SNAP ) ) . to . eql ( { } ) ;
231
+
232
+ // User will be gone (a.k.a. logged out) after refresh.
233
+ await driver . webDriver . navigate ( ) . refresh ( ) ;
234
+ await driver . injectConfigAndInitAuth ( ) ;
235
+ await driver . waitForAuthInit ( ) ;
236
+ expect ( await driver . getUserSnapshot ( ) ) . to . equal ( null ) ;
237
+ } ) ;
238
+ } ) ;
145
239
146
240
// TODO: Compatibility tests (e.g. sign in with JS SDK and should stay logged in with TS SDK).
147
241
} ) ;
0 commit comments