Имитация постоянного свойства из модуля для конкретной тестовой группы

У меня есть MyComponent.tsx, который использует модуль constants.ts, чтобы что-то делать на основе константы IS_IOS:

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

Я пытаюсь высмеивать constants.ts по-разному в каждом тесте. Я пробовал все методы из здесь и здесь, но все равно результатов нет. Модуль вообще не издевается. Вот мой тестовый файл и файл компонента:

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

Вот результат, который я получаю в консоли:

  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)

Теперь он работает, если я помещаю jest.mock в начало файла, но проблема в том, что он имитирует IS_IOS с тем же значением (например, 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();
  });
});

Как я уже сказал, издевается в обоих случаях:

  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)

Я пробовал jest.doMock, пытался добавить __esModule - ничего из этого работает. Как по-разному смоделировать модуль в каждом тесте?

Спасибо заранее за ваше время!


person Petro Ivanenko    schedule 22.01.2021    source источник


Ответы (1)


jest.resetModules не может влиять на уже импортированные модули. Его следует комбинировать с require, который является локальным для теста, чтобы jest.mock, специфичный для теста, повлиял на него.

Модули ES следует имитировать с помощью магического свойства __esModule, чтобы они не обрабатывались как модули CommonJS:

jest.mock('../../../src/constants', () => ({
  __esModule: true,
  platform: { IS_IOS: false }
}));
const { MyComponent } = require('../../../src/MyComponent');
person Estus Flask    schedule 22.01.2021
comment
Спасибо за ваш вклад, но как мне использовать эти знания для решения моей проблемы? Я не могу перенести импорт из MyComponent в свои тесты. - person Petro Ivanenko; 22.01.2021
comment
Необязательно перемещать их, хотя ничто не мешает вам это сделать. Их следует использовать в дополнение к импорту верхнего уровня. В тесте используется локальный MyComponent. То же самое относится к любому другому импорту, который зависит от тестового макета. - person Estus Flask; 22.01.2021
comment
Большое спасибо! Это было именно то, что мне нужно! Мне также пришлось написать это так: { MyComponent: MyComponentLocal }, чтобы соответствовать требованию eslint no-shadow. - person Petro Ivanenko; 25.01.2021