firestore-jest-mock icon indicating copy to clipboard operation
firestore-jest-mock copied to clipboard

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

Open stasmotorny opened this issue 11 months ago • 2 comments

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.

stasmotorny avatar Mar 26 '24 22:03 stasmotorny

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
  });
});

sbatson5 avatar Mar 29 '24 14:03 sbatson5

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 <ListItem /> 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')

stasmotorny avatar Mar 29 '24 18:03 stasmotorny