Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

React Native Firestore mock does not work with react-native-firebase package #196

Open
GitGeddes opened this issue Jul 14, 2024 · 0 comments

Comments

@GitGeddes
Copy link

Description

I am using React Native with the react-native-firebase package and tried using firestore-jest-mock to mock my database. Currently, my tests fail when using the mock as the documentation suggests. The documentation for these two packages do not align.

The react-native-firestore package documentation suggests importing firestore as the default export like so and calling firestore as the default function:

import firestore from '@react-native-firebase/firestore';

const usersCollection = firestore().collection('users');

Whereas firestore-jest-mock documentation suggests importing an injected Firestore stub that does not exist in @react-native-firebase/firestore then calling its constructor.

// mockReactNativeFirestore called above
test('testing stuff', () => {
  const { Firestore } = require('@react-native-firebase/firestore'); // Doesn't normally exist in this package
  const firestore = new Firestore();

  // Notice we're not calling firestore as a function
  return firestore
    .collection('users')
    .get()
    .then(userDocs => {
      expect(mockCollection).toHaveBeenCalledWith('users');
      expect(userDocs.docs[0].data().name).toEqual('Homer Simpson');
    });
});

I am not familiar with the @google-cloud/firestore package and how the documentation suggests we use it, so I'm not sure how different it is from react-native-firebase. I utilize other parts of the API like FieldValue and FieldPath in my production code. When using mockReactNativeFirebase the code I wanted to test would fail to load, saying these were all undefined or that firestore is not a function.

Steps to reproduce

  1. Create new React Native project
  2. Install @react-native-firebase/firestore and firestore-jest-mock
  3. Set up Jest and Firestore mock using firestore-jest-mock documentation
  4. Create tests for firestore using @react-native-firebase/firestore documentation

firestore.test.ts

import {mockCollection} from 'firestore-jest-mock/mocks/firestore';
import firestore, {firebase} from '@react-native-firebase/firestore';

describe('firestore-jest-mock tests', () => {
  it('gets a user', async () => {
    await firestore().collection('users').doc('test').get();
    expect(mockCollection).toHaveBeenCalledWith('users');
  });
  it('creates and uses an increment function', async () => {
    const incrementFunction = firebase.firestore.FieldValue.increment(1);
    await firestore()
      .collection('users')
      .doc('test')
      .set({followerCount: incrementFunction}, {merge: true});
    expect(mockCollection).toHaveBeenCalledWith('users');
  });
});

firestoreMock.setup.ts

import {mockReactNativeFirestore} from 'firestore-jest-mock';

mockReactNativeFirestore({
  database: {
    users: [
      {
        id: 'test',
        followerCount: 0,
      },
    ],
  },
});

// Needed to get Jest working in a React Native project
jest.mock('react-native/Libraries/EventEmitter/NativeEventEmitter');

Expected result

Firestore tests pass.

Actual result

Tests fail after using mockReactNativeFirestore({ database: { ... }}).

When running Jest tests:

...
    TypeError: (0 , _firestore2.default) is not a function

      4 | describe('firestore-jest-mock tests', () => {
      5 |   it('gets a user', async () => {
    > 6 |     await firestore().collection('users').doc('test').get();
...
    TypeError: Cannot read properties of undefined (reading 'firestore')

       8 |   });
       9 |   it('creates and calls an increment function', async () => {
    > 10 |     const incrementFunction = firebase.firestore.FieldValue.increment(1);
...

The same errors appear when trying to render components that reference firestore() during tests as well.

Environment

  • Node version: 20.11.1
  • React Native version 0.74.3
  • React version 18.2.0
  • @react-native-firebase/app: "^20.1.0",
  • @react-native-firebase/firestore: "^20.1.0",
  • firestore-jest-mock: "^0.25.0"

Potential Fix

I have already created a patch using patch-package to fix these errors in my project:

patches/firestore-jest-mock+0.25.0.patch

diff --git a/node_modules/firestore-jest-mock/mocks/reactNativeFirebaseFirestore.js b/node_modules/firestore-jest-mock/mocks/reactNativeFirebaseFirestore.js
index 2f0e0ea..574b26a 100644
--- a/node_modules/firestore-jest-mock/mocks/reactNativeFirebaseFirestore.js
+++ b/node_modules/firestore-jest-mock/mocks/reactNativeFirebaseFirestore.js
@@ -25,7 +25,18 @@ const mockReactNativeFirestore = (overrides = {}, options = defaultOptions) => {
 function mockModuleIfFound(moduleName, overrides, options) {
     try {
         require.resolve(moduleName);
-        jest.doMock(moduleName, () => firestoreStub(overrides, options));
+        jest.doMock(moduleName, () => {
+            const stub = firestoreStub(overrides, options);
+            return {
+                __esModule: true,
+                default: () => new (stub.Firestore)(),
+                firebase: {
+                    firestore: {
+                        ...stub
+                    }
+                }
+            }
+        });
     }
     catch (e) {
         // eslint-disable-next-line no-console

Notice that instead of returning the firestoreStub directly, it now returns as an esModule with a default method so that we can use firestore() how @react-native-firebase/firestore suggests. I also added the firebase object so that it matches the exports of @react-native-firebase/firestore. For example, the suggested way to use FieldValue and FieldPath are like so:

import { firebase } from '@react-native-firebase/firestore`;

const incrementFunction = firebase.firestore.FieldValue.increment(1);
const fieldPath = new firebase.firestore.FieldPath('parent', 'child');

With my patch all of these tests pass now with no changes to my production code. I'd like to make this change a PR, as well as updating documentation and test cases. I looked at the tests and this would break every mockReactNativeFirestore test in full-setup-library-firestore.test.js but only require minor, repetitive changes. Forgive me if this is the wrong way to suggest this change.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant