A month of Flutter: set up Firestore rules tests
Tags: flutter, tutorial, firebase, testing
Published: 2018-12-27 03:05:02

_Originally published on [bendyworks.com](https://bendyworks.com/blog/a-month-of-flutter-set-up-firestore-rules-tests)._

One aspect of using Firestore for my data backend means I need to be certain my [security rules](https://firebase.google.com/docs/firestore/security/get-started) 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](https://bendyworks.com/blog/a-month-of-flutter-setting-up-firebase-firestore) in the `server` directory. I'm going to continue that work and configure tests to run on the [Firestore emulator](https://firebase.google.com/docs/firestore/security/test-rules-emulator) based off of the [typescript-qickstart](https://github.com/firebase/quickstart-nodejs/tree/master/firestore-emulator/typescript-quickstart) example.

In `package.json` I'll add some `devDependencies` and define several `scripts`. [Node package `scripts`](https://docs.npmjs.com/misc/scripts) can be run with `npm run <name>`.

 - `postinstall` will set up the Firestore emulator after `npm install` is run in the `scripts` directory
 - `start-emulator` will will do just that
 - `pretest` will compile the project's [TypeScript](https://www.typescriptlang.org/) files before the `test` script is run
 - `test` will run the actual tests within the `test` directory using [mocha test runner](https://mochajs.org/)
 - `posttest` will cleanup the test `*.js` and `*.js.map` files created during `pretest`
 - `ci` uses a handy [Node package `start-server-and-test`](https://www.npmjs.com/package/start-server-and-test) to 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](https://www.npmjs.com/package/mocha-typescript).

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.
>
> _[Test your security rules](https://firebase.google.com/docs/firestore/security/test-rules-emulator)_

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.

~~~js
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:

~~~ts
@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:

~~~bash
  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](https://bendyworks.com/blog/a-month-of-flutter-configuring-continuous-integration).

## Code changes

- [#62 Set up Firestore rules tests](https://github.com/abraham/birb/pull/62)