在这里我问的这个问题:
我在问模块突变的性质。
事实证明,ES6模块实际上无法进行突变-它们的所有属性都被视为常量。 (See this answer)
但是以某种方式-当Jest测试模块时-它们可以被突变,这就是Jest允许模拟的方式。
这是怎么回事?
我想象它正在运行的babel插件-将模块转换为CommonJS模块?是否有任何相关文档?
有没有办法查看转译的代码?
答案 0 :(得分:6)
ES6模块实际上不能被突变-它们的所有属性都被视为常量。
有趣。您是对的,甚至像这样简单的事情:
import * as lib from "./lib"; // import an ES6 module
const spy = jest.spyOn(lib, 'someFunc'); // spy on someFunc
...从技术上讲,这是不允许的,因为jest.spyOn
replaces the method on the object with a spy和lib.someFunc
应该是ES6模块中与someFunc
的绑定。
但是以某种方式-当Jest测试模块时-它们可以被突变,这就是Jest允许模拟的方式。
这是怎么回事?
只能更改它们,因为Jest
实际上并未使用ES6模块。
(出于完整性考虑,可能可以通过使用Jest
的{{3}}使用实际的ES6模块运行Node
,但是我没有尝试过)。
我想象这是一个正在运行的babel插件-编译模块...关于此的任何文档吗?
experimental support for ES6 Modules。
因此,默认情况下,Jest
将使用babel-jest
,后者会使用babel
来转译源代码(并进行其他一些操作,例如"babel-jest
is automatically installed when installing Jest and will automatically transform files if a babel configuration exists in your project. To avoid this behavior, you can explicitly reset the transform
configuration option")。
请注意,Jest
也可以使用hoisting calls to jest.mock
进行配置,该映射将“正则表达式映射到转换器的路径”。
有没有办法查看转译的代码?
是的。转换是在jest-runtime
transform
中完成的,并将输出保存到缓存here。
查看已编译代码的最简单方法是查看缓存。
您可以通过使用here选项运行Jest
来执行此操作,该选项将输出运行config
时使用的Jest
。通过查看“ cacheDirectory”的值可以找到缓存位置。
然后使用--showConfig
选项运行Jest
以清除缓存。
最后,正常运行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
--clearCache
时,code.js
和code.test.js
都会从require('./lib')
获取相同的对象。
someFunc
导出为exports.someFunc
,可以重新分配。
是的,你是完全正确的。这样的间谍活动(或嘲笑)仅能正常工作,因为babel
将ES6模块以允许它们突变的方式转换为Node
模块。