The Firebase Emulators make it easier to fully validate your app's behavior and verify your Firebase Security Rules configurations. Use the Firebase Emulators to run and automate unit tests in a local environment. The methods outlined in this document should help you as you build and automate unit tests for your app that validate your Rules.
If you haven't already, set up the Firebase Emulators.
Before you run the emulator
Before you start using the emulator, keep in mind the following:
- The emulator will initially load the rules specified in the
firestore.rules
field of yourfirebase.json
file. If the file does not exist and you don't use theloadFirestoreRules
method as described below, the emulator treats all projects as having open rules. - While
most Firebase SDKs
work with the emulators directly, only the
@firebase/rules-unit-testing
library supports mockingauth
in Security Rules, making unit tests much easier. In addition, the library supports a few emulator-specific features like clearing all data, as listed below. - The emulators will also accept production Firebase Auth tokens provided through Client SDKs and evaluate rules accordingly, which allows connecting your application directly to the emulators in integration and manual tests.
Differences between the emulator and production
- You do not have to explicitly create a database instance. The emulator will automatically create any database instance that is accessed.
- Each new database is started with closed rules, so non-admin users will not be able to read or write.
- Each emulated database applies the Spark plan limits and quotas (most notably, this limits each instance to 100 concurrent connections).
- Any database will accept the string
"owner"
as an admin auth token. - The emulators do not currently have working interactions with other Firebase
products. Notably, the normal Firebase Authentication flow does not work.
Instead, you can use the
initializeTestApp()
method in therules-unit-testing
library, which takes anauth
field. The Firebase object created using this method behaves as if it has successfully authenticated as whatever entity you provide. If you pass innull
, it will behave as an unauthenticated user (auth != null
rules will fail, for example).
Run local tests
Use the @firebase/rules-unit-testing
module to interact with the emulator
that runs locally. If you get timeouts or ECONNREFUSED
errors, double-check
that the emulator is actually running.
We strongly recommend using a recent version of Node.js so you can use
async/await
notation. Almost all of the behavior you might want to test
involves asynchronous functions, and the testing module is designed to work with
Promise-based code.
Interacting with the Realtime Database emulator
A production Firebase Realtime Database instance is accessible at a subdomain of
firebaseio.com
, and you can access the REST api like this:
https://<database_name>.firebaseio.com/path/to/my/data.json
The emulator runs locally, and is available at localhost:9000
. To interact
with a specific database instance, you will have to use the ns
query parameter
to specify the database name.
http://localhost:9000/path/to/my/data.json?ns=<database_name>
Test SDK methods
Select a product to see the methods used by the Firebase Test SDK to interface with the emulator.
Cloud Firestore
Cloud Firestore
initializeTestApp({ projectId: string, auth: Object }) => FirebaseApp
This method returns an initialized Firebase app corresponding to the project ID and auth variable specified in the options. Use this to create an app authenticated as a specific user to use in tests.
firebase.initializeTestApp({ projectId: "my-test-project", auth: { uid: "alice", email: "alice@example.com" } });
initializeAdminApp({ projectId: string }) => FirebaseApp
This method returns an initialized admin Firebase app. This app bypasses security rules when performing reads and writes. Use this to create an app authenticated as an admin to set state for tests.
firebase.initializeAdminApp({ projectId: "my-test-project" });
apps() => [FirebaseApp]
This method returns all the currently initialized test and admin apps.
Use this to clean up apps between or after tests.
Promise.all(firebase.apps().map(app => app.delete()))
loadFirestoreRules({ projectId: string, rules: Object }) => Promise
This method sends rules to a locally running database. It takes an object that specifies the rules as a string. Use this method to set your database's rules.
firebase.loadFirestoreRules({ projectId: "my-test-project", rules: fs.readFileSync("/path/to/firestore.rules", "utf8") });
assertFails(pr: Promise) => Promise
This method returns a promise that is rejected if the input succeeds or that succeeds if the input is rejected. Use this to assert if a database read or write fails.
firebase.assertFails(app.firestore().collection("private").doc("super-secret-document").get());
assertSucceeds(pr: Promise) => Promise
This method returns a promise that succeeds if the input succeeds and is rejected if the input is rejected. Use this to assert if a database read or write succeeds.
firebase.assertSucceeds(app.firestore().collection("public").doc("test-document").get());
clearFirestoreData({ projectId: string }) => Promise
This method clears all data associated with a particular project in the locally running Firestore instance. Use this method to clean-up after tests.
firebase.clearFirestoreData({ projectId: "my-test-project" });
Realtime Database
Realtime Database
initializeTestApp({ databaseName: string, auth: Object }) => FirebaseApp
Use this to create an app authenticated as a specific user to use in tests.
Returns an initialized firebase app corresponding to the database name and auth variable override specified in options.
firebase.initializeTestApp({
databaseName: "my-database",
auth: { uid: "alice" }
});
initializeAdminApp({ databaseName: string }) => FirebaseApp
Use this to create an app authenticated as an admin to set up state for tests.
Returns an initialized admin firebase app corresponding to the database name specified in options. This app bypasses security rules when reading and writing to the database.
firebase.initializeAdminApp({ databaseName: "my-database" });
loadDatabaseRules({ databaseName: string, rules: Object }) => Promise
Use this to set your database's rules.
Sends rules to a locally running database. Takes an options object that specifies your "databaseName" and your "rules" as strings.
firebase
.loadDatabaseRules({
databaseName: "my-database",
rules: "{'rules': {'.read': false, '.write': false}}"
});
apps() => [FirebaseApp]
Returns all the currently initialized test and admin apps.
Use this to clean up apps between or after tests (note that initialized apps with active listeners prevent JavaScript from exiting):
Promise.all(firebase.apps().map(app => app.delete()))
assertFails(pr: Promise) => Promise
Returns a promise that is rejected if the input succeeds and succeeds if the input is rejected.
Use this to assert that a database read or write fails:
firebase.assertFails(app.database().ref("secret").once("value"));
assertSucceeds(pr: Promise) => Promise
Returns a promise that succeeds if the input succeeds and is rejected if the input is rejected.
Use this to assert that a database read or write succeeds:
firebase.assertSucceeds(app.database().ref("public").once("value"));