Заглушка единой экспортируемой функции с Sinon - PullRequest
0 голосов
/ 14 июня 2019

Я только что изменил свой импорт lodash с import _ from 'lodash'; на import debounce from 'lodash/debounce';
В моем тесте у меня было sandbox.stub(_, 'debounce').returnsArg(0);, но теперь я застрял в том, что его изменить.Очевидно, sandbox.stub(debounce).returnsArg(0); не будет работать.Не уверен, что делать, когда из модуля экспортируется только одна функция.

1 Ответ

0 голосов
/ 22 июня 2019

Этот синтаксис:

import something from 'myModule';

... - это синтаксис ES6, который связывает something с default экспортом 'myModule '.

Если модуль является модулем ES6, вы можете заблокировать default экспорт модуля следующим образом:

import * as myModule from 'myModule';
const sinon = require('sinon');

// ...

const stub = sinon.stub(myModule, 'default');

... но это работает, только если 'myModule' является модулем ES6.

В этом случае 'lodash/debounce' не является модулем ES6, он поставляется предварительно скомпилированным. Последняя строка такова:

module.exports = debounce;

... что означает, что экспорт модуля равен функции debounce.

Это означает, что для того, чтобы заглушить 'lodash/debounce', вам нужно смоделировать весь модуль.

Sinon не обеспечивает насмешки на уровне модулей, поэтому вам нужно использовать что-то вроде proxyquire:

const proxyquire = require('proxyquire');
const sinon = require('sinon');

const debounceStub = sinon.stub().returnsArg(0);
const code = proxyquire('[path to your code]', { 'lodash/debounce': debounceStub })

... или если вы используете Jest, вы можете использовать что-то вроде jest.mock:

jest.mock('lodash/debounce', () =>
  jest.fn((func, ms) => func)  // <= mock debounce to simply return the function
);

Детали

Причина, по которой сохранение модуля экспорта default работает только в том случае, если это модуль ES6, вызвана тем, что происходит во время компиляции.

Синтаксис ES6 компилируется в пре-ES6 JavaScript. Например, Бабель превращает это:

import something from 'myModule';

... в это:

var _myModule = _interopRequireDefault(require("myModule"));

function _interopRequireDefault(obj) {
  return obj && obj.__esModule ?
    obj :  // <= return the result of require("myModule") if it is an ES6 module...
    { default: obj };  // <= otherwise set it to the default property of a wrapper object
}

... поэтому, если 'myModule' является модулем ES6, он возвращается напрямую ... но если это не так, то взаимодействие возвращает объект переноса.

Поскольку каждый import получает свой объект-обертку, изменение свойства default для одного не влияет на свойство default для других.

...