Home > OS >  How to reset firestore unit testing my Cloud Functions with jest
How to reset firestore unit testing my Cloud Functions with jest

Time:09-22

I followed the Cloud Functions recommendation and created my unit testing in online mode, everything makes sense to me, but I am getting inconsistency when I am debugging. I just trying to reset the firestore state by resetting and seeding the database.

When I run my test suite separately, they work perfectly; if I run all the test suites together appear all the errors, I am pretty sure that this is related to the beforeEach hooks but idk how to fix them.

I have 3 test suites, I will share with you 1 of them and the function responsible of the reset of the firestore.

// eslint-disable-next-line spaced-comment
    /// <reference types="jest" />

    import { cleanup, getDb, initializeFirebase, makeChange, resetDb, wrap } from './util';
    initializeFirebase();

    import { streamerIsOffline, streamerIsOnline } from './__fixtures__/onStreamerUpdateSnaps';
    import { getScheduler, SchedulerClientWrapper } from './../utils/SchedulerClientWrapper';
    import onStreamerUpdate from '../onStreamerUpdate';

    const db = getDb();

    jest.mock('./../utils/SchedulerClientWrapper');

    const mockedGetScheduler = jest.mocked(getScheduler, true);

    const wrapped = wrap(onStreamerUpdate);

    const schedulerClientWrapper = new SchedulerClientWrapper();
    const mockedPause: jest.Mock = jest.fn();
    const mockedResume: jest.Mock = jest.fn();
    const mockedJobIsEnabled: jest.Mock = jest.fn();


    schedulerClientWrapper.pause = mockedPause;
    schedulerClientWrapper.resume = mockedResume;
    schedulerClientWrapper.jobIsEnabled = mockedJobIsEnabled;

    describe('onStreamerUpdate', () => {
      beforeEach(
          async () => {
            await resetDb(); //I am resetting firestore here
            mockedGetScheduler.mockClear();
            jest.resetAllMocks();
          });

      it('should resume the scheduledJob when the first streamer becomes online',
          async () => {
            await updateStreamerStatus('64522496', true); //I am preparing the setup here

            const beforeSnap = streamerIsOffline;
            const afterSnap = streamerIsOnline;

            const change = makeChange(beforeSnap, afterSnap);

            mockedGetScheduler.mockReturnValue(schedulerClientWrapper);

            mockedJobIsEnabled.mockResolvedValue(false);

            await wrapped(change);

            expect(mockedJobIsEnabled).toBeCalled();
            expect(mockedResume).toBeCalled();
            expect(mockedPause).not.toBeCalled();
          });
          
      afterAll(() => {
        cleanup();
      });
      
    });

    const updateStreamerStatus = async (streamerId: string, isOnline: boolean) => {
      const stremersRef = db.collection('streamers');

      const query = stremersRef.where('broadcasterId', '==', streamerId);
      const querySnapshot = await query.get();
      console.log('streamers', (await stremersRef.get()).docs.map((doc) => doc.data())); //I am debugging here
      const streamerDocId = querySnapshot.docs[0].id;
      await stremersRef.doc(streamerDocId).update({ isOnline });
    };

And you can find the functions that wipe and seed firestore below:

import firebaseFunctionsTest from 'firebase-functions-test';
import { getApp, getApps, initializeApp, cert } from 'firebase-admin/app';
import { getFirestore } from 'firebase-admin/firestore';

const projectId = 'latamqchallengetest';

export const { wrap, cleanup, firestore: firestoreTestData, makeChange } = firebaseFunctionsTest({
  databaseURL: `https://${projectId}.firebaseio.com`,
  storageBucket: `${projectId}.appspot.com`,
  projectId: projectId,
}, './../google-credentials/latamqchallengetest-firebase-adminsdk.json');

export const initializeFirebase = () => {
  if (getApps().length <= 0) {
    initializeApp({
      credential: cert('./../google-credentials/latamqchallengetest-firebase-adminsdk.json'),
    });
  }
  return getApp();
};

export const getDb = () => {
  initializeFirebase();
  const db = getFirestore();
  return db;
};

export const wipeDb = async () => {
  const db = getDb();
  const collections = await db.listCollections();
  const deletePromises = collections.map((collectionRef) =>
    db.recursiveDelete(collectionRef));

  Promise.all([...deletePromises]);
};

export const seed = async () => {
  const db = getDb();
  await db.collection('streamers').add({
    broadcasterId: '64522496',
    broadcasterName: 'ITonyl',
    color: '1565C0',
    description: 'Sr. Truchita',
    isOnline: false,
    puuid: 'kRQyIDe5TfLhWtn8jXgo_4Zjlfg4rPypXWiPCXrkTMUsiQT3TYVCkVO6Au3QTdd4x-13CbluPA53dg',
    summonerId: '9bnJOmLXDjX-sgPjn4ZN1_-f6m4Ojd2OWlNBzrdH0Xk2xw',
  });
  await db.collection('streamers').add({
    broadcasterId: '176444069',
    broadcasterName: 'Onokenn',
    color: '424242',
    description: 'El LVP Player',
    isOnline: false,
    puuid: 'Gbfj8FyB6OZewfXgAwvLGpkayA6xyevFfEW7UZdrzA6saKVTyntP4HxhBQFd_EIGa_P1xC9eVdy8sQ',
    summonerId: 'pPWUsvk_67FuF7ky1waWDM_gho-3NYP4enWTtte6deR3CjxOGoCfoIjjNw',
  });
};

export const resetDb = async () => {
  await wipeDb();
  await seed();
};

Sometimes I find that firestore has 4 records, other times it has 0 records, 2 records and so on .. I don't know why I await the promises before each test.

I expect to keep the same state before each test, can you help me please?

CodePudding user response:

All the problem was the parallel behavior of jest, I just needed to run the tests sequentially with the param --runInBand or maxWorkers=1

  • Related