Модули 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
экспериментальной поддержки модулей ES6 , но я не пробовал).
Я предполагаю, что это плагин babel, который работает - перенос модуля ... Есть ли какая-либо документация по этому поводу?
"babel-jest
автоматически устанавливается при установке Jest и автоматически преобразует файлы, если в вашем проекте есть конфигурация babel. Чтобы избежать этого, вы можете явно сбросить параметр конфигурации transform
" .
Таким образом, по умолчанию Jest
будет использовать babel-jest
, который переносит исходный код с помощью babel
(и делает несколько других вещей, таких как подъем вызовов на jest.mock
).
Обратите внимание, что Jest
также можно настроить с помощью transform
, который отображает «регулярные выражения на пути к преобразователям».
Есть ли способ просмотреть перенесенный код?
Да. Преобразования выполняются в jest-runtime
здесь и выходные данные сохраняются в кэш здесь .
Самый простой способ взглянуть на переданный код - это просмотреть кэш.
Вы можете сделать это, запустив Jest
с параметром --showConfig
, который выведет config
, используемый при запуске Jest
. Расположение кеша можно найти, посмотрев на значение «cacheDirectory».
Затем запустите Jest
с параметром --clearCache
, чтобы очистить кэш.
Наконец, запустите Jest
в обычном режиме, и каталог кэша будет содержать переданный код для вашего проекта.
Пример * +1091 ** * тысяча девяносто-два
Последний 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
модулями таким образом, что их можно изменять.