nrwl / nx-react-native

87 stars 21 forks source link

jest module mocks inside tests are not working #35

Open dominikspiertz opened 3 years ago

dominikspiertz commented 3 years ago

Hello everybody, and first of all thanks for making react-native work inside the nx environment.

I normally use nx with react and node. I just started my first react native project with nx. When writing tests with jest and @testing-library/react-native, I'd normally use jest.mock('./module') and jest.spyOn to mock external dependencies in my unit tests.

When using a clean install of the most recent version of create-nx-workspace and @nrwl/react-native this is not possible, which makes it impossible for me to work on a project with react native and nx. If you indeed use jest.mock from the setup file test-setup.ts this is possible. Since it does not help creating individual mocks depending on the test case that does not help or replace the desired effect.

Here is an example of the procedure:

Hello.tsx (Component added to App.tsx)

import React, { FC } from 'react';
import { Text } from 'react-native';

export const Hello: FC = () => {
  return <Text>Hello</Text>
}

App.spec.ts

import { Text } from 'react-native';
import React from 'react';
import { cleanup, render } from '@testing-library/react-native';

// Avoid conflict with app.json
// @ts-ignore
import App from './App.tsx';
import * as Hello from './Hello';

jest.mock('./Hello')

describe('<App />', () => {
  afterEach(cleanup)
  beforeEach(() => {
    jest.spyOn(Hello, 'Hello').mockReturnValue(<Text>MockedHello</Text>)
  })

  it('renders correctly', () => {
    const { getByText } = render(<App />);
    expect(getByText('MockedHello')).toBeDefined()
  });
})

This throws the error, that I cannot override the component, even if it has been mocked with jest.mock:

TypeError: Cannot redefine property: Hello
        at Function.defineProperty (<anonymous>)

      afterEach(cleanup)
      beforeEach(() => {
      >  jest.spyOn(Hello, 'Hello').mockReturnValue(<Text>MockedHello</Text>)
         |          ^

I am thankful for feedback, since everything else seems to work like a charm with the react native plugin. Thanks in advance

gioragutt commented 3 years ago

any update on this?

shaikhrahil commented 2 years ago

After going through a number of solutions online, a lot of documentation , and none of them working out, I found something that works for me. Please feel free to update / improve on it

So instead of mocking at the top, I started creating a mockRender variable and run it beforeEach. Code example:

describe('dashboard.tsx', () => {
  let mockRender
  beforeEach(() => {
    mockRender = () =>
      render(
        <CustomAppWrapper
          init={{
            firstName: 'Rahil',
            lastName: 'Shaikh',
            id: 123,
          }}
        >
          <Dashboard />
        </CustomAppWrapper>,
      )
  })

  it('shows loader', () => {
    useStats.mockImplementation(() => ({ connecting: true, listen: jest.fn() }))
    mockRender()
    expect(screen.getByText('Loading ...')).toBeDefined()
  })

  it('shows error message', () => {
    const error = 'Unable to load'
    useStats.mockImplementation(() => ({ error, listen: jest.fn() }))
    mockRender()
    expect(screen.getByText(error)).toBeDefined()
  })
})

This is a sample of what I have implemented. Hope it helps out any one stuck with this ✌

@gioragutt @dominikspiertz