Jacob Bowdoin
Jacob Bowdoin

Reputation: 57

Timestamp not working with firebase-functions-test

I'm using firebase-admin 8.6.0 and firebase-functions-test 0.1.6 which has support for Firestore Timestamps in testing (as of 0.1.5 https://github.com/firebase/firebase-functions-test/releases) but am still receiving an error message when trying to use them with test.firestore.makeDocumentSnapshot.

Can someone help me understand the error in my implementation?

import * as admin from 'firebase-admin';
admin.initializeApp();
const db = admin.firestore();
const settings = { timestampsInSnapshots: true};
db.settings(settings);

const timestamp = admin.firestore.FieldValue.serverTimestamp();
const testingTimestamp1 = admin.firestore.Timestamp.now();
const testingTimestamp2 = admin.firestore.Timestamp.fromDate(new Date);

import * as TestFunctions from 'firebase-functions-test';

const firebaseConfig = {
    databaseURL: 'https://...HIDDEN...',
    projectId: '...HIDDEN...',
    storageBucket: '...HIDDEN...appspot.com',
}

const test = TestFunctions(firebaseConfig, 'service-account-dev.json');

const data({
  timestamp,
  testingTimestamp1,
  testingTimestamp2,
});

const snap = test.firestore.makeDocumentSnapshot(data, path);

const wrapped = test.wrap(processImport);
await wrapped(snap, {params: testParams});

I can't get any of the three timestamp options to work. The latter one I tried learning from @the0rem in https://github.com/firebase/firebase-functions-test/pull/28 but to no avail. I always receive this error:

Cannot encode [object Object]to a Firestore Value. Local testing does not yet support Firestore geo points.`

Upvotes: 0

Views: 1374

Answers (1)

Kay Qube
Kay Qube

Reputation: 96

I was excited when I saw your question because I just faced the same issue. Anyway, here is how I finally solved it. This is the JSON data that I saved from my Firestore database:

const customer = { 
    username: "A8tAz6wdtucMNKvWSgDkx4bquc2", 
    timestamp: { 
        _seconds: 1578762627, 
        _nanoseconds: 828000000 
    }, 
    role: "user" 
};

Note that timestamp is just a plain object with two properties: _seconds and _nanoseconds. This is where the error "Cannot encode [object Object]to a Firestore Value." comes from i.e. the data object, customer, contains another object, timestamp, which Firestore is unable to parse. What we do to solve this is to make sure that timestamp is not a plain object but an instance of admin.firestore.Timestamp. And here is how you do that:

const seconds = customer.timestamp._seconds;
const nanosecs = customer.timestamp._nanoseconds;

// create a new Timestamp object passing in the required constructor arguments
const properTimestamp = new admin.firestore.Timestamp(seconds, nanosecs);
customer.timestamp = properTimestamp; // update the timestamp reference in your data object
// Now you can do this
test.firestore.makeDocumentSnapshot(customer, '/users/A8tAz6wdtucMNKvWSgDkx4bquc2')

Now if you do console.log(customer); you will see that the timestamp object is an instance of admin.firestore.Timestamp, here is the console output:

// OUTPUT
{
    username: 'A8tAz6wdtucMNKvWSgDkx4bquc2',
    timestamp: Timestamp { _seconds: 1578762627, _nanoseconds: 828000000 },
    role: 'user'
}

PS: I got the answer by checking how Firebase was trying to parse the values/objects in the data. Here is where the parsing was failing and the exception was being thrown (in the file: ../node_modules/firebase-functions-test/lib/providers/firestore.js:165:15):

if (val instanceof firebase_admin_1.firestore.Timestamp) {
        return {
            timestampValue: val.toDate().toISOString(),
        };
    }

Upvotes: 3

Related Questions