From 2ce95696fe01f8c0fde08daa4359e39917654441 Mon Sep 17 00:00:00 2001 From: Mila <107142260+milaGGL@users.noreply.github.com> Date: Tue, 14 May 2024 13:58:30 -0400 Subject: [PATCH] Fix multi tab persistence issue (#8247) --- .changeset/nine-rings-jog.md | 6 +++ .../firestore/src/core/sync_engine_impl.ts | 3 +- .../test/unit/specs/query_spec.test.ts | 40 ++++++++++++++++++- 3 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 .changeset/nine-rings-jog.md diff --git a/.changeset/nine-rings-jog.md b/.changeset/nine-rings-jog.md new file mode 100644 index 00000000000..20a1d8b3d6d --- /dev/null +++ b/.changeset/nine-rings-jog.md @@ -0,0 +1,6 @@ +--- +'@firebase/firestore': patch +'firebase': patch +--- + +Fix multi-tab persistence raising empty snapshot issue diff --git a/packages/firestore/src/core/sync_engine_impl.ts b/packages/firestore/src/core/sync_engine_impl.ts index f4db6f4a5bd..bba07f4f4bc 100644 --- a/packages/firestore/src/core/sync_engine_impl.ts +++ b/packages/firestore/src/core/sync_engine_impl.ts @@ -1095,9 +1095,10 @@ export async function syncEngineEmitNewSnapsAndNotifyLocalStore( // secondary clients to update query state. if (viewSnapshot || remoteEvent) { if (syncEngineImpl.isPrimaryClient) { + const isCurrent = viewSnapshot && !viewSnapshot.fromCache; syncEngineImpl.sharedClientState.updateQueryState( queryView.targetId, - viewSnapshot?.fromCache ? 'not-current' : 'current' + isCurrent ? 'current' : 'not-current' ); } } diff --git a/packages/firestore/test/unit/specs/query_spec.test.ts b/packages/firestore/test/unit/specs/query_spec.test.ts index 5e9736db95b..9046540a2ff 100644 --- a/packages/firestore/test/unit/specs/query_spec.test.ts +++ b/packages/firestore/test/unit/specs/query_spec.test.ts @@ -24,7 +24,7 @@ import { Document } from '../../../src/model/document'; import { doc, filter, query } from '../../util/helpers'; import { describeSpec, specTest } from './describe_spec'; -import { spec, SpecBuilder } from './spec_builder'; +import { client, spec, SpecBuilder } from './spec_builder'; // Helper to seed the cache with the specified docs by listening to each one. function specWithCachedDocs(...docs: Document[]): SpecBuilder { @@ -136,4 +136,42 @@ describeSpec('Queries:', [], () => { ); } ); + + specTest( + 'Queries in different tabs will not interfere', + ['multi-client'], + () => { + const query1 = query('collection', filter('key', '==', 'a')); + const query2 = query('collection', filter('key', '==', 'b')); + const docA = doc('collection/a', 1000, { key: 'a' }); + const docB = doc('collection/b', 1000, { key: 'b' }); + + return ( + client(0) + .becomeVisible() + // Listen to the first query in the primary client + .expectPrimaryState(true) + .userListens(query1) + .watchAcks(query1) + .watchSends({ affects: [query1] }, docA) + + // Listen to different query in the secondary client + .client(1) + .userListens(query2) + + .client(0) + .expectListen(query2) + .watchCurrents(query1, 'resume-token-1000') + // Receive global snapshot before the second query is acknowledged + .watchSnapshots(1000) + .expectEvents(query1, { added: [docA] }) + // This should not trigger empty snapshot for second query(bugged behavior) + .client(1) + .client(0) + .watchAcksFull(query2, 2000, docB) + .client(1) + .expectEvents(query2, { added: [docB] }) + ); + } + ); });