dappsnation/akita-ng-fire

Firestore Internal Assertion Failed When Testing CollectionService (Jest)

Closed this issue · 4 comments

I'm trying to test CollectionService, similar to the tests found here: https://github.com/dappsnation/akita-ng-fire/blob/v7/projects/akita-ng-fire/src/lib/collection/collection.service.spec.ts

When invoking the following functions in a Jest unit test

  • authService.signin(user, pass)
  • service.syncCollection()

I get the following exception:

    Unhandled Promise rejection: FIRESTORE (9.8.1) INTERNAL ASSERTION FAILED: Unexpected state ; Zone: <root> ; Task: Promise.then
 ; Value: Error: FIRESTORE (9.8.1) INTERNAL ASSERTION FAILED: Unexpected state
        at fail (/home/erik/dev/monobased/node_modules/@firebase/firestore/src/util/assert.ts:40:9)
        at hardAssert (/home/erik/dev/monobased/node_modules/@firebase/firestore/src/util/assert.ts:54:5)
        at fromBytes (/home/erik/dev/monobased/node_modules/@firebase/firestore/src/remote/serializer.ts:252:5)
        at fromWatchChange (/home/erik/dev/monobased/node_modules/@firebase/firestore/src/remote/serializer.ts:475:25)
        at PersistentListenStream.onMessage (/home/erik/dev/monobased/node_modules/@firebase/firestore/src/remote/persistent_strea
m.ts:642:25)

An Example -- TagService can be any CollectionService in this context. (For context, I'm running the Firebase Emulator)

import { getApp, initializeApp, provideFirebaseApp } from "@angular/fire/app";
import { connectFirestoreEmulator, getFirestore, provideFirestore } from "@angular/fire/firestore";
import {createServiceFactory, SpectatorService} from '@ngneat/spectator';
import { TagService } from "./tag.service";
import { TagQuery } from "./tag.query";
import { TagStore } from "./tag.store";

describe('Tags Test', () => {

  const createService = createServiceFactory({
    service: TagService,
    imports: [
      provideFirebaseApp(() => initializeApp({
        apiKey: 'AIzaSyD8fRfGLDsh8u8pXoKwzxiDHMqg-b1IpN0',
        authDomain: 'akita-ng-fire-f93f0.firebaseapp.com',
        databaseURL: 'https://akita-ng-fire-f93f0.firebaseio.com',
        projectId: 'akita-ng-fire-f93f0',
        storageBucket: 'akita-ng-fire-f93f0.appspot.com',
        messagingSenderId: '561612331472',
        appId: '1:561612331472:web:307acb3b5d26ec0cb8c1d5'
      }, 'collection service app')),
      provideFirestore(() => {
        const firestore = getFirestore(getApp('collection service app'));

        if (!firestore['_initialized'])
        {
          connectFirestoreEmulator(firestore, 'localhost', 8080);
          // enableIndexedDbPersistence(firestore);
        }

        return firestore;
      })
    ],
    providers: [
      TagStore,
      TagQuery
    ]
  });

  let spectator: SpectatorService<TagService>;
  let service: TagService;
  beforeEach(async () => {
    spectator = createService();
    service = spectator.service;
  });

  it('should create', () => {
    expect(spectator.service).toBeTruthy();
  });

  it('SyncCollection', async (done) => {
    service.syncCollection().subscribe(v => {
      expect(true).toBeTruthy();
      done();
    });
  });
});

After doing some research. It seems that the solution may be to run jest in a node environment. But this causes a cascading set of problems since we're using the Angular TestBed to provide all of the dependencies. -- I also don't see this project's tests doing that explicitly, but maybe that's because it's using karma/jasmine?


Dependencies:

    "@angular/fire": "^7.3.0",
    "@datorama/akita": "^7.1.1",
    "akita-ng-fire": "^7.0.0",
    "firebase": "^9.8.1",
    "@angular/core": "13.3.5",

Most likely this is an issue with jest described in the following bug report:
firebase/firebase-js-sdk#3653
Possible workaround here: jestjs/jest#7780 (comment)

EDIT: workaround when using jsdom instead of node environment: firebase/firebase-js-sdk#3096 (comment)

Basically the issue here is with jest where the following assertion fails:

const foo = Buffer.alloc(0);
const isInstance = foo instanceof Uint8Array;
expect(isInstance).toBe(true);

And it effects this firestore code. This has nothing to do with akita-ng-fire.

@hakimio -- Thank you for the input

Also sorry, I was trying to test CollectionService, but was initially guessing this was not specific to akita-ng-fire, as you mentioned. So I should have posted my question somewhere more applicable.

I tried the workaround you mentioned, which led me to upgrade to jest 28, since the above wasn't working for me.

This issue can be closed, I'm getting the following when trying to test CollectionService with Jest 28. Which to your point has nothing to do with akita-ng-fire itself.

    Jest encountered an unexpected token
   ...
    /home/erik/dev/monobased/node_modules/@firebase/firestore/dist/index.esm2017.js:12860
                    function (t, e) {
                    ^^^^^^^^

    SyntaxError: Function statements require a function name

      at Runtime.createScriptFromCode (../../node_modules/@jest/core/node_modules/jest-runtime/build/index.js:1773:14)
      at Object.<anonymous> (../../node_modules/firebase/firestore/dist/index.esm.js:1:1)

I mistakenly mentioned that node could not be used as the jest environment due to Angular TestBed. This is not true. My test had nested dependencies on classes that used document/router which caused those problems.

I was able to use node as my jest environment once I removed those dependencies and then was able to successfully test CollectionService - syncCollection() and signin().