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