Skip to content

Instantly share code, notes, and snippets.

@pfiadDi
Created June 9, 2022 12:28
Show Gist options
  • Save pfiadDi/1a8333d76095a1dd5af5c686aa023e9c to your computer and use it in GitHub Desktop.
Save pfiadDi/1a8333d76095a1dd5af5c686aa023e9c to your computer and use it in GitHub Desktop.
Testing Firestore security rules example
import fs from 'fs';
import * as path from 'path';
import {before,it} from "mocha"
const TEST_FIREBASE_PROJECT_ID = "test-firestore-rules-project";
import { Data, DataRealEstateTypeEnum} from '../entities/ts/models/Data'
import { OfferStatus } from '../entities/ts/models/OfferStatus'
import {
assertFails,
assertSucceeds,
initializeTestEnvironment,
RulesTestEnvironment
} from "@firebase/rules-unit-testing"
import { doc, getDoc, setDoc, setLogLevel, deleteDoc } from 'firebase/firestore';
const {allowed, allowedToken} = {
allowed : "allowed",
allowedToken : {
email: "email@d.com",
email_verified: true
}
};
const {uid2, token2} = {
uid2 : "uid2",
token2 : {
email: "email2@d.com",
email_verified: false
}
};
let testEnv : RulesTestEnvironment;
const collection1 = "Offers";
const collection2 = "Templates";
const randDocname = () : string => {
return `doc${Math.floor(Math.random() * 100)}`;
}
const fullPathColl1 = () : string => {
return `${collection1}/${randDocname()}`;
}
const fullPathColl2 = () : string => {
return `${collection2}/${randDocname()}`;
}
const createTemplateDoc = (uid : string) => {
return {
uid : uid,
logo: "logostring"
}
}
const createData = (uid : string) : Data => {
return {
uid : uid,
status : OfferStatus.Created,
name : "Mein erstes Angebot",
address : "Hauptstrasse 1",
register : "Wien Mitte",
realEstateType : DataRealEstateTypeEnum.Apartment,
ez: "2002/2",
kg: "200 Korneuburg",
gstnr : "123456789",
houseType : "Einfamilienhaus",
isApartment : true,
apartmentTopnumber : "1",
isOtherRoom : false,
otherRoomTopnumber : "1",
otherRoomName : "Abstellraum",
isGarageSpace : true,
garageTopnumber : "1232",
constitution : "A short description",
seller: "Thomas Maier"
}
}
const pathTestDoc = fullPathColl1();
const testData : Data = createData(allowed)
const pathDocTemplate = fullPathColl2();
const testDataTemplate = createTemplateDoc(allowed)
const pathTestDoc2 = fullPathColl1();
const testData2 = createData(uid2)
before(async () => {
// Silence expected rules rejections from Firestore SDK. Unexpected rejections
// will still bubble up and will be thrown as an error (failing the tests).
setLogLevel('error');
testEnv = await initializeTestEnvironment({
firestore: {
rules: fs.readFileSync(path.resolve(__dirname, "../firestore.rules"), "utf8")
},
});
await testEnv.withSecurityRulesDisabled(async (context) => {
await setDoc(doc(context.firestore(), pathTestDoc2), testData2);
});
await testEnv.withSecurityRulesDisabled(async (context) => {
await setDoc(doc(context.firestore(), pathDocTemplate), testDataTemplate);
});
});
after(async () => {
// Delete all the FirebaseApp instances created during testing.
// Note: this does not affect or clear any data.
await testEnv.cleanup();
});
//Unit test the security rules
describe("Planned and correct access", () => {
describe("Authenticated user with verified email can create docs in offer with their uid and read those", () => {
it('can write a new doc in offers', async () => {
await assertSucceeds(setDoc(doc(testEnv.authenticatedContext(allowed,allowedToken).firestore(),pathTestDoc),testData));
});
it('can read', async () => {
await assertSucceeds(getDoc(doc(testEnv.authenticatedContext(allowed,allowedToken).firestore(), pathTestDoc)));
});
it('can read own docs in templates', async () => {
await assertSucceeds(getDoc(doc(testEnv.authenticatedContext(allowed,allowedToken).firestore(), pathDocTemplate)));
});
it('can not write to Templates', async () => {
await assertFails(setDoc(doc(testEnv.authenticatedContext(allowed,allowedToken).firestore(), `Templates/randDoc`),{add: "data"}));
});
it('can not add addtional data', async () => {
await assertFails(setDoc(doc(testEnv.authenticatedContext(allowed,allowedToken).firestore(), pathTestDoc),{add: "data"},{merge:true}));
});
it('can not write random docs', async () => {
await assertFails(setDoc(doc(testEnv.authenticatedContext(allowed,allowedToken).firestore(), `whatever/randDoc`),{add: "data"}));
});
it('can not delete docs', async () => {
await assertFails(deleteDoc(doc(testEnv.authenticatedContext(allowed,allowedToken).firestore(), pathTestDoc)));
});
});
});
describe("Forbidden access", () => {
describe("Authenticated user without verified email can't do aynthing", () => {
it('can not read', async () => {
await assertFails(getDoc(doc(testEnv.authenticatedContext(uid2,token2).firestore(), pathTestDoc2)));
});
it('can not write a new doc in offers', async () => {
await assertFails(setDoc(doc(testEnv.authenticatedContext(uid2,token2).firestore(), `${pathTestDoc}asdf`),testData2));
});
it('can not write random docs', async () => {
await assertFails(setDoc(doc(testEnv.authenticatedContext(uid2,token2).firestore(), `whatever/randDoc`),{add: "data"}));
});
});
describe("Access without any authentication", () => {
/* We don't delete this data to test the delete operation afterwards on this document */
it('can not read', async () => {
await assertFails(getDoc(doc(testEnv.unauthenticatedContext().firestore(), pathTestDoc)));
});
it('can not write', async () => {
await assertFails(setDoc(doc(testEnv.unauthenticatedContext().firestore(), 'aNew/doc'),{new: "data"}));
});
});
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment