@@ -52,7 +52,6 @@ import { JsonObject } from '../../../src/model/field_value';
52
52
import { Mutation } from '../../../src/model/mutation' ;
53
53
import {
54
54
emptyByteString ,
55
- Platform ,
56
55
PlatformSupport
57
56
} from '../../../src/platform/platform' ;
58
57
import { Connection , Stream } from '../../../src/remote/connection' ;
@@ -99,6 +98,7 @@ import {
99
98
SharedClientState ,
100
99
WebStorageSharedClientState
101
100
} from '../../../src/local/shared_client_state' ;
101
+ import { TestPlatform , SharedFakeWebStorage } from '../../util/test_platform' ;
102
102
103
103
class MockConnection implements Connection {
104
104
watchStream : StreamBridge <
@@ -1137,230 +1137,6 @@ class MemoryTestRunner extends TestRunner {
1137
1137
}
1138
1138
}
1139
1139
1140
- /**
1141
- * `Document` mock that implements the `visibilitychange` API used by Firestore.
1142
- */
1143
- class MockDocument {
1144
- private _visibilityState : VisibilityState = 'unloaded' ;
1145
- private visibilityListener : EventListener | null ;
1146
-
1147
- get visibilityState ( ) : VisibilityState {
1148
- return this . _visibilityState ;
1149
- }
1150
-
1151
- addEventListener ( type : string , listener : EventListener ) : void {
1152
- assert (
1153
- type === 'visibilitychange' ,
1154
- "MockDocument only supports events of type 'visibilitychange'"
1155
- ) ;
1156
- this . visibilityListener = listener ;
1157
- }
1158
-
1159
- removeEventListener ( type : string , listener : EventListener ) : void {
1160
- if ( listener === this . visibilityListener ) {
1161
- this . visibilityListener = null ;
1162
- }
1163
- }
1164
-
1165
- raiseVisibilityEvent ( visibility : VisibilityState ) : void {
1166
- this . _visibilityState = visibility ;
1167
- if ( this . visibilityListener ) {
1168
- this . visibilityListener ( new Event ( 'visibilitychange' ) ) ;
1169
- }
1170
- }
1171
- }
1172
-
1173
- /**
1174
- * `WebStorage` mock that implements the WebStorage behavior for multiple
1175
- * clients. To get a client-specific storage area that implements the WebStorage
1176
- * API, invoke `getStorageArea(storageListener)`.
1177
- */
1178
- class SharedMockStorage {
1179
- private readonly data = new Map < string , string > ( ) ;
1180
- private readonly activeClients : Array < {
1181
- storageListener : EventListener ;
1182
- storageArea : Storage ;
1183
- } > = [ ] ;
1184
-
1185
- getStorageArea ( storageListener : EventListener ) : Storage {
1186
- const clientIndex = this . activeClients . length ;
1187
- const self = this ;
1188
-
1189
- const storageArea : Storage = {
1190
- get length ( ) : number {
1191
- return self . length ;
1192
- } ,
1193
- getItem : ( key : string ) => this . getItem ( key ) ,
1194
- key : ( index : number ) => this . key ( index ) ,
1195
- clear : ( ) => this . clear ( ) ,
1196
- removeItem : ( key : string ) => {
1197
- const oldValue = this . getItem ( key ) ;
1198
- this . removeItem ( key ) ;
1199
- this . raiseStorageEvent ( clientIndex , key , oldValue , null ) ;
1200
- } ,
1201
- setItem : ( key : string , value : string ) => {
1202
- const oldValue = this . getItem ( key ) ;
1203
- this . setItem ( key , value ) ;
1204
- this . raiseStorageEvent ( clientIndex , key , oldValue , value ) ;
1205
- }
1206
- } ;
1207
-
1208
- this . activeClients [ clientIndex ] = { storageListener, storageArea } ;
1209
-
1210
- return storageArea ;
1211
- }
1212
-
1213
- private clear ( ) : void {
1214
- this . data . clear ( ) ;
1215
- }
1216
-
1217
- private getItem ( key : string ) : string | null {
1218
- return this . data . get ( key ) ;
1219
- }
1220
-
1221
- private key ( index : number ) : string | null {
1222
- return Array . from ( this . data . keys ( ) ) [ index ] ;
1223
- }
1224
-
1225
- private removeItem ( key : string ) : void {
1226
- this . data . delete ( key ) ;
1227
- }
1228
-
1229
- private setItem ( key : string , data : string ) : void {
1230
- this . data . set ( key , data ) ;
1231
- }
1232
-
1233
- private get length ( ) : number {
1234
- return this . data . size ;
1235
- }
1236
-
1237
- private raiseStorageEvent (
1238
- sourceClientIndex : number ,
1239
- key : string ,
1240
- oldValue : string | null ,
1241
- newValue : string | null
1242
- ) : void {
1243
- this . activeClients . forEach ( ( client , index ) => {
1244
- // WebStorage doesn't raise events for writes from the originating client.
1245
- if ( sourceClientIndex === index ) {
1246
- return ;
1247
- }
1248
-
1249
- client . storageListener ( {
1250
- key,
1251
- oldValue,
1252
- newValue,
1253
- storageArea : client . storageArea
1254
- } as any ) ; // tslint:disable-line:no-any Not mocking entire Event type.
1255
- } ) ;
1256
- }
1257
- }
1258
-
1259
- /**
1260
- * `Window` mock that implements the event and storage API that is used by
1261
- * Firestore.
1262
- */
1263
- class MockWindow {
1264
- private readonly storageArea : Storage ;
1265
- private storageListener : EventListener = ( ) => { } ;
1266
-
1267
- constructor ( sharedMockStorage : SharedMockStorage ) {
1268
- this . storageArea = sharedMockStorage . getStorageArea ( event =>
1269
- this . storageListener ( event )
1270
- ) ;
1271
- }
1272
-
1273
- get localStorage ( ) : Storage {
1274
- return this . storageArea ;
1275
- }
1276
-
1277
- get indexedDB ( ) : IDBFactory {
1278
- return window . indexedDB ;
1279
- }
1280
-
1281
- addEventListener ( type : string , listener : EventListener ) : void {
1282
- switch ( type ) {
1283
- case 'storage' :
1284
- this . storageListener = listener ;
1285
- break ;
1286
- case 'unload' :
1287
- // The spec tests currently do not rely on 'unload' listeners.
1288
- break ;
1289
- default :
1290
- fail ( `MockWindow doesn't support events of type '${ type } '` ) ;
1291
- }
1292
- }
1293
-
1294
- removeEventListener ( type : string , listener : EventListener ) : void {
1295
- if ( type === 'storage' ) {
1296
- assert (
1297
- this . storageListener === listener ,
1298
- "Listener passed to 'removeEventListener' doesn't match the current listener."
1299
- ) ;
1300
- this . storageListener = ( ) => { } ;
1301
- }
1302
- }
1303
- }
1304
-
1305
- /**
1306
- * Implementation of `Platform` that allows mocking of `document` and `window`.
1307
- */
1308
- class TestPlatform implements Platform {
1309
- readonly mockDocument : MockDocument | null = null ;
1310
- readonly mockWindow : MockWindow | null = null ;
1311
-
1312
- constructor (
1313
- private readonly basePlatform : Platform ,
1314
- private readonly mockStorage : SharedMockStorage
1315
- ) {
1316
- this . mockDocument = new MockDocument ( ) ;
1317
- this . mockWindow = new MockWindow ( this . mockStorage ) ;
1318
- }
1319
-
1320
- get document ( ) : Document | null {
1321
- // tslint:disable-next-line:no-any MockWindow doesn't support full Document interface.
1322
- return this . mockDocument as any ;
1323
- }
1324
-
1325
- get window ( ) : Window | null {
1326
- // tslint:disable-next-line:no-any MockWindow doesn't support full Window interface.
1327
- return this . mockWindow as any ;
1328
- }
1329
-
1330
- get base64Available ( ) : boolean {
1331
- return this . basePlatform . base64Available ;
1332
- }
1333
-
1334
- get emptyByteString ( ) : ProtoByteString {
1335
- return this . basePlatform . emptyByteString ;
1336
- }
1337
-
1338
- raiseVisibilityEvent ( visibility : VisibilityState ) : void {
1339
- if ( this . mockDocument ) {
1340
- this . mockDocument . raiseVisibilityEvent ( visibility ) ;
1341
- }
1342
- }
1343
-
1344
- loadConnection ( databaseInfo : DatabaseInfo ) : Promise < Connection > {
1345
- return this . basePlatform . loadConnection ( databaseInfo ) ;
1346
- }
1347
-
1348
- newSerializer ( databaseId : DatabaseId ) : JsonProtoSerializer {
1349
- return this . basePlatform . newSerializer ( databaseId ) ;
1350
- }
1351
-
1352
- formatJSON ( value : AnyJs ) : string {
1353
- return this . basePlatform . formatJSON ( value ) ;
1354
- }
1355
-
1356
- atob ( encoded : string ) : string {
1357
- return this . basePlatform . atob ( encoded ) ;
1358
- }
1359
-
1360
- btoa ( raw : string ) : string {
1361
- return this . basePlatform . btoa ( raw ) ;
1362
- }
1363
- }
1364
1140
/**
1365
1141
* Runs the specs using IndexedDbPersistence, the creator must ensure that it is
1366
1142
* enabled for the platform.
@@ -1409,7 +1185,7 @@ export async function runSpec(
1409
1185
// tslint:disable-next-line:no-console
1410
1186
console . log ( 'Running spec: ' + name ) ;
1411
1187
1412
- const sharedMockStorage = new SharedMockStorage ( ) ;
1188
+ const sharedMockStorage = new SharedFakeWebStorage ( ) ;
1413
1189
1414
1190
// PORTING NOTE: Non multi-client SDKs only support a single test runner.
1415
1191
const runners : TestRunner [ ] = [ ] ;
0 commit comments