javascript - 指定在任何 Jest 设置发生之前运行的代码

标签 javascript jestjs

tl;dr 是:

1) 我怎样才能让 Jest 使用 native require 函数在任何地方加载我的测试中的所有模块。

2) 我将在哪里/如何进行修改(即替换为 esm 加载程序)https://github.com/standard-things/esm require 函数在一个地方,在任何测试运行之前,因此所有测试都将使用修改后的 require。


我想使用 esm-loader与我的 Jest 测试文件。为此,我需要在运行任何测试代码之前全局修补 require 函数,例如

require = require("@std/esm")(模块, { esm: "js", cjs: true });

我如何告诉 Jest 在触及或请求任何其他内容之前执行该代码?

我尝试将 setupTestFrameworkScriptFilesetupFiles 数组条目指向一个包含该文件的文件,但都没有用(尽管我确认两者都运行了)。

或者,我使用 npm 脚本启动这些测试

"scripts": {
  "test": "jest"
}

是否有一些 CLI 魔术可以让我加载一个模块然后运行jest


编辑 - testEnvironmentresolver 选项让我想知道这是否曾经使用实际的 Node require 函数来加载模块,或者而不是使用自己的模块加载器。如果是这样,我想知道这是否可能。

最佳答案

所以这个开始工作有点困难。解决方案非常简单,但我花了一段时间才让它工作。问题是无论何时你在 Jest 中使用任何模块

  • 安装文件
  • 设置框架文件
  • 测试文件
  • 模块文件

它们都是通过下面的方式加载的

({"Object.":function(module,exports,require,__dirname,__filename,global,jest){/*Module code inside*/ }});

如果你看一下 node_modules/jest-runtime/build/index.js:495:510

const dirname = (_path || _load_path()).default.dirname(filename);
localModule.children = [];
localModule.parent = mockParentModule;
localModule.paths = this._resolver.getModulePaths(dirname);
localModule.require = this._createRequireImplementation(filename, options);

const transformedFile = this._scriptTransformer.transform(
filename,
{
  collectCoverage: this._coverageOptions.collectCoverage,
  collectCoverageFrom: this._coverageOptions.collectCoverageFrom,
  collectCoverageOnlyFrom: this._coverageOptions.collectCoverageOnlyFrom,
  isInternalModule,
  mapCoverage: this._coverageOptions.mapCoverage },

this._cacheFS[filename]);

this._createRequireImplementation(filename, options); 为每个模块提供一个自定义需求对象。因此,您根本无法在任何地方获得 native require 功能。一旦 jest 启动,从那时起加载的每个模块都将具有 jest 的自定义 require 函数。

当我们加载一个模块时,jest-runtime 中的requireModule 方法被调用。以下是摘录自同一个

  moduleRegistry[modulePath] = localModule;
  if ((_path || _load_path()).default.extname(modulePath) === '.json') {
    localModule.exports = this._environment.global.JSON.parse(
    (0, (_stripBom || _load_stripBom()).default)((_gracefulFs || _load_gracefulFs()).default.readFileSync(modulePath, 'utf8')));

  } else if ((_path || _load_path()).default.extname(modulePath) === '.node') {
    // $FlowFixMe
    localModule.exports = require(modulePath);
  } else {
    this._execModule(localModule, options);
  }

如您所见,如果文件的扩展名是 .node,它会直接加载模块,否则它会调用 _execModule。此函数与我之前发布的执行代码转换的代码相同

const isInternalModule = !!(options && options.isInternalModule);
const filename = localModule.filename;
const lastExecutingModulePath = this._currentlyExecutingModulePath;
this._currentlyExecutingModulePath = filename;
const origCurrExecutingManualMock = this._isCurrentlyExecutingManualMock;
this._isCurrentlyExecutingManualMock = filename;

const dirname = (_path || _load_path()).default.dirname(filename);
localModule.children = [];
localModule.parent = mockParentModule;
localModule.paths = this._resolver.getModulePaths(dirname);
localModule.require = this._createRequireImplementation(filename, options);

现在,当我们想要修改require 函数用于我们的测试时,我们需要_execModule 来直接导出我们的代码。所以代码应该类似于加载 .node 模块

  } else if ((_path || _load_path()).default.extname(modulePath) === '.mjs') {
    // $FlowFixMe
    require = require("@std/esm")(localModule);
    localModule.exports = require(modulePath);
  } else {

但这样做意味着修补代码,我们希望避免这种情况。所以我们要做的是避免直接使用 jest 命令,而是创建我们自己的 jeSTLoad.js 并运行它。加载jest的代码很简单

#!/usr/bin/env node
/**
 * Copyright (c) 2014-present, Facebook, Inc. All rights reserved.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 */

cli = require('jest/bin/jest');

现在我们要在 cli 加载之前修改 _execModule。所以我们添加下面的代码

const jestRuntime = require("jest-runtime");
oldexecModule = jestRuntime.prototype._execModule;

jestRuntime.prototype._execModule = function (localModule, options) {
    if (localModule.id.indexOf(".mjs") > 0) {
        localModule.exports = require("@std/esm")(localModule)(localModule.id);
        return localModule;
    }
    return oldexecModule.apply(this, [localModule, options]);
};

cli = require('jest/bin/jest');

现在是测试时间

//__test__/sum.test.js
sum = require('../sum.mjs').sum;


test('adds 1 + 2 to equal 3', () => {
  expect(sum(1, 2)).toBe(3);
});


test('adds 2 + 3 to equal 5', () => {
  expect(sum(3, 2)).toBe(5);
});

还有一个sum.mjs文件

export function sum (x, y) { return x + y }

现在我们运行测试

Jest Test

解决方案在下面的 repo 中可用

https://github.com/tarunlalwani/jest-overriding-require-function-stackoverflow

您可以通过运行 npm test 克隆和测试解决方案。

关于javascript - 指定在任何 Jest 设置发生之前运行的代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46433678/

相关文章:

javascript - 为什么输入类型=文件的变化没有被识别为 `form.serialzie()`

javascript - Jquery 工具提示不适用于文本/模板

javascript - JavaScript 字符什么时候可以占用 2 个代码单元?代码单元到底是什么?

react-router - component.find ('a).prop(' href')返回undefined而不是href值

reactjs - React 组件上的 Jest 测试 : Unexpected token "<"

javascript - Ajax 成功数据返回完整的 HTML 页面

javascript - 如何使用 jQuery 检查是否给出了相同的输入?

javascript - 在 react-testing-library 中运行单元测试时出现意外标识符

jquery - 如何使用 jest 测试导入 jQuery UI 组件的 React 组件

typescript - React.jsx : type is invalid when testing a React component with an svg with Jest and React Testing Library