开玩笑如何允许模块的变异? [英] How does jest allow mutation of modules?

查看:146
本文介绍了开玩笑如何允许模块的变异?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在这里我问的这个问题:

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?

推荐答案

ES6模块实际上不能被突变-它们的所有属性都被视为常量.

ES6 modules can't actually be mutated - all of their properties are treated as constants.

有趣.您是对的,甚至像这样简单的事情:

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

...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测试模块时-它们可以被突变,这就是Jest允许进行模拟的方式.

But somehow - when Jest tests modules - they can be mutated, and that's how Jest allows for mocking.

这是怎么回事?

只能更改它们,因为Jest实际上并未使用ES6模块.

They can only be mutated because Jest isn't actually using ES6 modules.

(出于完整性考虑,可能可以通过使用Node

(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插件-编译模块...关于此的任何文档吗?

I imagine that it's a babel plugin that that's running - transpiling the module...Is there any documentation about this?

"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编译源代码(并执行其他一些操作,例如

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".

有没有办法查看转译的代码?

Is there a way to view the transpiled code?

是的.转换在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.jscode.test.jsrequire('./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.

这篇关于开玩笑如何允许模块的变异?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆