指定在任何 Jest 设置发生之前运行的代码 [英] Specify code to run before any Jest setup happens

查看:20
本文介绍了指定在任何 Jest 设置发生之前运行的代码的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

tl;dr 是:

1) 我如何让 Jest 使用原生的 require 函数在任何地方加载我测试中的所有模块.

2) 我将在哪里/如何修改(即替换为 esm 加载器)

解决方案可在以下 repo 中获得

https://github.com/tarunlalwani/jest-overriding-require-函数堆栈溢出

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

The tl;dr is:

1) How can I have Jest use the native require function to load all modules in my tests anywhere.

2) Where / how would I go about modifying (ie replacing with the esm loader) https://github.com/standard-things/esm the require function in one place, before any tests run, so all tests will use the modified require.


I'd like to use the esm-loader with my Jest test files. In order to do so, I need to patch the require function globally, before any test code runs, with something like

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

How do I tell Jest to execute that code before anything else is touched or requested?

I tried pointing both setupTestFrameworkScriptFile and an setupFiles array entry to a file with that in it, but neither worked (though I did confirm that both ran).

Alternatively, I'm firing off these tests with an npm script

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

Is there some CLI magic whereby I can just load a module and then run jest?


Edit - the testEnvironment and resolver options make me wonder if this is ever even using the actual Node require function to load modules, or instead using its own module loader. If so I wonder if this is even possible.

解决方案

So this one was a bit tough to get working. The solution is quite simple but it took me a while to get it working. The problem is that whenever you use any module in jest

  • Setup Files
  • Setup Framework Files
  • Test Files
  • Module files

They are all loaded in below way

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

If you have a look at 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); gives every module a custom require object. So you as such don't get the native require function at all, anywhere. Once jest has started every module loaded from then on will have jest's custom require function.

When we load a module, the requireModule methods from the jest-runtime gets called. Below is an excerpt from the same

  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);
  }

As you can see if the extension of the file is .node it loads the module directly, else it calls the _execModule. This function is the same code that I posted earlier which does the code transformation

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);

Now when we want to modify require function for our test, we need _execModule to export our code directly. So the code should be similar to loading of a .node modules

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

But doing that would mean patching the code, which we want to avoid. So what we do instead is avoid using the jest command directly, and create our own jestload.js and running that. The code for loading jest is simple

#!/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');

Now we want to modify the _execModule before the cli loads. So we add below code

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');

Now time for a test

//__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);
});

And a sum.mjs file

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

Now we run the test

The solution is available on below repo

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

You can clone and test the solution by running npm test.

这篇关于指定在任何 Jest 设置发生之前运行的代码的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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