Created
June 9, 2022 12:28
-
-
Save pfiadDi/1a8333d76095a1dd5af5c686aa023e9c to your computer and use it in GitHub Desktop.
Testing Firestore security rules example
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 protected]", | |
email_verified: true | |
} | |
}; | |
const {uid2, token2} = { | |
uid2 : "uid2", | |
token2 : { | |
email: "[email protected]", | |
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