sbatson5 / firestore-jest-mock

Jest Helper library for mocking Cloud Firestore
https://www.npmjs.com/package/firestore-jest-mock
177 stars 57 forks source link

How to mock properly @react-native-firebase/firestore #188

Open stasmotorny opened 7 months ago

stasmotorny commented 7 months ago

Hey, guys. I'm trying to mock firestore for testing, but can't find the wright workaround.

my mock for firestore:

import {jest} from '@jest/globals';
import {mockReactNativeFirestore} from 'firestore-jest-mock';

const db = {
  userCollection: {
    1: {
      collection: [101922, 1535, 105778, 105398, 30002],
    },
  },
};

jest.mock('@react-native-firebase/firestore', () =>
  mockReactNativeFirestore(db),
);

With this implementation my tests often fails with error TypeError: (0 , _firestore.default) is not a function. I think something is wrong with my mock but can't figure out what exactly.

sbatson5 commented 7 months ago

mockReactNativeFirestore actually does the mock for you, so you shouldn't have to call jest.mock. The test should look like:

describe('your test', () => {
  mockReactNativeFirestore({
    userCollection: {
      1: {
        collection: [101922, 1535, 105778, 105398, 30002],
      },
    },
  };

  test('something', () => {
      // the rest of the test
  });
});
stasmotorny commented 7 months ago

mockReactNativeFirestore actually does the mock for you, so you shouldn't have to call jest.mock. The test should look like:

describe('your test', () => {
  mockReactNativeFirestore({
    userCollection: {
      1: {
        collection: [101922, 1535, 105778, 105398, 30002],
      },
    },
  };

  test('something', () => {
      // the rest of the test
  });
});

Hm. My tests still failed. This time I mocked firestore like this:

mockReactNativeFirestore({
  database: {
    userCollection: [
      {
        id: '1',
        collection: [101922, 1535, 105778, 105398, 30002],
      },
    ],
  },
});

My test looks like this:

it('should render item title', () => {
  const wrapper = render(<ListItem item={item} isInCollection={true} />);
  expect(wrapper.getAllByText('Some title')).toHaveLength(1);
  expect(wrapper.getAllByText('Finished')).toHaveLength(1);
});

Inside component I'm using firestore like this:

const firebase = firestore().collection('userCollection').doc(user?.user.uid);
<Button
  testID="remove_button"
  onPress={() => {
    firebase.update({
      collection: firestore.FieldValue.arrayRemove(item.id),
    });
  }}>
            Remove
</Button>

The only way I found to make tests work is to mock firebase manually like this:

jest.mock('@react-native-firebase/firestore', () => {
  const mockFirestore: any = jest.fn().mockReturnValue({
    collection: jest.fn().mockReturnValue({
      doc: jest.fn().mockReturnValue({
        collection: [101922, 1535, 105778, 105398, 30002],
        update: jest.fn(),
      }),
    }),
  });

  mockFirestore.FieldValue = {
    arrayUnion: jest.fn(),
    arrayRemove: jest.fn(),
  };

  return mockFirestore;
});

This way works but I will need to extend it for every new case, so it is better to use your library.

I will appreciate any ideas of how to make it work. Thank you.

Oh, I forgot to add an error I got during the test.

TypeError: Cannot read properties of undefined (reading 'collection')