问题描述
在这里我问的这个问题:
In this question that I asked here:
为什么如果从另一个模块调用该模块,对一个模块进行变异会更新引用吗?如果从其自身调用,则不会更新该引用吗?
我在问模块突变的性质.
I'm asking about the nature of module mutation.
事实证明,ES6模块实际上无法进行突变-它们的所有属性都被视为常量. (查看此答案)
However as it it turns out, ES6 modules can't actually be mutated - all of their properties are treated as constants. (See this answer)
但是以某种方式-当Jest测试模块时-它们可以被突变,这就是Jest允许模拟的方式.
But somehow - when Jest tests modules - they can be mutated, and that's how Jest allows for mocking.
这是怎么回事?
我想象这是一个正在运行的babel插件-将模块转换为CommonJS模块吗?是否有任何相关文档?
I imagine that it's a babel plugin that that's running - transpiling the module to CommonJS modules? Is there any documentation about this?
有没有办法查看转译的代码?
Is there a way to view the transpiled code?
推荐答案
有趣.您是对的,甚至像这样简单的事情:
Interesting. You're right, even something as simple as this:
import * as lib from "./lib"; // import an ES6 module
const spy = jest.spyOn(lib, 'someFunc'); // spy on someFunc
...从技术上讲不应被允许,因为jest.spyOn
用间谍代替对象上的方法,lib.someFunc
应该与ES6模块中的someFunc
绑定.
...technically shouldn't be allowed since jest.spyOn
replaces the method on the object with a spy and lib.someFunc
should be a binding to someFunc
in the ES6 module.
这是怎么回事?
只能更改它们,因为Jest
实际上并未使用ES6模块.
They can only be mutated because Jest
isn't actually using ES6 modules.
(出于完整性考虑,可能可以通过使用Node
的对ES6模块的实验支持,但我没有尝试过.)
(I guess for completeness it might be possible to run Jest
using actual ES6 modules by using Node
's experimental support for ES6 Modules but I haven't tried).
"babel-jest
在安装Jest时自动安装,并且在安装时会自动转换文件项目中存在babel配置.要避免这种情况,可以显式重置transform
配置选项" .
"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
将使用babel-jest
,该代码将使用babel
编译源代码(并执行其他一些操作,例如提升对jest.mock
的调用).
So by default Jest
will use babel-jest
which transpiles the source code using babel
(and does a few other things like hoisting calls to jest.mock
).
请注意,也可以使用 transform
来配置Jest
将正则表达式映射到转换器的路径".
Note that Jest
can be also be configured using transform
which maps "regular expressions to paths to transformers".
是的.转换在jest-runtime
,然后将输出保存到缓存此处.
Yes. Transformations are done in jest-runtime
here and the output is saved to a cache here.
查看已编译代码的最简单方法是查看缓存.
The easiest way to look at the transpiled code is to view the cache.
您可以通过使用 --showConfig
选项运行Jest
来做到这一点.将输出运行Jest
时使用的config
.通过查看"cacheDirectory"的值可以找到缓存位置.
You can do that by running Jest
with the --showConfig
option which will output the config
used when running Jest
. The cache location can be found by looking at the value of "cacheDirectory".
然后使用 --clearCache
选项运行Jest
以清除缓存
最后,正常运行Jest
,缓存目录将包含您项目的已转码代码.
Finally, run Jest
normally and the cache directory will contain the transpiled code for your project.
示例
最新的Jest
(v24)将转换此代码:
The latest Jest
(v24) will transpile this code:
// 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
处理,_interopRequireWildcard
在后台使用require
.
The import * as lib from 'lib';
line gets handled by _interopRequireWildcard
which uses require
under the hood.
每次调用require
都会得到完全相同的返回对象,如果它将解析为相同的文件" ,因此code.js
和code.test.js
从require('./lib')
获取相同的对象.
Every call to require
"will get exactly the same object returned, if it would resolve to the same file" so code.js
and code.test.js
are getting the same object from require('./lib')
.
someFunc
导出为exports.someFunc
,从而可以对其进行重新分配.
someFunc
is exported as exports.someFunc
which allows it to be reassigned.
是的,你是完全正确的.这样的间谍(或嘲笑)仅能起作用,因为babel
将ES6模块以允许它们突变的方式转换为Node
模块.
So yes, you're exactly right. Spying (or mocking) like this only works because the ES6 modules are getting transpiled by babel
into Node
modules in a way that allows them to be mutated.
这篇关于开玩笑如何允许模块的变异?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!