- ADMIN FROM ANYWHERE FOR ANYTHING -
The wonderful world of serverless development brings us many gifts for a relatively low price, but as with everything there are also downsides. We are using Firebase, a serverless framework by Google, and we love it. However, let's focus for now on a problem we encountered, and the tool we have created to make it work well.
One of the issues we face, with not being in full control of the database, is seeding and asserting the state of the database during development and testing. Manually preparing data every once in a while is doable for small projects, but when the projects get larger you need more tools. Since serverless is bleeding edge, the tool landscape is still being built. Let's introduce a new tool to that landscape, a must have in your project setup and during you (automated) tests: Firebridge
yarn add @endran/firebridge
The challenge
When using Firebase in large projects, you are faced with (at least) these two challenges
Initialising Firebase:
Any decent testing setup must be able to reliably control the data it is working with. This means we need to be able to reset Cloud Firestore with a consistent data set over and over again.
Frontend Admin Access:
We need to be able to insert data and assert data during End to End tests (for which we are using Cypress). We need to be able to bypass our elaborate security rules, for this we need Admin Access.
When naively adding the Firebase Admin SDK in you application, you will be faced with a world of hurt. The Firebase Admin SDK is meant to be used in a Node.JS environment, not in the browser, so it just won't ever work.
Initialising Firebase
The fastest way to get started with Firebase is to just start using it. The first couple of days you can do fine with manually creating data via the Firebase Console. You can grow you application together with the database, and everything is fine. But there will come a point where you will get afraid of touching the DB, since you cannot just roll back. This is where you must start to use Firebridge.
The creation process
Setup Firebridge, and run the FIRESTORE.EXPORT
command. This will export the current state of your Firestore, you can commit this export file to git.
Next, go ham on your package.json
(or if you are not using NPM, choose you favourite build script tooling), and do something like below. See the README of Firebridge for the content of the command files.
"scripts": {
"firebridge": "firebridge --serviceAccount firebase-admin.json",
"firestore:export": "yarn firebridge --commandPath 'commands/export.json'",
"firestore:clear": "yarn firebridge --commandPath 'commands/clear.json'",
"firestore:import": "yarn firebridge --commandPath 'commands/import.json'",
"firestore:reinit": "yarn firestore:clear && yarn firestore:import"
}
Now you are ready to experiment with your database once more. You can try new stuff in your app, and roll back whenever you want, or you can extend your data set with new functionality first, and then import it into Firestore. It also enables you to have several Firebase instances for various purposes and have a consistent database.
Users
Next to testdata you often also need accounts. These can also be created using Firebridge. This way you can have a consistent set of user across various instances of Firestore for test purposes. The account details will also be in version control, so every developer can just lookup the email and password fields of any test account. Even when new accounts are added, or existing accounts are changed, the entire team can just look it up. Again, see Firebridge for the details on the command files.
"scripts": {
"firebridge": "firebridge -serviceAccount firebase-admin.json",
"auth:clear": "yarn firebridge --commandPath 'commands/clear-users.json'",
"auth:add": "yarn firebridge --commandPath 'commands/add-users.json'",
"auth:reinit": "yarn auth:clear && yarn auth:add"
}
End to end test way of working
Having a reliable data set to start with is a must for creating proper End to End tests, but it's just a start. Often you need to create or mutate data, or you need to assert some value in the database at the end of a test run. It's not always possible to read/write Firestore with the client SDK, due to security rules. And during setup or teardown of tests we'd rather use the Admin SDK, but this doesn't run in the browser.
Recently we have fallen in love with Cypress, a new state of the art framework for UI tests that offers - and I quote - "Fast, easy and reliable testing for anything that runs in a browser.". It's a blessing compared to Protractor. However, using the Firebase Admin SDK directly is a no go. You'll get;
Oops...we found an error preparing this test file
Cypress, which always runs in a browser context, so we needed to overcome this.
Open the bridge
Open up Firebridge, choose your favourite port.
"scripts": {
"firebridge": "firebridge -serviceAccount firebase-admin.json",
"openbridge": "yarn firebridge --open 3999"
}
In your test just call Firebridge with data you want to set, or data you want to retrieve. See the README for the exact content of the POST body. Remember that whenever you set data via Firebridge, it will take a brief moment before you see it reflected in your application. That's just life for serverless development, allow for the delay in your assertions (preferable not with sleeps
).
Last thoughts
The format of the body and the format of the command files is exactly the same, so you could also do the command described earlier via HTTP as well. For example, we use AUTH.ADD
and AUTH.DELETE
to create/delete fresh account, to test our login flow.
Internally Firebridge uses node-firestore-import-export, this library has support for complex data types like Timestamp
and Geopoint
. If Firebridge would export the content in plain strings, instead this slightly more complicated format, then type information on types like Timestamp
would be lost. Get familiar with the format, it's worth it.
If you have Timestamp
or Date
in your test data, you run the risk of dates getting stale. For example it could be that birthday information might be important for your application, so you need dates to be fresh. For this, use a tool like Testdate.
Firebridge enable you to have a consistent environment between multiple Firebase instances. You can create as many instances as you have developers, create an ci, acceptance and production environment, and configure them identically, in an instant.
Cover image by Luke Price.