firebase / firebase-js-sdk

Firebase Javascript SDK
https://firebase.google.com/docs/web/setup
Other
4.83k stars 890 forks source link

Error: FIRESTORE (9.10.0) INTERNAL ASSERTION FAILED: Unexpected state when trying to run unit test for Firestore Rules with Firebase Emulators #6684

Open raaaahman opened 1 year ago

raaaahman commented 1 year ago

Describe your environment

Describe the problem

I am trying to test my cloud Firestore Security rules using the Firebase Emulators. Emulators work fine for manual tests, but when I try to run automated tests with Jest (React Scripts to be specific), I have the following error:

node:internal/process/promises:279 triggerUncaughtException(err, true / fromPromise /); ^

Error: FIRESTORE (9.10.0) INTERNAL ASSERTION FAILED: Unexpected state

Stack trace points here: https://github.com/firebase/firebase-js-sdk/blob/afe6e22845f7b91f19bd9a6b8179764e95e27254/packages/firestore/src/util/async_queue_impl.ts#L186

Steps to reproduce:

  1. create a new project with npx create-react-app my-project
  2. create a Firebase project, and enable Firestore
  3. Install Firebase Emulators with ǹpm install -g firebase-tools`
  4. write some test using Jest, example in file named myTest.test.js
  5. run Firebase Emulators with firebase emulators:start
  6. run tests with npm test

Relevant Code:

Test code:
describe('The Cloud Firestore Security Rules', () => {
    let testEnv, unauthDb

    beforeAll(async () => {
        testEnv = await initializeTestEnvironment({
            projectId: 'mtg-deck-planner-11665',
            firestore: {
                rules: readFileSync(resolve(__dirname, '../../firestore.rules'), 'utf-8'),
                host: 'localhost',
                port: '9000'
            }
        })
        unauthDb = testEnv.unauthenticatedContext().firestore()
    })

    afterAll(() => {
        testEnv.cleanup()
    })

    afterEach(async () => {
       await testEnv.clearFirestore()
    })

    it('should not allow any unauthenticated user to write to the database', async () => {        
        const docRef = doc(unauthDb, '/any', 'docId')

        await assertFails(setDoc(docRef, { data: 'test' }))
    })

    it('should not allow any unauthenticated user to view users\' data', async () => {
        const collectionPath = 'users'
        const docPath = 'userId'
        await testEnv.withSecurityRulesDisabled(
            (amdinCtx) => setDoc(doc(amdinCtx.firestore(), collectionPath, docPath), { uid: 'user_123' })
        )
        const docRef = doc(unauthDb, collectionPath, docPath)

        await assertFails(getDoc(docRef))
    })
})

First test pass and fail for the correct reason. Second test exit the Node process with the aforementioned error message.

Firestore rules
rules_version = '2';
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if false;
    }
    match /users/{userId} {
      allow read, write: if false;
    }
  }
}
package.json dependencies
  "dependencies": {
    "@reduxjs/toolkit": "^1.8.5",
    "@testing-library/jest-dom": "^5.16.5",
    "@testing-library/react": "^13.4.0",
    "@testing-library/user-event": "^14.4.3",
    "firebase": "^9.10.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0",
    "react-redux": "^8.0.2",
    "react-scripts": "^5.0.1",
    "web-vitals": "^2.1.4"
  },
  "devDependencies": {
    "@firebase/rules-unit-testing": "^2.0.4"
  }
MarkDuckworth commented 1 year ago

Possibly a duplicate of: https://github.com/firebase/firebase-js-sdk/issues/6658. We will be looking into this.

raaaahman commented 1 year ago

I am having additional warning message with @firebase/firestore version 9.15.0:

@firebase/firestore: Firestore (9.15.0): Connection GRPC stream error. Code: 13 Message: 13 INTERNAL: Response message parsing error: index out of range: 34 + 1 > 34

I'm not sure if this is related though.

raaaahman commented 1 year ago

I realize that in my original steps I did:

  1. run Firebase Emulators with firebase emulators:start
  2. run tests with npm test

This was two commands in separate terminals. But I since had a better outcome running firebase emulators:exec "node ./path/to/my/test-script.js": it worked with every Testing SDK feature (9.15.0).

Are the aforementioned steps 5 and 6 supposed to work just as well as the emulators:exec command?

natedx commented 1 year ago

Hello, Solved this error by setting testEnvironment to node as suggested in the answer on SO : https://stackoverflow.com/a/63465382 You can do this either by creating a jest.config.js file or by passing the --env=node flag to the jest command.

As I understand it, jsdom implements a browser environment and is useful for UI tests. While testing firebase security rules, we want a node 'server' environment.

This may seem obvious to many, but perhaps it could be included in the firebase documentation ?

Zeusmist commented 1 year ago

I get this error when I setup firestore listeners on multiple docs. It happens both when I'm using firestore emulator and also in production. Mine is Error: FIRESTORE (9.18.0) INTERNAL ASSERTION FAILED: Unexpected state 9.18.0