Originally published on bendyworks.com.
One aspect of using Firestore for my data backend means I need to be certain my security rules are configured correctly. Otherwise users might be able to read or write date they shouldn't have access to.
A few days ago I set up Firestore in the
server directory. I'm going to continue that work and configure tests to run on the Firestore emulator based off of the typescript-qickstart example.
In
package.json I'll add some devDependencies and define several scripts. Node package scripts can be run with npm run <name>.postinstallwill set up the Firestore emulator afternpm installis run in thescriptsdirectorystart-emulatorwill will do just thatpretestwill compile the project's TypeScript files before thetestscript is runtestwill run the actual tests within thetestdirectory using mocha test runnerposttestwill cleanup the test*.jsand*.js.mapfiles created duringpretestciuses a handy Node packagestart-server-and-testto start the emulator, wait for it to be ready, run the tests, and then shut down
I created a new
tsconfig.json file with npx tsc --init. The two main changes I made were to target es6 instead of es5 and enable experimentalDecorators for the mocha-typescript package.
Within
test/firestore.ts I'm defining a FirestoreTest class that will handle loading the rules, and setting up and tearing down test databases. mocha-typescript will use a new instance of this class for each test. Each instance will use a different projectId to avoid different test runs from interfering with each other.The Cloud Firestore emulator persists data. This might impact your results. To run tests independently, assign a different project ID for each, independent test. When you call firebase.initializeAdminApp or firebase.initializeTestApp, append a user ID, timestamp, or random integer to the projectID.
I changed
firestore.rules so there was an allowed rule and a denied rule. These will be updated with real rules before the next deploy.service cloud.firestore {
match /databases/{database}/documents {
match /{document=**} {
allow read: if true;
allow write: if false;
}
}
}
The initial tests for the
user collection in user_rules_test.ts look like this:@suite
class Users extends FirestoreTest {
@test
async 'can read'() {
const user = this.db().collection('users').doc('alice');
await firebase.assertSucceeds(user.get());
}
@test
async 'can not write'() {
const user = this.db().collection('users').doc('alice');
await firebase.assertFails(user.set({ nickname: 'alice' }));
}
}
The
@suite, @test, and class style is supported by mocha-typescript. One of the reasons I chose TypeScript instead of JavaScript is because the types are similar to Dart much of the time.
I created a success test and a failure test to as proof of concept while setting up all the tooling. They get a database handle and assert that it can be read or written to.
I can now run
npm run ci and see the following: Users
✓ can read (162ms)
✓ can not write (95ms)
2 passing (462ms)
The next step will be to get these tests running along with the existing CI.

Comments
Post a Comment