firestore-node-mock 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,610 @@
1
+ // @ts-nocheck
2
+ import { mock } from 'node:test';
3
+
4
+ import * as timestamp from './timestamp.js';
5
+ import * as fieldValue from './fieldValue.js';
6
+ import * as query from './query.js';
7
+ import * as transaction from './transaction.js';
8
+ import * as path from './path.js';
9
+
10
+ import buildDocFromHash from './helpers/buildDocFromHash.js';
11
+ import buildQuerySnapShot from './helpers/buildQuerySnapShot.js';
12
+
13
+ export const mockCollectionGroup = mock.fn();
14
+ export const mockBatch = mock.fn();
15
+ export const mockRunTransaction = mock.fn();
16
+ export const mockRecursiveDelete = mock.fn();
17
+
18
+ export const mockSettings = mock.fn();
19
+ export const mockUseEmulator = mock.fn();
20
+ export const mockCollection = mock.fn();
21
+ export const mockDoc = mock.fn();
22
+ export const mockCreate = mock.fn();
23
+ export const mockUpdate = mock.fn();
24
+ export const mockSet = mock.fn();
25
+ export const mockAdd = mock.fn();
26
+ export const mockDelete = mock.fn();
27
+ export const mockListDocuments = mock.fn();
28
+ export const mockListCollections = mock.fn();
29
+
30
+ export const mockBatchDelete = mock.fn();
31
+ export const mockBatchCommit = mock.fn();
32
+ export const mockBatchUpdate = mock.fn();
33
+ export const mockBatchSet = mock.fn();
34
+ export const mockBatchCreate = mock.fn();
35
+
36
+ export const mockOnSnapShot = mock.fn();
37
+
38
+ const _randomId = () => Math.floor(Math.random() * Number.MAX_SAFE_INTEGER).toString();
39
+
40
+ // @ts-ignore
41
+ export class FakeFirestore {
42
+ constructor(stubbedDatabase = {}, options = {}) {
43
+ this.database = timestamp.convertTimestamps(stubbedDatabase);
44
+ this.query = new query.Query('', this);
45
+ this.options = options;
46
+ }
47
+
48
+ set collectionName(collectionName) {
49
+ this.query.collectionName = collectionName;
50
+ this.recordToFetch = null;
51
+ }
52
+
53
+ get collectionName() {
54
+ return this.query.collectionName;
55
+ }
56
+
57
+ getAll(...params) {
58
+ //Strip ReadOptions object
59
+ params = params.filter(arg => arg instanceof FakeFirestore.DocumentReference);
60
+
61
+ return Promise.all(transaction.mocks.mockGetAll(...params) || [...params].map(r => r.get()));
62
+ }
63
+
64
+ /**
65
+ * @returns {import('./firestore.js').FirestoreBatch}
66
+ */
67
+ batch() {
68
+ mockBatch(...arguments);
69
+ return {
70
+ _ref: this,
71
+ delete() {
72
+ mockBatchDelete(...arguments);
73
+ return this;
74
+ },
75
+ set(doc, data, setOptions = {}) {
76
+ mockBatchSet(...arguments);
77
+ this._ref._updateData(doc.path, data, setOptions.merge);
78
+ return this;
79
+ },
80
+ update(doc, data) {
81
+ mockBatchUpdate(...arguments);
82
+ this._ref._updateData(doc.path, data, true);
83
+ return this;
84
+ },
85
+ create(doc, data) {
86
+ mockBatchCreate(...arguments);
87
+ this._ref._updateData(doc.path, data, false);
88
+ return this;
89
+ },
90
+ commit() {
91
+ mockBatchCommit(...arguments);
92
+ return Promise.resolve([]);
93
+ },
94
+ };
95
+ }
96
+
97
+ settings() {
98
+ mockSettings(...arguments);
99
+ return;
100
+ }
101
+
102
+ useEmulator() {
103
+ mockUseEmulator(...arguments);
104
+ }
105
+
106
+ collection(path) {
107
+ // Accept any collection path
108
+ // See https://firebase.google.com/docs/reference/js/firestore_#collection
109
+ mockCollection(...arguments);
110
+
111
+ if (path === undefined) {
112
+ throw new Error(
113
+ `FakeFirebaseError: Function Firestore.collection() requires 1 argument, but was called with 0 arguments.`,
114
+ );
115
+ } else if (!path || typeof path !== 'string') {
116
+ throw new Error(
117
+ `FakeFirebaseError: Function Firestore.collection() requires its first argument to be of type non-empty string, but it was: ${JSON.stringify(
118
+ path,
119
+ )}`,
120
+ );
121
+ }
122
+
123
+ // Ignore leading slash
124
+ const pathArray = path.replace(/^\/+/, '').split('/');
125
+ // Must be collection-level, so odd-numbered elements
126
+ if (pathArray.length % 2 !== 1) {
127
+ throw new Error(
128
+ `FakeFirebaseError: Invalid collection reference. Collection references must have an odd number of segments, but ${path} has ${pathArray.length}`,
129
+ );
130
+ }
131
+
132
+ const { coll } = this._docAndColForPathArray(pathArray);
133
+ return coll;
134
+ }
135
+
136
+ collectionGroup(collectionId) {
137
+ mockCollectionGroup(...arguments);
138
+ return new FakeFirestore.Query(collectionId, this, true);
139
+ }
140
+
141
+ doc(path) {
142
+ mockDoc(path);
143
+ return this._doc(path);
144
+ }
145
+
146
+ _doc(path) {
147
+ // Accept any document path
148
+ // See https://firebase.google.com/docs/reference/js/firestore_#doc
149
+
150
+ if (path === undefined) {
151
+ throw new Error(
152
+ `FakeFirebaseError: Function Firestore.doc() requires 1 argument, but was called with 0 arguments.`,
153
+ );
154
+ } else if (!path || typeof path !== 'string') {
155
+ throw new Error(
156
+ `FakeFirebaseError: Function Firestore.doc() requires its first argument to be of type non-empty string, but it was: ${JSON.stringify(
157
+ path,
158
+ )}`,
159
+ );
160
+ }
161
+
162
+ // Ignore leading slash
163
+ const pathArray = path.replace(/^\/+/, '').split('/');
164
+ // Must be document-level, so even-numbered elements
165
+ if (pathArray.length % 2 !== 0) {
166
+ throw new Error(`FakeFirebaseError: Invalid document reference. Document references must have an even number of segments, but ${path} has ${pathArray.length}
167
+ `);
168
+ }
169
+
170
+ const { doc } = this._docAndColForPathArray(pathArray);
171
+ return doc;
172
+ }
173
+
174
+ _docAndColForPathArray(pathArray) {
175
+ let doc = null;
176
+ let coll = null;
177
+ for (let index = 0; index < pathArray.length; index += 2) {
178
+ const collectionId = pathArray[index] || '';
179
+ const documentId = pathArray[index + 1] || '';
180
+
181
+ coll = new FakeFirestore.CollectionReference(collectionId, doc, this);
182
+ if (!documentId) {
183
+ break;
184
+ }
185
+ doc = new FakeFirestore.DocumentReference(documentId, coll);
186
+ }
187
+
188
+ return { doc, coll };
189
+ }
190
+
191
+ runTransaction(updateFunction) {
192
+ mockRunTransaction(...arguments);
193
+ return updateFunction(new FakeFirestore.Transaction());
194
+ }
195
+
196
+ _updateData(path, object, merge) {
197
+ // Do not update unless explicity set to mutable.
198
+ if (!this.options.mutable) {
199
+ return;
200
+ }
201
+
202
+ // note: this logic could be deduplicated
203
+ const pathArray = path.replace(/^\/+/, '').split('/');
204
+
205
+ // Must be document-level, so even-numbered elements
206
+ if (pathArray.length % 2 !== 0) {
207
+ throw new Error(
208
+ `FakeFirebaseError: Invalid document reference. Document references must have an even number of segments, but ${path} has ${pathArray.length}`,
209
+ );
210
+ }
211
+
212
+ // The parent entry is the id of the document
213
+ const docId = pathArray.pop();
214
+ // Find the parent of docId. Run through the path, creating missing entries
215
+ const parent = pathArray.reduce((last, entry, index) => {
216
+ const isCollection = index % 2 === 0;
217
+ if (isCollection) {
218
+ return last[entry] || (last[entry] = []);
219
+ } else {
220
+ const existingDoc = last.find(doc => doc.id === entry);
221
+ if (existingDoc) {
222
+ // return _collections, creating it if it doesn't already exist
223
+ return existingDoc._collections || (existingDoc._collections = {});
224
+ }
225
+
226
+ const _collections = {};
227
+ last.push({ id: entry, _collections });
228
+ return _collections;
229
+ }
230
+ }, this.database);
231
+
232
+ // parent should now be an array of documents
233
+ // Replace existing data, if it's there, or add to the end of the array
234
+ const oldIndex = parent.findIndex(doc => doc.id === docId);
235
+ parent[oldIndex >= 0 ? oldIndex : parent.length] = {
236
+ ...(merge ? parent[oldIndex] : undefined),
237
+ ...object,
238
+ id: docId,
239
+ };
240
+ }
241
+
242
+ recursiveDelete(ref, bulkWriter) {
243
+ mockRecursiveDelete(...arguments);
244
+ return Promise.resolve();
245
+ }
246
+ }
247
+
248
+ FakeFirestore.Query = query.Query;
249
+ FakeFirestore.FieldValue = fieldValue.FieldValue;
250
+ FakeFirestore.Timestamp = timestamp.Timestamp;
251
+ FakeFirestore.Transaction = transaction.Transaction;
252
+ FakeFirestore.FieldPath = path.FieldPath;
253
+
254
+ /*
255
+ * ============
256
+ * Document Reference
257
+ * ============
258
+ */
259
+
260
+ /** @type {typeof import('./firestore.js').FakeFirestore.DocumentReference} */
261
+ FakeFirestore.DocumentReference = class DocumentReference {
262
+ constructor(id, parent) {
263
+ this.id = id;
264
+ this.parent = parent;
265
+ this.firestore = parent.firestore;
266
+ this.path = parent.path.split('/').concat(id).join('/');
267
+ }
268
+
269
+ collection(collectionName) {
270
+ mockCollection(...arguments);
271
+ return new FakeFirestore.CollectionReference(collectionName, this);
272
+ }
273
+
274
+ listCollections() {
275
+ mockListCollections();
276
+
277
+ const document = this._getRawObject();
278
+ if (!document._collections) {
279
+ return Promise.resolve([]);
280
+ }
281
+
282
+ const collectionRefs = [];
283
+ for (const collectionId of Object.keys(document._collections)) {
284
+ collectionRefs.push(new FakeFirestore.CollectionReference(collectionId, this));
285
+ }
286
+
287
+ return Promise.resolve(collectionRefs);
288
+ }
289
+
290
+ delete() {
291
+ mockDelete(...arguments);
292
+ return Promise.resolve();
293
+ }
294
+
295
+ onSnapshot() {
296
+ mockOnSnapShot(...arguments);
297
+ let callback;
298
+ let errorCallback;
299
+ // eslint-disable-next-line
300
+ let options;
301
+
302
+ try {
303
+ if (typeof arguments[0] === 'function') {
304
+ [callback, errorCallback] = arguments;
305
+ } else {
306
+ // eslint-disable-next-line no-unused-vars
307
+ [options, callback, errorCallback] = arguments;
308
+ }
309
+
310
+ callback(this._get());
311
+ } catch (e) {
312
+ if (errorCallback) {
313
+ errorCallback(e);
314
+ } else {
315
+ throw e;
316
+ }
317
+ }
318
+
319
+ // Returns an unsubscribe function
320
+ return () => {};
321
+ }
322
+
323
+ get() {
324
+ query.mocks.mockGet(...arguments);
325
+ const data = this._get();
326
+ return Promise.resolve(data);
327
+ }
328
+
329
+ create(object) {
330
+ mockCreate(...arguments);
331
+ this.firestore._updateData(this.path, object, false);
332
+ return Promise.resolve(
333
+ buildDocFromHash({ ...object, _ref: this, _updateTime: timestamp.Timestamp.now() }),
334
+ );
335
+ }
336
+
337
+ update(object) {
338
+ mockUpdate(...arguments);
339
+ if (this._get().exists) {
340
+ this.firestore._updateData(this.path, object, true);
341
+ }
342
+ return Promise.resolve(
343
+ buildDocFromHash({ ...object, _ref: this, _updateTime: timestamp.Timestamp.now() }),
344
+ );
345
+ }
346
+
347
+ set(object, setOptions = {}) {
348
+ mockSet(...arguments);
349
+ this.firestore._updateData(this.path, object, setOptions.merge);
350
+ return Promise.resolve(
351
+ buildDocFromHash({ ...object, _ref: this, _updateTime: timestamp.Timestamp.now() }),
352
+ );
353
+ }
354
+
355
+ isEqual(other) {
356
+ return (
357
+ other instanceof FakeFirestore.DocumentReference &&
358
+ other.firestore === this.firestore &&
359
+ other.path === this.path
360
+ );
361
+ }
362
+
363
+ orderBy() {
364
+ return this.query.orderBy(...arguments);
365
+ }
366
+
367
+ limit() {
368
+ return this.query.limit(...arguments);
369
+ }
370
+
371
+ offset() {
372
+ return this.query.offset(...arguments);
373
+ }
374
+
375
+ startAfter() {
376
+ return this.query.startAfter(...arguments);
377
+ }
378
+
379
+ startAt() {
380
+ return this.query.startAt(...arguments);
381
+ }
382
+
383
+ /**
384
+ * A private method for internal use.
385
+ * @returns {Object|null} The raw object of the document or null.
386
+ */
387
+ _getRawObject() {
388
+ // Ignore leading slash
389
+ const pathArray = this.path.replace(/^\/+/, '').split('/');
390
+
391
+ if (pathArray[0] === 'database') {
392
+ pathArray.shift(); // drop 'database'; it was included in legacy paths, but we don't need it now
393
+ }
394
+
395
+ let requestedRecords = this.firestore.database[pathArray.shift()];
396
+ let document = null;
397
+ if (requestedRecords) {
398
+ const documentId = pathArray.shift();
399
+ document = requestedRecords.find(record => record.id === documentId);
400
+ } else {
401
+ return null;
402
+ }
403
+
404
+ for (let index = 0; index < pathArray.length; index += 2) {
405
+ const collectionId = pathArray[index];
406
+ const documentId = pathArray[index + 1];
407
+
408
+ if (!document || !document._collections) {
409
+ return null;
410
+ }
411
+ requestedRecords = document._collections[collectionId] || [];
412
+ if (requestedRecords.length === 0) {
413
+ return null;
414
+ }
415
+
416
+ document = requestedRecords.find(record => record.id === documentId);
417
+ if (!document) {
418
+ return null;
419
+ }
420
+
421
+ // +2 skips to next document
422
+ }
423
+
424
+ if (!!document || false) {
425
+ return document;
426
+ }
427
+ return null;
428
+ }
429
+
430
+ _get() {
431
+ const document = this._getRawObject();
432
+
433
+ if (document) {
434
+ document._ref = this;
435
+ document._readTime = timestamp.Timestamp.now();
436
+ return buildDocFromHash(document);
437
+ } else {
438
+ return {
439
+ createTime: undefined,
440
+ exists: false,
441
+ data: () => undefined,
442
+ id: this.id,
443
+ readTime: undefined,
444
+ ref: this,
445
+ updateTime: undefined,
446
+ };
447
+ }
448
+ }
449
+
450
+ /**
451
+ * @returns {DocumentReference}
452
+ */
453
+ withConverter() {
454
+ query.mocks.mockWithConverter(...arguments);
455
+ return this;
456
+ }
457
+ };
458
+
459
+ /*
460
+ * ============
461
+ * Collection Reference
462
+ * ============
463
+ */
464
+
465
+ FakeFirestore.CollectionReference = class CollectionReference extends FakeFirestore.Query {
466
+ constructor(id, parent, firestore) {
467
+ super(id, firestore || parent.firestore);
468
+
469
+ this.id = id;
470
+ this.parent = parent;
471
+ if (parent) {
472
+ this.path = parent.path.concat(`/${id}`);
473
+ } else {
474
+ this.path = id;
475
+ }
476
+ }
477
+
478
+ add(object) {
479
+ mockAdd(...arguments);
480
+ const newDoc = new FakeFirestore.DocumentReference(_randomId(), this);
481
+ this.firestore._updateData(newDoc.path, object);
482
+ return Promise.resolve(newDoc);
483
+ }
484
+
485
+ doc(id = _randomId()) {
486
+ mockDoc(id);
487
+ return new FakeFirestore.DocumentReference(id, this, this.firestore);
488
+ }
489
+
490
+ /**
491
+ * A private method, meant mainly to be used by `get` and other internal objects to retrieve
492
+ * the list of database records referenced by this CollectionReference.
493
+ * @returns {Object[]} An array of mocked document records.
494
+ */
495
+ _records() {
496
+ // Support subcollections as paths: "collection/documentId/subcollection"
497
+ if (this.firestore.database[this.path]) {
498
+ return this.firestore.database[this.path];
499
+ }
500
+
501
+ // Ignore leading slash
502
+ const pathArray = this.path.replace(/^\/+/, '').split('/');
503
+
504
+ let requestedRecords = this.firestore.database[pathArray.shift()];
505
+ if (pathArray.length === 0) {
506
+ return requestedRecords || [];
507
+ }
508
+
509
+ // Since we're a collection, we can assume that pathArray.length % 2 is always 0
510
+
511
+ for (let index = 0; index < pathArray.length; index += 2) {
512
+ const documentId = pathArray[index];
513
+ const collectionId = pathArray[index + 1];
514
+
515
+ if (!requestedRecords) {
516
+ return [];
517
+ }
518
+ const document = requestedRecords.find(record => record.id === documentId);
519
+ if (!document || !document._collections) {
520
+ return [];
521
+ }
522
+
523
+ requestedRecords = document._collections[collectionId] || [];
524
+ if (requestedRecords.length === 0) {
525
+ return [];
526
+ }
527
+
528
+ // +2 skips to next collection
529
+ }
530
+ return requestedRecords;
531
+ }
532
+
533
+ listDocuments() {
534
+ mockListDocuments();
535
+ // Returns all documents, including documents with no data but with
536
+ // subcollections: see https://googleapis.dev/nodejs/firestore/latest/CollectionReference.html#listDocuments
537
+ return Promise.resolve(
538
+ this._records().map(rec => new FakeFirestore.DocumentReference(rec.id, this, this.firestore)),
539
+ );
540
+ }
541
+
542
+ get() {
543
+ query.mocks.mockGet(...arguments);
544
+ return Promise.resolve(this._get());
545
+ }
546
+
547
+ _get() {
548
+ // Make sure we have a 'good enough' document reference
549
+ const records = this._records().map(rec => ({
550
+ ...rec,
551
+ _ref: new FakeFirestore.DocumentReference(rec.id, this, this.firestore),
552
+ }));
553
+ // Firestore does not return documents with no local data
554
+ const isFilteringEnabled = this.firestore.options.simulateQueryFilters;
555
+ return buildQuerySnapShot(
556
+ records,
557
+ isFilteringEnabled ? this.filters : undefined,
558
+ this.selectFields,
559
+ );
560
+ }
561
+
562
+ isEqual(other) {
563
+ return (
564
+ other instanceof FakeFirestore.CollectionReference &&
565
+ other.firestore === this.firestore &&
566
+ other.path === this.path
567
+ );
568
+ }
569
+ };
570
+
571
+ // Re-exporting mocks from other modules for convenience (keeping backward compatibility with original structure)
572
+ export const {
573
+ mockGet,
574
+ mockSelect,
575
+ mockWhere,
576
+ mockLimit,
577
+ mockOrderBy,
578
+ mockOffset,
579
+ mockStartAfter,
580
+ mockStartAt,
581
+ mockQueryOnSnapshot,
582
+ mockQueryOnSnapshotUnsubscribe,
583
+ mockWithConverter
584
+ } = query.mocks;
585
+
586
+ export const {
587
+ mockGetAll,
588
+ mockGetAllTransaction,
589
+ mockGetTransaction,
590
+ mockSetTransaction,
591
+ mockUpdateTransaction,
592
+ mockDeleteTransaction,
593
+ mockCreateTransaction
594
+ } = transaction.mocks;
595
+
596
+ export const {
597
+ mockArrayUnionFieldValue,
598
+ mockArrayRemoveFieldValue,
599
+ mockDeleteFieldValue,
600
+ mockIncrementFieldValue,
601
+ mockServerTimestampFieldValue
602
+ } = fieldValue.mocks;
603
+
604
+ export const {
605
+ mockTimestampToDate,
606
+ mockTimestampToMillis,
607
+ mockTimestampFromDate,
608
+ mockTimestampFromMillis,
609
+ mockTimestampNow
610
+ } = timestamp.mocks;
@@ -0,0 +1,20 @@
1
+ import type { StubOverrides, StubOptions } from './firebase.js';
2
+ import type { FakeFirestore } from './firestore.js';
3
+
4
+ declare class Firestore extends FakeFirestore {
5
+ constructor();
6
+ }
7
+
8
+ interface GCloudFirestoreMock {
9
+ Firestore: typeof Firestore;
10
+ Query: typeof Firestore.Query;
11
+ CollectionReference: typeof Firestore.CollectionReference;
12
+ DocumentReference: typeof Firestore.DocumentReference;
13
+ FieldValue: typeof Firestore.FieldValue;
14
+ FieldPath: typeof Firestore.FieldPath;
15
+ Timestamp: typeof Firestore.Timestamp;
16
+ Transaction: typeof Firestore.Transaction;
17
+ }
18
+
19
+ export const firestoreStub: (overrides: StubOverrides, options?: StubOptions) => GCloudFirestoreMock;
20
+ export const mockGoogleCloudFirestore: (overrides: StubOverrides, options?: StubOptions) => void;
@@ -0,0 +1,43 @@
1
+ import { mock } from 'node:test';
2
+ import { createRequire } from 'node:module';
3
+ import { FakeFirestore } from './firestore.js';
4
+ import defaultOptions from './helpers/defaultMockOptions.js';
5
+
6
+ const require = createRequire(import.meta.url);
7
+
8
+ export const firestoreStub = (overrides, options = defaultOptions) => {
9
+ class Firestore extends FakeFirestore {
10
+ constructor() {
11
+ super(overrides.database, options);
12
+ }
13
+ }
14
+ return {
15
+ Query: FakeFirestore.Query,
16
+ CollectionReference: FakeFirestore.CollectionReference,
17
+ DocumentReference: FakeFirestore.DocumentReference,
18
+ FieldValue: FakeFirestore.FieldValue,
19
+ FieldPath: FakeFirestore.FieldPath,
20
+ Timestamp: FakeFirestore.Timestamp,
21
+ Transaction: FakeFirestore.Transaction,
22
+ /** @type {Firestore.constructor} */
23
+ Firestore,
24
+ };
25
+ };
26
+
27
+ export const mockGoogleCloudFirestore = (overrides = {}, options = defaultOptions) => {
28
+ mockModuleIfFound('@google-cloud/firestore', overrides, options);
29
+ };
30
+
31
+ function mockModuleIfFound(moduleName, overrides, options) {
32
+ try {
33
+ require.resolve(moduleName);
34
+ const stub = firestoreStub(overrides, options);
35
+ mock.module(moduleName, {
36
+ defaultExport: stub,
37
+ namedExports: stub,
38
+ });
39
+ } catch (e) {
40
+ // eslint-disable-next-line no-console
41
+ console.info(`Module ${moduleName} not found, mocking skipped.`);
42
+ }
43
+ }
@@ -0,0 +1,28 @@
1
+ import type { FakeFirestore, FakeFirestoreDatabase } from '../firestore.js';
2
+
3
+ export type DocumentData = { [field: string]: unknown };
4
+
5
+ export interface DocumentHash extends DocumentData {
6
+ id?: string;
7
+ _collections: FakeFirestoreDatabase;
8
+ _createTime?: typeof FakeFirestore.Timestamp;
9
+ _readTime?: typeof FakeFirestore.Timestamp;
10
+ _ref: typeof FakeFirestore.DocumentReference;
11
+ _updateTime?: typeof FakeFirestore.Timestamp;
12
+ }
13
+
14
+ export interface MockedDocument<T = DocumentData> {
15
+ createTime: typeof FakeFirestore.Timestamp;
16
+ exists: boolean;
17
+ id: string;
18
+ readTime: typeof FakeFirestore.Timestamp;
19
+ ref: typeof FakeFirestore.DocumentReference;
20
+ metadata: {
21
+ hasPendingWrites: 'Server';
22
+ };
23
+ updateTime: typeof FakeFirestore.Timestamp;
24
+ data(): T | undefined;
25
+ get(fieldPath: string): unknown;
26
+ }
27
+
28
+ export default function buildDocFromHash(hash?: DocumentHash, id?: string, selectFields?: string[]): MockedDocument;