Подтвердить что ты не робот

Как я могу высмеять импорт модуля ES6 с помощью Jest?

Я начинаю думать, что это невозможно, но я все равно хочу спросить.

Я хочу проверить, что один из моих модулей ES6 вызывает другой модуль ES6 определенным образом. С Жасмин это очень просто -

Код приложения:

// myModule.js
import dependency from './dependency';

export default (x) => {
  dependency.doSomething(x * 2);
}

И тестовый код:

//myModule-test.js
import myModule from '../myModule';
import dependency from '../dependency';

describe('myModule', () => {
  it('calls the dependency with double the input', () => {
    spyOn(dependency, 'doSomething');

    myModule(2);

    expect(dependency.doSomething).toHaveBeenCalledWith(4);
  });
});

Что эквивалентно Jest? Я чувствую, что это такая простая вещь, которую хочется делать, но я рвал волосы, пытаясь понять это.

Ближе всего я пришел, заменив import на require s и перемещая их внутри тестов/функций. Ни то, что я хочу сделать.

// myModule.js
export default (x) => {
  const dependency = require('./dependency'); // yuck
  dependency.doSomething(x * 2);
}

//myModule-test.js
describe('myModule', () => {
  it('calls the dependency with double the input', () => {
    jest.mock('../dependency');

    myModule(2);

    const dependency = require('../dependency'); // also yuck
    expect(dependency.doSomething).toBeCalledWith(4);
  });
});

Для бонусных очков я бы хотел, чтобы все это работало, когда функция внутри dependency.js является экспортом по умолчанию. Тем не менее, я знаю, что шпионаж об экспорте по умолчанию не работает в Jasmine (или, по крайней мере, я никогда не смог заставить его работать), поэтому я не надеюсь, что это возможно и в Jest.

4b9b3361

Ответ 1

Я смог решить эту проблему с помощью взлома с использованием import *. Это даже работает как для именованных, так и для экспорта по умолчанию!

Для именованного экспорта:

// dependency.js
export const doSomething = (y) => console.log(y)

// myModule.js
import { doSomething } from './dependency';

export default (x) => {
  doSomething(x * 2);
}

// myModule-test.js
import myModule from '../myModule';
import * as dependency from '../dependency';

describe('myModule', () => {
  it('calls the dependency with double the input', () => {
    dependency.doSomething = jest.fn(); // Mutate the named export

    myModule(2);

    expect(dependency.doSomething).toBeCalledWith(4);
  });
});

Или для экспорта по умолчанию:

// dependency.js
export default (y) => console.log(y)

// myModule.js
import dependency from './dependency'; // Note lack of curlies

export default (x) => {
  dependency(x * 2);
}

// myModule-test.js
import myModule from '../myModule';
import * as dependency from '../dependency';

describe('myModule', () => {
  it('calls the dependency with double the input', () => {
    dependency.default = jest.fn(); // Mutate the default export

    myModule(2);

    expect(dependency.default).toBeCalledWith(4); // Assert against the default
  });
});

Как правильно заметил ниже Михай Дамиан, это мутирует объект dependency модуля, и поэтому он "просочится" в другие тесты. Поэтому, если вы используете этот подход, вы должны сохранить исходное значение и затем устанавливать его снова после каждого теста. Чтобы сделать это легко с Jest, используйте метод spyOn() вместо jest.fn() потому что он поддерживает легкое восстановление его исходного значения, поэтому избегая ранее упомянутой "утечки".

Ответ 2

Вы должны издеваться над модулем и установить шпиона самостоятельно:

import myModule from '../myModule';
import dependency from '../dependency';
jest.mock('../dependency', () => ({
  doSomething: jest.fn()
}))

describe('myModule', () => {
  it('calls the dependency with double the input', () => {
    myModule(2);
    expect(dependency.doSomething).toBeCalledWith(4);
  });
});

Ответ 3

Добавим больше к Андреасу ответ. У меня была та же проблема с кодом ES6, но я не хотел мутировать импорт. Это выглядело взломанным. Поэтому я сделал это

import myModule from '../myModule';
import dependency from '../dependency';
jest.mock('../dependency');

describe('myModule', () => {
  it('calls the dependency with double the input', () => {
    myModule(2);
  });
});

И добавьте dependency.js в папку "__ mocks __" параллельно с dependency.js. Это сработало для меня. Кроме того, это дало мне возможность возвращать подходящие данные из макетной реализации. Убедитесь, что вы указали правильный путь к модулю, который хотите высмеять.

Ответ 4

Чтобы высмеять модуль загрузки зависимостей ES6 по умолчанию, используя jest:

import myModule from '../myModule';
import dependency from '../dependency';

jest.mock('../dependency');

// If necessary, you can place a mock implementation like this:
dependency.mockImplementation(() => 42);

describe('myModule', () => {
  it('calls the dependency once with double the input', () => {
    myModule(2);

    expect(dependency).toHaveBeenCalledTimes(1);
    expect(dependency).toHaveBeenCalledWith(4);
  });
});

Другие варианты не помогли мне.

Ответ 5

Я решил это по-другому. Допустим, у вас есть зависимость .js

export const myFunction = () => { }

Помимо этого я создаю файл depdency.mock.js со следующим содержимым:

export const mockFunction = jest.fn();

jest.mock('dependency.js', () => ({ myFunction: mockFunction }));

и в тесте, прежде чем импортировать файл с зависимостью, которую я использую:

import { mockFunction } from 'dependency.mock'
import functionThatCallsDep from './tested-code'

it('my test', () => {
    mockFunction.returnValue(false);

    functionThatCallsDep();

    expect(mockFunction).toHaveBeenCalled();

})

Ответ 6

На вопрос уже дан ответ, но вы можете решить его следующим образом:

dependency.js

module.exports.doSomething = (x) => x

myModule.js:

const { doSomething } = require('./dependency')
module.exports = (x) => doSomething(x * 2)

myModule.spec.js:

jest.mock('../dependency')
const { doSomething } = require('../dependency')
const myModule = require('../myModule')
describe('myModule', () => {
    it('calls the dependency with double the input', () => {
      doSomething.mockImplementation((x) => x * 10)

      myModule(2);

      expect(doSomething).toHaveBeenCalledWith(4);
      console.log(myModule(2)) // 40
    });
  });