Generate test reports

Cloud Firestore and Realtime Database both rely on powerful, concise rules languages specifically created to govern information security and access control. However, as rules get longer and more complex, you might need some help debugging errors in their behavior.

The Firebase Emulators include the ability to generate rule coverage reports, so you can see see exactly what each subexpression evaluated to when you reproduce an error. The reports also provide information about how frequently each test case used a rule, like traditional "line coverage" techniques.

Generate a report

After running a suite of tests, you can access test coverage reports that show how each of your security rules was evaluated.

To get the reports, query an exposed endpoint on the emulator while it's running. For a browser-friendly version, use the following URL:

Cloud Firestore

http://localhost:8080/emulator/v1/projects/<database_name>:ruleCoverage.html
 

Realtime Database

http://localhost:9000/.inspect/coverage?ns=<database_name>
 

This breaks your rules into expressions and subexpressions that you can mouseover for more information, including number of evaluations and values returned. For the raw JSON version of this data, include the following URL in your query:

Cloud Firestore

http://localhost:8080/emulator/v1/projects/<database_name>:ruleCoverage
 

Realtime Database

http://localhost:9000/.inspect/coverage.json?ns=<database_name>
 

Debugging example rules

To easily generate a test report, use the emulator quickstarts available on GitHub for Cloud Firestore and Realtime Database. These quickstarts guide you through properly installing and initializing the emulators, then generating sample tests from an example set of rules.

Consider an example app using Cloud Firestore that counts how many times users click a button. The app employs the following rules:

Cloud Firestore

 service cloud.firestore {
   match /databases/{database}/documents {
     match /counters/{counter} {
       allow read;
       allow write: if request.resource.data.value == resource.data.value +1;
     }
   }
 }
 

To debug the errors in the rules shown above, use the following sample JavaScript test:

const counter0 = db.collection("counters").doc("0");
await firebase.assertSucceeds(counter0.set({value: 0}));

The emulator generates a report available at the URL noted above:

http://localhost:8080/emulator/v1/projects/<database_name>:ruleCoverage.html

The report shows the following undefined and null-value errors:

The problem with this specific example is that the rules don't differentiate between creating the document and updating the document. Consequently, the write isn't allowed if the document doesn't exist, and the document can't be created because it doesn't exist. Differentiating the "write" into two more specific operations — "create" and "update" — solves the problem.

Cloud Firestore

 service cloud.firestore {
   match /databases/{database}/documents {
     match /counters/{counter} {
       allow read;
       allow create: if request.resource.data.value == 0;
       allow update: if request.resource.data.value == resource.data.value +1;
     }
   }
 }
 

The generated report shows how frequently each rule was used and what was returned.