Search code examples
javascriptfirebasetestinggoogle-cloud-firestorefirebase-security

Firestore, rules-unit-testing with/without @firebase/firestore


So I am genuinly confused by the rule testing docs at this point.

They are assuming an emulator, does that mean it's possible without one?

Why are they importing @firebase/firestore if the tests don't rlly need it since the refs gained by using the RulesContext have the admin-sdk dot-notation style.

Here 2 examples

// Setup
const authedSetsRef =  testEnv.authenticatedContext(id).firestore().collection(name)

// With only rules-unit-testing package
assertFails(authedSetsRef.get())

// Their docs
assertFails(getDocs(authedSetsRef)) // <= Why this way with the extra import

More complicated confusing example why I even came to this issue, the OR queries. I do not find an option to do these with the rules-unit-testing package.

  • With @firebase/firestore
  • With @admin-sdk

Link to those 2 examples, the 1st is under web modular api the 2nd under dropdown>node.js (where the admin sdk always is)

But neither option is usable in the rules-unit-testing package........?????? atleast there is no Filer.or to import


Solution

  • Why are they importing @firebase/firestore if the tests don't [really] need it since the refs gained by using the RulesContext have the admin-sdk dot-notation style.

    The @firebase/rules-unit-testing package is currently built around the firebase/compat/* compatibility libraries that emulate the legacy namespaced SDK's syntax (what you refer to as admin-sdk dot-notation). This was likely done so that updating tests could be done progressively as users upgraded their projects to the modular syntax.

    Because the library imports these legacy versions of the code, you can use either syntax if you are continuing an old project, but for new projects you should follow the modular SDK testing methods documentation.

    ... the OR queries. I do not find an option to do these with the rules-unit-testing package.

    You will need to import or() from the "firebase/firestore" library. It is a new feature that is unsupported by the legacy namespaced syntax.

    The below examples use this import block:

    import {
      assertFails,
      assertSucceeds,
      initializeTestEnvironment
    } from "@firebase/rules-unit-testing"
    
    import {
      collection,
      doc,
      getDoc,
      getDocs,
      or,
      query,
      where
    } from "firebase/firestore";
    

    Setting up the test environment:

    let testEnv = await initializeTestEnvironment({
      projectId: "demo-project-1234",
      firestore: {
        rules: fs.readFileSync("firestore.rules", "utf8"),
      },
    });
    
    const USERID_UNDER_TEST = "user-abc";
    const userAuthedTestEnv = testEnv.authenticatedContext(USERID_UNDER_TEST);
    const db = userAuthedTestEnv.firestore();
    

    Actioning a test for data of all users:

    const usersColRef = collection(db, "users");
    
    // returns a promise, chain appropriately
    assertFails(getDocs(usersColRef));
    

    Actioning a test for the user's own data:

    const usersColRef = collection(db, "users");
    const userDocRef = doc(usersColRef, USERID_UNDER_TEST);
    
    // returns a promise, chain appropriately
    assertSucceeds(getDoc(userDocRef));
    

    Actioning a test for finding important messages that user is the recipient of, where each message is unread or mentions the user by their username:

    const messagesColRef = collection(db, "messages");
    const importantMessagesQuery = query(
      messagesColRef,
      where("recipient", "==", USERID_UNDER_TEST),
      or(
        where("read", "==", false),
        where("mentionedRecipient", "==", true)
      )
    )
    
    // returns a promise, chain appropriately
    assertSucceeds(getDocs(importantMessagesQuery));