Модули ES6 фактически не могут быть изменены - все их свойства рассматриваются как константы.
Интересный. Вы правы, даже в таком простом случае:
import * as lib from "./lib"; // import an ES6 module
const spy = jest.spyOn(lib, 'someFunc'); // spy on someFunc
... технически недопустимо, поскольку jest.spyOn
заменяет метод объекта на шпион, и lib.someFunc
должен быть привязкой к someFunc
в модуле ES6.
Но каким-то образом - когда Jest тестирует модули - они могут быть видоизменены, и именно так Jest позволяет имитировать.
Как это происходит?
Они могут быть изменены только потому, что Jest
на самом деле не использует модули ES6.
(Я полагаю, для полноты картины возможно можно запустить Jest
с использованием реальных модулей ES6, используя Node
's экспериментальная поддержка модулей ES6, но я не пробовал).
Я полагаю, что это плагин babel, который работает - транспиляция модуля ... Есть ли документация по этому поводу?
babel-jest
автоматически устанавливается при установке Jest и автоматически преобразует файлы, если в вашем проект. Чтобы избежать этого, можно явно сбросить transform
параметр конфигурации.
Таким образом, по умолчанию Jest
будет использовать babel-jest
, который переносит исходный код с помощью babel
(и выполняет еще несколько вещей, например подъем вызовов к jest.mock
).
Обратите внимание, что Jest
также можно настроить с помощью transform
, который отображает обычные выражения к путям к трансформерам.
Есть ли способ просмотреть транспилированный код?
да. Преобразования выполняются в jest-runtime
--showConfig
, который выведет config
, используемый при запуске Jest
. Расположение кеша можно найти, посмотрев значение cacheDirectory.
Затем запустите Jest
с параметром --clearCache
, чтобы очистить кеш.
Наконец, запустите Jest
в обычном режиме, и каталог кеша будет содержать перенесенный код для вашего проекта.
Пример
Последняя версия Jest
(v24) перенесет этот код:
// lib.js
export const someFunc = () => 1;
// code.js
import { someFunc } from './lib';
export const func = () => someFunc() + 1;
// code.test.js
import { func } from './code';
import * as lib from './lib';
test('func', () => {
const spy = jest.spyOn(lib, 'someFunc');
func();
expect(spy).toHaveBeenCalled(); // SUCCESS
});
...к этому:
// lib.js
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.someFunc = void 0;
const someFunc = () => 1;
exports.someFunc = someFunc;
// code.js
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.func = void 0;
var _lib = require("./lib");
const func = () => (0, _lib.someFunc)() + 1;
exports.func = func;
// code.test.js
"use strict";
var _code = require("./code");
var lib = _interopRequireWildcard(require("./lib"));
function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = Object.defineProperty && Object.getOwnPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : {}; if (desc.get || desc.set) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } } newObj.default = obj; return newObj; } }
test('func', () => {
const spy = jest.spyOn(lib, 'someFunc');
(0, _code.func)();
expect(spy).toHaveBeenCalled(); // SUCCESS
});
Строка import * as lib from 'lib';
обрабатывается _interopRequireWildcard
, который использует require
под капотом.
Каждый вызов require
будет возвращать один и тот же объект, если он разрешит одно и то же файл, поэтому code.js
и code.test.js
получают один и тот же объект из require('./lib')
.
someFunc
экспортируется как exports.someFunc
, что позволяет переназначить его.
Так что да, вы совершенно правы. Подобное слежение (или насмешка) работает только потому, что модули ES6 babel
передаются в Node
модули таким образом, чтобы они могли видоизменяться.
person
Brian Adams
schedule
28.01.2019