The Firebase Local Emulator Suite make it easier to fully validate your app's features and behavior . It's also a great tool for verifying 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
or 'storage.rules' field of yourfirebase.json
file. If the file does not exist and you don't use theloadFirestoreRules
or 'loadStorageRules' 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 database emulators 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).
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>
Run local unit tests with the version 9 JavaScript SDK
Firebase distributes a Security Rules unit testing library with both its version 9 JavaScript SDK and its version 8 SDK. The library APIs are significantly different. We recommend the v9 testing library, which is more streamlined and requires less setup to connect to emulators and thus safely avoid accidental use of production resources. For backwards compatibility, we continue to make the v8 testing library available .
- Common test methods and utility functions in the v9 SDK
- Emulator-specific test methods in the v9 SDK
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.
The v9 Rules Unit Testing library is always aware of the emulators and never touches your production resources.
You import the library using v9 modular import statements. For example:
import {
assertFails,
assertSucceeds,
initializeTestEnvironment
} from "@firebase/rules-unit-testing"
// Use `const { … } = require("@firebase/rules-unit-testing")` if imports are not supported
// Or we suggest `const testing = require("@firebase/rules-unit-testing")` if necessary.
Once imported, implementing unit tests involves:
- Creating and configuring a
RulesTestEnvironment
with a call toinitializeTestEnvironment
. - Setting up test data without triggering Rules, using a convenience
method that allows you to temporarily bypass them,
RulesTestEnvironment.withSecurityRulesDisabled
. - Setting up test suite and per-test before/after hooks with calls to
clean up test data and environment, like
RulesTestEnvironment.cleanup()
orRulesTestEnvironment.clearFirestore()
. - Implementing test cases that mimic authentication states using
RulesTestEnvironment.authenticatedContext
andRulesTestEnvironment.unauthenticatedContext
.
Common methods and utility functions
Also see emulator-specific test methods using the modular API .
initializeTestEnvironment() => RulesTestEnvironment
This function initializes a test environment for rules unit testing. Call this function first for test setup. Successful execution requires emulators to be running.
The function accepts an optional object defining a TestEnvironmentConfig
,
which can consist of a project ID and emulator configuration settings.
let testEnv = await initializeTestEnvironment({ projectId: "demo-project-1234", firestore: { rules: fs.readFileSync("firestore.rules", "utf8"), }, });
RulesTestEnvironment.authenticatedContext({ user_id: string, tokenOptions?: TokenOptions }) => RulesTestContext
This method creates a RulesTestContext
, which behaves like an authenticated
Authentication user. Requests created via the returned context will have a mock
Authentication token attached. Optionally, pass an object defining custom claims or
overrides for Authentication token payloads.
Use the returned test context object in your tests to access any emulator
instances configured, including those configured with initializeTestEnvironment
.
// Assuming a Firestore app and the Firestore emulator for this example import { setDoc } from "firebase/firestore"; const alice = testEnv.authenticatedContext("alice", { … }); // Use the Firestore instance associated with this context await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });
RulesTestEnvironment.unauthenticatedContext() => RulesTestContext
This method creates a RulesTestContext
, which behaves like a client that is
not logged in via Authentication. Requests created via the returned context will not
have Firebase Auth tokens attached.
Use the returned test context object in your tests to access any emulator
instances configured, including those configured with initializeTestEnvironment
.
// Assuming a Cloud Storage app and the Storage emulator for this example import { getStorage, ref, deleteObject } from "firebase/storage"; const alice = testEnv.unauthenticatedContext(); // Use the Cloud Storage instance associated with this context const desertRef = ref(alice.storage(), 'images/desert.jpg'); await assertSucceeds(deleteObject(desertRef));
RulesTestEnvironment.withSecurityRulesDisabled()
Run a test setup function with a context that behaves as if Security Rules were disabled.
This method takes a callback function, which takes the Security-Rules-bypassing context and returns a promise. The context will be destroyed once the promise resolves / rejects.
RulesTestEnvironment.cleanup()
This method destroys all RulesTestContexts
created in the test environment and
cleans up the underlying resources, allowing a clean exit.
This method does not change the state of emulators in any way. To reset data between tests, use the application emulator-specific clear data method.
assertSucceeds(pr: Promise<any>)) => Promise<any>
This is a test case utility function.
The function asserts that the supplied Promise wrapping an emulator operation will be resolved with no Security Rules violations.
await assertSucceeds(setDoc(alice.firestore(), '/users/alice'), { ... });
assertFails(pr: Promise<any>)) => Promise<any>
This is a test case utility function.
The function asserts that the supplied Promise wrapping an emulator operation will be rejected with a Security Rules violation.
await assertFails(setDoc(alice.firestore(), '/users/bob'), { ... });
Emulator-specific methods
Also see common test methods and utility functions using the modular API .
Cloud Firestore
Cloud Firestore
RulesTestEnvironment.clearFirestore() => Promise<void>
This method clears data in the Firestore database that belongs to the projectId
configured for the Firestore emulator.
RulesTestContext.firestore(settings?: Firestore.FirestoreSettings) => Firestore;
This method gets a Firestore instance for this test context. The returned Firebase JS Client SDK instance can be used with the client SDK APIs (v9 modular or v9 compat).