Skip to content

Commit ca5e473

Browse files
Setting visibilityState on client init
FFDFG [AUTOMATED]: Prettier Code Styling
1 parent 75b08c8 commit ca5e473

File tree

2 files changed

+62
-52
lines changed

2 files changed

+62
-52
lines changed

packages/firestore/src/local/indexeddb_persistence.ts

+20-18
Original file line numberDiff line numberDiff line change
@@ -109,8 +109,8 @@ export class IndexedDbPersistence implements Persistence {
109109
*/
110110
static MAIN_DATABASE = 'main';
111111

112-
private readonly document: Document | null;
113-
private readonly window: Window | null;
112+
private readonly document: Document;
113+
private readonly window: Window;
114114

115115
private simpleDb: SimpleDb;
116116
private started: boolean;
@@ -134,7 +134,7 @@ export class IndexedDbPersistence implements Persistence {
134134
private serializer: LocalSerializer;
135135

136136
/** Our 'visibilitychange` listener if registered. */
137-
private documentVisibilityHandler: ((e: Event) => void) | null;
137+
private documentVisibilityHandler: ((e?: Event) => void) | null;
138138

139139
/** Callback for primary state notifications. */
140140
private primaryStateListener = IndexedDbPersistence.EMPTY_PRIMARY_STATE_LISTENER;
@@ -144,6 +144,10 @@ export class IndexedDbPersistence implements Persistence {
144144
platform: Platform,
145145
serializer: JsonProtoSerializer
146146
) {
147+
assert(
148+
platform.window !== null && platform.document !== null,
149+
"Expected 'window' and 'document' to be defined"
150+
);
147151
this.dbName = prefix + IndexedDbPersistence.MAIN_DATABASE;
148152
this.serializer = new LocalSerializer(serializer);
149153
this.localStoragePrefix = prefix;
@@ -160,29 +164,27 @@ export class IndexedDbPersistence implements Persistence {
160164
return Promise.reject(this.persistenceError);
161165
}
162166

163-
if (this.document) {
164-
this.documentVisibilityHandler = () => {
165-
const inForeground = document.visibilityState === 'visible';
166-
if (inForeground !== this.inForeground) {
167-
this.inForeground = inForeground;
168-
this.refreshClientState();
169-
}
170-
};
171-
172-
this.document.addEventListener(
173-
'visibilitychange',
174-
this.documentVisibilityHandler
175-
);
176-
}
177-
178167
assert(!this.started, 'IndexedDbPersistence double-started!');
179168
this.started = true;
169+
this.inForeground = this.document.visibilityState === 'visible';
170+
171+
this.documentVisibilityHandler = () => {
172+
const inForeground = this.document.visibilityState === 'visible';
173+
if (inForeground !== this.inForeground) {
174+
this.inForeground = inForeground;
175+
this.refreshClientState();
176+
}
177+
};
180178

181179
return SimpleDb.openOrCreate(this.dbName, SCHEMA_VERSION, createOrUpgradeDb)
182180
.then(db => {
183181
this.simpleDb = db;
184182
})
185183
.then(() => {
184+
this.document.addEventListener(
185+
'visibilitychange',
186+
this.documentVisibilityHandler
187+
);
186188
this.refreshClientState();
187189
this.scheduleClientStateRefresh();
188190
this.attachWindowUnloadHook();

packages/firestore/test/unit/specs/spec_test_runner.ts

+42-34
Original file line numberDiff line numberDiff line change
@@ -348,7 +348,7 @@ abstract class TestRunner {
348348

349349
constructor(
350350
private readonly name: string,
351-
protected readonly platform: MockPlatform,
351+
protected readonly platform: TestPlatform,
352352
config: SpecConfig
353353
) {
354354
this.databaseInfo = new DatabaseInfo(
@@ -812,7 +812,7 @@ abstract class TestRunner {
812812

813813
private doApplyClientState(state: SpecClientState): Promise<void> {
814814
if (state.visibility) {
815-
this.platform.fireVisibilityEvent(state.visibility!);
815+
this.platform.raiseVisibilityEvent(state.visibility!);
816816
}
817817
return Promise.resolve();
818818
}
@@ -1033,49 +1033,53 @@ class MemoryTestRunner extends TestRunner {
10331033
}
10341034

10351035
/**
1036-
* Implementation of `Platform` that allows mocking of `visibilitychange`
1037-
* events.
1038-
* */
1039-
class MockPlatform implements Platform {
1040-
private visibilityState: VisibilityState = 'unloaded';
1041-
private visibilityListener: EventListener | null = null;
1042-
private mockDocument: Document;
1043-
1044-
constructor(private readonly basePlatform: Platform) {
1045-
this.initMockDocument();
1046-
}
1047-
1048-
initMockDocument() {
1049-
this.mockDocument = {
1050-
visibilityState: this.visibilityState,
1051-
addEventListener: (type: string, listener: EventListener) => {
1052-
assert(
1053-
type === 'visibilitychange',
1054-
"MockPlatform only supports events of type 'visibilitychange'"
1055-
);
1056-
this.visibilityListener = listener;
1057-
},
1058-
removeEventListener: (type: string, listener: EventListener) => {
1059-
if (listener === this.visibilityListener) {
1060-
this.visibilityListener = null;
1061-
}
1062-
}
1063-
} as any; // tslint:disable-line:no-any Not implementing the entire document interface
1036+
* `Document` mock that implements the `visibilitychange` API used by Firestore.
1037+
*/
1038+
class MockDocument {
1039+
private _visibilityState: VisibilityState = 'unloaded';
1040+
private visibilityListener: EventListener | null;
1041+
1042+
get visibilityState(): VisibilityState {
1043+
return this._visibilityState;
10641044
}
10651045

1066-
fireVisibilityEvent(visibility: VisibilityState) {
1067-
this.visibilityState = visibility;
1046+
addEventListener(type: string, listener: EventListener) {
1047+
assert(
1048+
type === 'visibilitychange',
1049+
"MockDocument only supports events of type 'visibilitychange'"
1050+
);
1051+
this.visibilityListener = listener;
1052+
}
1053+
1054+
removeEventListener(type: string, listener: EventListener) {
1055+
if (listener === this.visibilityListener) {
1056+
this.visibilityListener = null;
1057+
}
1058+
}
1059+
1060+
raiseVisibilityEvent(visibility: VisibilityState) {
1061+
this._visibilityState = visibility;
10681062
if (this.visibilityListener) {
10691063
this.visibilityListener(new Event('visibilitychange'));
10701064
}
10711065
}
1066+
}
1067+
1068+
/**
1069+
* Implementation of `Platform` that allows mocking of `document` and `window`.
1070+
*/
1071+
class TestPlatform implements Platform {
1072+
private mockDocument = new MockDocument();
1073+
1074+
constructor(private readonly basePlatform: Platform) {}
10721075

10731076
get window(): Window | null {
10741077
return this.basePlatform.window;
10751078
}
10761079

10771080
get document(): Document {
1078-
return this.mockDocument;
1081+
// tslint:disable-next-line:no-any MockDocument doesn't support full Document interface.
1082+
return (this.mockDocument as any) as Document;
10791083
}
10801084

10811085
get base64Available(): boolean {
@@ -1086,6 +1090,10 @@ class MockPlatform implements Platform {
10861090
return this.basePlatform.emptyByteString;
10871091
}
10881092

1093+
raiseVisibilityEvent(visibility: VisibilityState) {
1094+
this.mockDocument.raiseVisibilityEvent(visibility);
1095+
}
1096+
10891097
loadConnection(databaseInfo: DatabaseInfo): Promise<Connection> {
10901098
return this.basePlatform.loadConnection(databaseInfo);
10911099
}
@@ -1140,7 +1148,7 @@ export async function runSpec(
11401148
steps: SpecStep[]
11411149
): Promise<void> {
11421150
console.log('Running spec: ' + name);
1143-
const platform = new MockPlatform(PlatformSupport.getPlatform());
1151+
const platform = new TestPlatform(PlatformSupport.getPlatform());
11441152
let runners: TestRunner[] = [];
11451153
for (let i = 0; i < config.numClients; ++i) {
11461154
if (usePersistence) {

0 commit comments

Comments
 (0)