1

I have MyComponent.tsx that uses constants.ts module in order to do something based on the IS_IOS constant:

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

import { platform } from '../../constants';

const { IS_IOS } = platform;
interface Props {}

export const MyComponent = (props: Props) => {
  return (
    <View>
      <Text>Alpha Beta { String(IS_IOS) }</Text>
    </View>
  );
};

I am trying to mock constants.ts differently in each test. I have tried all methods from here and here, but still no results. The module is not mocked at all. Here are my test file, and component file:

MyComponent.test.tsx:

// @ts-nocheck
import React from 'react';
import { cleanup, render } from '@testing-library/react-native';
import { MyComponent } from '../../../src/MyComponent';

describe('MyComponent', () => {
  afterEach(() => {
    jest.resetModules();
    jest.clearAllMocks();
    cleanup();
  });

  it('one', () => {
    jest.mock('../../../src/constants', () => ({
      platform: { IS_IOS: false }
    }));

    const { debug } = render(<MyComponent/>);
    debug();
  });

  it('two', () => {
    jest.mock('../../../src/constants', () => ({
      platform: { IS_IOS: true }
    }));

    const { debug } = render(<MyComponent/>);
    debug();
  });
});

This is the result that I get into the console:

  console.log
    <View>
      <Text>
        Alpha Beta 
        true
      </Text>
    </View>

      at debugDeep (node_modules/@testing-library/react-native/build/helpers/debugDeep.js:19:13)

  console.log
    <View>
      <Text>
        Alpha Beta 
        true
      </Text>
    </View>

      at debugDeep (node_modules/@testing-library/react-native/build/helpers/debugDeep.js:19:13)

Now, it works if I put jest.mock at the beginning of the file, but the problem is that it mocks IS_IOS with same value (i.e. IS_IOS = false):

// @ts-nocheck
import React from 'react';
import { cleanup, render } from '@testing-library/react-native';
import { MyComponent } from '../../../src/MyComponent';

jest.mock('../../../src/constants', () => ({
  platform: { IS_IOS: false }
}));

describe('MyComponent', () => {
  afterEach(() => {
    jest.resetModules();
    jest.clearAllMocks();
    cleanup();
  });

  it('one', () => {
    const { debug } = render(<MyComponent/>);
    debug();
  });

  it('two', () => {
    const { debug } = render(<MyComponent/>);
    debug();
  });
});

As I said, mocks in both cases:

  console.log
    <View>
      <Text>
        Alpha Beta 
        false
      </Text>
    </View>

      at debugDeep (node_modules/@testing-library/react-native/build/helpers/debugDeep.js:19:13)

  console.log
    <View>
      <Text>
        Alpha Beta 
        false
      </Text>
    </View>

      at debugDeep (node_modules/@testing-library/react-native/build/helpers/debugDeep.js:19:13)

I have tried jest.doMock, tried adding __esModule - none of it works. How do I mock module differently in each test?

Thanks in advance for your time!

Petro Ivanenko
  • 637
  • 2
  • 8
  • 19

1 Answers1

2

jest.resetModules cannot affect modules that have already been imported. It should be combined with require that is local to a test in order for test-specific jest.mock to affect it.

ES modules should be mocked with magic __esModule property in order for them to not be processed as CommonJS modules:

jest.mock('../../../src/constants', () => ({
  __esModule: true,
  platform: { IS_IOS: false }
}));
const { MyComponent } = require('../../../src/MyComponent');
Estus Flask
  • 206,104
  • 70
  • 425
  • 565
  • Thanks for your input, but how do I use this knowledge to solve my problem? I can't move imports from MyComponent into my tests. – Petro Ivanenko Jan 22 '21 at 11:45
  • You shouldn't necessarily move them, although nothing prevents you from doing that. You should use them in addition to top-level imports. A test uses `MyComponent` that is local to it. The same applies to any other import that depends on test-specific mock. – Estus Flask Jan 22 '21 at 12:07
  • Thanks a lot! It was exactly what I needed! I also had to write it like that: `{ MyComponent: MyComponentLocal }` to comply with eslint no-shadow requirement. – Petro Ivanenko Jan 25 '21 at 08:20