So I'm have a very specific error come up in the firestore emulator.
Error: Value for argument "data" is not a valid Firestore document. Detected an object of type "Timestamp" that doesn't match the expected instance (found in field "reserveBeginDateTime"). Please ensure that the Firestore types you are using are from the same NPM package.)
at validateUserInput (node_modules/@google-cloud/firestore/build/src/serializer.js:326:15)
at Object.validateUserInput (node_modules/@google-cloud/firestore/build/src/serializer.js:263:13)
at validateDocumentData (node_modules/@google-cloud/firestore/build/src/write-batch.js:577:18)
at WriteBatch.set (node_modules/@google-cloud/firestore/build/src/write-batch.js:243:9)
at DocumentReference.set (node_modules/@google-cloud/firestore/build/src/reference.js:342:14)
at Context.<anonymous> (rules.test.js:405:83)
at processImmediate (internal/timers.js:439:21)
My firestore rules for this doc are (as you can see i've been commenting out rules to try to nail down the problem, but no luck). Also, I can't seem to make the 'debug' function that firestore rules advertises work:
rules_version = '2';
service cloud.firestore {
match /databases/{database}/documents {
function documentFieldsCheckOut(requiredFields, optionalFields) {
let allFields = requiredFields.concat(optionalFields);
return request.resource.data.keys().hasAll(requiredFields) &&
request.resource.data.keys().hasOnly(allFields);
}
function documentFieldValuesCheckOut(value, allowedValues) {
return value in allowedValues;
}
match /{document=**} {
allow read, write: if false;
}
match /rentalTransactions/{transactionId} {
//
// function docEvaluateFieldsDataType() {
// return request.resource.data.borrowerId is string &&
// request.resource.data.ownerId is string &&
// request.resource.data.itemId is string &&
// request.resource.data.reserveBeginDateTime is timestamp &&
// request.resource.data.reserveEndDateTime is timestamp &&
// request.resource.data.cancellationDateTime is timestamp &&
// request.resource.data.checkoutDateTime is timestamp &&
// request.resource.data.returnedDateTime is timestamp &&
// documentFieldValuesCheckOut(resource.data.transportType, ["delivery", "meetup", "pickup"]);
// }
allow read: if ((resource.data.borrowerId == request.auth.uid) || (resource.data.ownerId == request.auth.uid));
allow create: if (request.resource.data.borrowerId == request.auth.uid); // &&
// documentFieldsCheckOut(["borrowerId", "ownerId", "itemId", "transportType", "reserveBeginDateTime", "reserveEndDateTime"],
// ["cancellationDateTime", "checkoutDateTime", "returnedDateTime"]); // &&
// docEvaluateFieldsDataType();
allow update: if (resource.data.borrowerId == request.auth.uid || resource.data.ownerId == request.auth.uid); // &&
// documentFieldsCheckOut([null], ["cancellationDateTime", "checkoutDateTime", "returnedDateTime"]); //&&
// docEvaluateFieldsDataType();
}
}
}
I've included the Mocha tests in the snippet. The first test- "Can't create with a different uid than the borrowerId works fine, but as soon as I attempt to create a document that includes a timestamp with the "AdminApp", it throws the error.
const firebase = require('@firebase/rules-unit-testing');
const MY_PROJECT_ID = '...';
const myId = "user_abc";
const myAuth = {uid: myId, email: "abc@gmail.com"}
const theirId = "user_xyz";
const admin = getAdminFirestore();
const db = getFirestore(myAuth);
function getFirestore(auth) {
return firebase.initializeTestApp({projectId: MY_PROJECT_ID, auth: auth}).firestore();
}
function getAdminFirestore() {
return firebase.initializeAdminApp({projectId: MY_PROJECT_ID}).firestore();
}
describe ('Mooch App user renting an item', () => {
// const REQUIRED_FIELDS = ["borrowerId", "ownerId", "itemId", "transportType",
// "reserveBeginDateTime", "reserveEndDateTime"];
// const OPTIONAL_FIELDS = ["cancellationDateTime", "checkoutDateTime", "returnedDateTime"];
// SYSTEM_UPDATED_FIELDS = ["transportCost", "rentalCost", "totalCost", "rentalStatus"];
const itemId = "item_123";
const transId = "transaction_123";
const sampBegDaTime = firebase.firestore.Timestamp.fromDate(new Date(2021, 3, 10));
const sampEndDaTime = firebase.firestore.Timestamp.fromDate(new Date(2021, 3, 15));
it("Can't create a rentalTransaction with a different borrowerID as our user", async() => {
const transaction = {
itemId: itemId,
ownerId: myId,
borrowerId: theirId,
transportType: "delivery",
reserveBeginDateTime: sampBegDaTime,
reserveEndDateTime: sampEndDaTime,
};
const setDoc = db.collection("rentalTransactions").doc(transId);
await firebase.assertFails(setDoc.set(transaction));
});
it("Can update a rentalTransaction with the same ownerID as our user", async() => {
const transaction = {
itemId: itemId,
ownerId: myId,
borrowerId: theirId,
transportType: "delivery",
reserveBeginDateTime: sampBegDaTime,
reserveEndDateTime: sampEndDaTime,
};
await admin.collection("rentalTransactions").doc(transId).set(transaction);
const updateDoc = await db.doc(`rentalTransactions/${transId}`);
await firebase.assertSucceeds(updateDoc.set({returnedDateTime: sampEndDaTime}));
});
});
I'm using firestore emulator in Webstorm.