Skip to content

Commit d782139

Browse files
authored
Merge 1fcebae into b516abd
2 parents b516abd + 1fcebae commit d782139

File tree

1 file changed

+57
-0
lines changed

1 file changed

+57
-0
lines changed

packages/firestore/test/integration/api/query.test.ts

+57
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ import {
4747
Query,
4848
query,
4949
QuerySnapshot,
50+
runTransaction,
5051
setDoc,
5152
startAfter,
5253
startAt,
@@ -2059,6 +2060,62 @@ apiDescribe('Queries', (persistence: boolean) => {
20592060
});
20602061
});
20612062
});
2063+
2064+
it('resuming a query should use existence filter to detect deletes', async () => {
2065+
// Prepare the names and contents of the 100 documents to create.
2066+
const testDocs: { [key: string]: object } = {};
2067+
for (let i = 0; i < 100; i++) {
2068+
testDocs['doc' + (1000 + i)] = { key: 42 };
2069+
}
2070+
2071+
return withTestCollection(persistence, testDocs, async (coll, db) => {
2072+
// Run a query to populate the local cache with the 100 documents and a
2073+
// resume token.
2074+
const snapshot1 = await getDocs(coll);
2075+
expect(snapshot1.size, 'snapshot1.size').to.equal(100);
2076+
const createdDocuments = snapshot1.docs.map(snapshot => snapshot.ref);
2077+
2078+
// Delete 50 of the 100 documents. Do this in a transaction, rather than
2079+
// deleteDoc(), to avoid affecting the local cache.
2080+
const deletedDocumentIds = new Set<string>();
2081+
await runTransaction(db, async txn => {
2082+
for (let i = 0; i < createdDocuments.length; i += 2) {
2083+
const documentToDelete = createdDocuments[i];
2084+
txn.delete(documentToDelete);
2085+
deletedDocumentIds.add(documentToDelete.id);
2086+
}
2087+
});
2088+
2089+
// Wait for 10 seconds, during which Watch will stop tracking the query
2090+
// and will send an existence filter rather than "delete" events when the
2091+
// query is resumed.
2092+
await new Promise(resolve => setTimeout(resolve, 10000));
2093+
2094+
// Resume the query and save the resulting snapshot for verification.
2095+
const snapshot2 = await getDocs(coll);
2096+
2097+
// Verify that the snapshot from the resumed query contains the expected
2098+
// documents; that is, that it contains the 50 documents that were _not_
2099+
// deleted.
2100+
// TODO(b/270731363): Remove the "if" condition below once the
2101+
// Firestore Emulator is fixed to send an existence filter. At the time of
2102+
// writing, the Firestore emulator fails to send an existence filter,
2103+
// resulting in the client including the deleted documents in the snapshot
2104+
// of the resumed query.
2105+
if (!(USE_EMULATOR && snapshot2.size === 100)) {
2106+
const actualDocumentIds = snapshot2.docs
2107+
.map(documentSnapshot => documentSnapshot.ref.id)
2108+
.sort();
2109+
const expectedDocumentIds = createdDocuments
2110+
.filter(documentRef => !deletedDocumentIds.has(documentRef.id))
2111+
.map(documentRef => documentRef.id)
2112+
.sort();
2113+
expect(actualDocumentIds, 'snapshot2.docs').to.deep.equal(
2114+
expectedDocumentIds
2115+
);
2116+
}
2117+
});
2118+
}).timeout('90s');
20622119
});
20632120

20642121
function verifyDocumentChange<T>(

0 commit comments

Comments
 (0)