Skip to content

Commit 2ce9569

Browse files
authored
Fix multi tab persistence issue (#8247)
1 parent 9cbb184 commit 2ce9569

File tree

3 files changed

+47
-2
lines changed

3 files changed

+47
-2
lines changed

.changeset/nine-rings-jog.md

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
'@firebase/firestore': patch
3+
'firebase': patch
4+
---
5+
6+
Fix multi-tab persistence raising empty snapshot issue

packages/firestore/src/core/sync_engine_impl.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -1095,9 +1095,10 @@ export async function syncEngineEmitNewSnapsAndNotifyLocalStore(
10951095
// secondary clients to update query state.
10961096
if (viewSnapshot || remoteEvent) {
10971097
if (syncEngineImpl.isPrimaryClient) {
1098+
const isCurrent = viewSnapshot && !viewSnapshot.fromCache;
10981099
syncEngineImpl.sharedClientState.updateQueryState(
10991100
queryView.targetId,
1100-
viewSnapshot?.fromCache ? 'not-current' : 'current'
1101+
isCurrent ? 'current' : 'not-current'
11011102
);
11021103
}
11031104
}

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

+39-1
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ import { Document } from '../../../src/model/document';
2424
import { doc, filter, query } from '../../util/helpers';
2525

2626
import { describeSpec, specTest } from './describe_spec';
27-
import { spec, SpecBuilder } from './spec_builder';
27+
import { client, spec, SpecBuilder } from './spec_builder';
2828

2929
// Helper to seed the cache with the specified docs by listening to each one.
3030
function specWithCachedDocs(...docs: Document[]): SpecBuilder {
@@ -136,4 +136,42 @@ describeSpec('Queries:', [], () => {
136136
);
137137
}
138138
);
139+
140+
specTest(
141+
'Queries in different tabs will not interfere',
142+
['multi-client'],
143+
() => {
144+
const query1 = query('collection', filter('key', '==', 'a'));
145+
const query2 = query('collection', filter('key', '==', 'b'));
146+
const docA = doc('collection/a', 1000, { key: 'a' });
147+
const docB = doc('collection/b', 1000, { key: 'b' });
148+
149+
return (
150+
client(0)
151+
.becomeVisible()
152+
// Listen to the first query in the primary client
153+
.expectPrimaryState(true)
154+
.userListens(query1)
155+
.watchAcks(query1)
156+
.watchSends({ affects: [query1] }, docA)
157+
158+
// Listen to different query in the secondary client
159+
.client(1)
160+
.userListens(query2)
161+
162+
.client(0)
163+
.expectListen(query2)
164+
.watchCurrents(query1, 'resume-token-1000')
165+
// Receive global snapshot before the second query is acknowledged
166+
.watchSnapshots(1000)
167+
.expectEvents(query1, { added: [docA] })
168+
// This should not trigger empty snapshot for second query(bugged behavior)
169+
.client(1)
170+
.client(0)
171+
.watchAcksFull(query2, 2000, docB)
172+
.client(1)
173+
.expectEvents(query2, { added: [docB] })
174+
);
175+
}
176+
);
139177
});

0 commit comments

Comments
 (0)