Skip to content

Commit f4ea29e

Browse files
test(firestore): serverTimestamps integration + unit tests
1 parent 00fa8c5 commit f4ea29e

4 files changed

Lines changed: 143 additions & 0 deletions

File tree

packages/firestore/__tests__/firestore.test.ts

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1314,6 +1314,90 @@ describe('Firestore', function () {
13141314
);
13151315
});
13161316

1317+
it('FirestoreDocumentSnapshot.data() respects SnapshotOptions.serverTimestamps', function () {
1318+
const firestore = getFirestore();
1319+
const snapshot = new FirestoreDocumentSnapshot(
1320+
// @ts-expect-error calling a private constructor directly which expects FirestoreInternal type
1321+
firestore,
1322+
{
1323+
data: { createdAt: [3] },
1324+
dataEstimate: { createdAt: [13, [123, 456]] },
1325+
dataPrevious: { createdAt: [13, [42, 0]] },
1326+
dataNone: { createdAt: [3] },
1327+
metadata: [false, true],
1328+
path: 'foo/bar',
1329+
exists: true,
1330+
},
1331+
null,
1332+
);
1333+
1334+
expect(snapshot.data()).toEqual({ createdAt: null });
1335+
expect(snapshot.data({ serverTimestamps: 'estimate' })?.createdAt).toBeInstanceOf(Timestamp);
1336+
expect(snapshot.data({ serverTimestamps: 'estimate' })?.createdAt).toMatchObject({
1337+
seconds: 123,
1338+
nanoseconds: 456,
1339+
});
1340+
expect(snapshot.data({ serverTimestamps: 'previous' })?.createdAt).toMatchObject({
1341+
seconds: 42,
1342+
nanoseconds: 0,
1343+
});
1344+
expect(snapshot.data({ serverTimestamps: 'none' })).toEqual({ createdAt: null });
1345+
});
1346+
1347+
it('FirestoreDocumentSnapshot.get() respects SnapshotOptions.serverTimestamps', function () {
1348+
const firestore = getFirestore();
1349+
const snapshot = new FirestoreDocumentSnapshot(
1350+
// @ts-expect-error calling a private constructor directly which expects FirestoreInternal type
1351+
firestore,
1352+
{
1353+
data: { nested: [16, { createdAt: [3] }] },
1354+
dataEstimate: { nested: [16, { createdAt: [13, [123, 456]] }] },
1355+
dataPrevious: { nested: [16, { createdAt: [13, [42, 0]] }] },
1356+
dataNone: { nested: [16, { createdAt: [3] }] },
1357+
metadata: [false, true],
1358+
path: 'foo/bar',
1359+
exists: true,
1360+
},
1361+
null,
1362+
);
1363+
1364+
expect(snapshot.get('nested.createdAt')).toBeNull();
1365+
expect(snapshot.get('nested.createdAt', { serverTimestamps: 'estimate' })).toMatchObject({
1366+
seconds: 123,
1367+
nanoseconds: 456,
1368+
});
1369+
expect(snapshot.get('nested.createdAt', { serverTimestamps: 'previous' })).toMatchObject({
1370+
seconds: 42,
1371+
nanoseconds: 0,
1372+
});
1373+
expect(snapshot.get('nested.createdAt', { serverTimestamps: 'none' })).toBeNull();
1374+
});
1375+
1376+
it('FirestoreDocumentSnapshot.data() passes SnapshotOptions through converter snapshots', function () {
1377+
const firestore = getFirestore();
1378+
const snapshot = new FirestoreDocumentSnapshot(
1379+
// @ts-expect-error calling a private constructor directly which expects FirestoreInternal type
1380+
firestore,
1381+
{
1382+
data: { createdAt: [3] },
1383+
dataEstimate: { createdAt: [13, [123, 456]] },
1384+
metadata: [false, true],
1385+
path: 'foo/bar',
1386+
exists: true,
1387+
},
1388+
{
1389+
toFirestore: data => data,
1390+
fromFirestore: converterSnapshot =>
1391+
converterSnapshot.data({ serverTimestamps: 'estimate' }),
1392+
},
1393+
);
1394+
1395+
expect(snapshot.data()?.createdAt).toMatchObject({
1396+
seconds: 123,
1397+
nanoseconds: 456,
1398+
});
1399+
});
1400+
13171401
describe('FieldValue', function () {
13181402
it('FieldValue.delete()', function () {
13191403
const fieldValue = firestore.FieldValue;

packages/firestore/consumer-type-test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -348,9 +348,12 @@ nsQuery.get().then((snap: FirebaseFirestoreTypes.QuerySnapshot) => {
348348
nsDocRef.get().then((snap: FirebaseFirestoreTypes.DocumentSnapshot) => {
349349
if (snap.exists()) {
350350
const d = snap.data();
351+
const estimate = snap.data({ serverTimestamps: 'estimate' });
351352
void d;
353+
void estimate;
352354
}
353355
void snap.get('field');
356+
void snap.get('field', { serverTimestamps: 'previous' });
354357
void snap.metadata.isEqual(snap.metadata);
355358
});
356359

@@ -638,6 +641,8 @@ getAggregateFromServer(modQuery1, aggSpec).then(
638641

639642
// ----- getDoc, getDocFromCache, getDocFromServer -----
640643
getDoc(modDoc).then(snap => snap.data());
644+
getDoc(modDoc).then(snap => snap.data({ serverTimestamps: 'estimate' }));
645+
getDoc(modDoc).then(snap => snap.get('field', { serverTimestamps: 'previous' }));
641646
getDocFromCache(modDoc).then(snap => snap.data());
642647
getDocFromServer(modDoc).then(snap => snap.data());
643648

packages/firestore/e2e/withConverter.e2e.js

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,14 @@ const {
2525
addDoc,
2626
setDoc,
2727
getDoc,
28+
onSnapshot,
2829
query,
2930
where,
3031
getDocs,
3132
writeBatch,
3233
increment,
34+
serverTimestamp,
35+
Timestamp,
3336
initializeFirestore,
3437
} = firestoreModular;
3538

@@ -590,6 +593,52 @@ describe('firestore.withConverter', function () {
590593
});
591594
});
592595

596+
it("passes data() serverTimestamps options through converter snapshots", function () {
597+
const timestampConverter = {
598+
toFirestore() {
599+
return {
600+
createdAt: serverTimestamp(),
601+
updatedAt: serverTimestamp(),
602+
};
603+
},
604+
fromFirestore(snapshot) {
605+
return snapshot.data({ serverTimestamps: 'estimate' });
606+
},
607+
};
608+
609+
return withTestCollection(async coll => {
610+
const ref = doc(coll, 'timestampConverter').withConverter(timestampConverter);
611+
await new Promise((resolve, reject) => {
612+
const unsubscribe = onSnapshot(
613+
ref,
614+
{ includeMetadataChanges: true },
615+
snapshot => {
616+
try {
617+
if (!snapshot.exists() || !snapshot.metadata.hasPendingWrites) {
618+
return;
619+
}
620+
621+
const data = snapshot.data();
622+
data.createdAt.should.be.an.instanceOf(Timestamp);
623+
data.updatedAt.should.be.an.instanceOf(Timestamp);
624+
unsubscribe();
625+
resolve();
626+
} catch (error) {
627+
unsubscribe();
628+
reject(error);
629+
}
630+
},
631+
reject,
632+
);
633+
634+
setDoc(ref, {}).catch(error => {
635+
unsubscribe();
636+
reject(error);
637+
});
638+
});
639+
});
640+
});
641+
593642
it('supports partials with merge', async function () {
594643
return withTestCollection(async coll => {
595644
const ref = doc(coll, 'post').withConverter(postConverterMerge);

packages/firestore/type-test.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -342,9 +342,12 @@ nsQuery.get().then((snap: FirebaseFirestoreTypes.QuerySnapshot) => {
342342
nsDocRef.get().then((snap: FirebaseFirestoreTypes.DocumentSnapshot) => {
343343
if (snap.exists()) {
344344
const d = snap.data();
345+
const estimate = snap.data({ serverTimestamps: 'estimate' });
345346
console.log(d);
347+
console.log(estimate);
346348
}
347349
console.log(snap.get('field'));
350+
console.log(snap.get('field', { serverTimestamps: 'previous' }));
348351
console.log(snap.metadata.isEqual(snap.metadata));
349352
});
350353

@@ -642,6 +645,8 @@ getAggregateFromServer(modQuery1, aggSpec).then(
642645

643646
// ----- getDoc, getDocFromCache, getDocFromServer -----
644647
getDoc(modDoc).then(snap => snap.data());
648+
getDoc(modDoc).then(snap => snap.data({ serverTimestamps: 'estimate' }));
649+
getDoc(modDoc).then(snap => snap.get('field', { serverTimestamps: 'previous' }));
645650
getDocFromCache(modDoc).then(snap => snap.data());
646651
getDocFromServer(modDoc).then(snap => snap.data());
647652

0 commit comments

Comments
 (0)