web-dev-qa-db-fra.com

Spécifiez le code à exécuter avant toute installation Jest

Le tl; dr est:

1) Comment puis-je demander à Jest d'utiliser la fonction native require pour charger tous les modules de mes tests n'importe où.

2) Où/comment pourrais-je modifier (c'est-à-dire le remplacer par le chargeur esm) https://github.com/standard-things/esm la fonction require en un seul endroit, avant l'exécution des tests, donc tous les tests utiliseront le requis modifié.


Je voudrais utiliser esm-loader avec mes fichiers de test Jest. Pour ce faire, je dois patcher la fonction require globalement, avant l'exécution de tout code de test, avec quelque chose comme

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

Comment dire à Jest d'exécuter ce code avant de toucher ou de demander quoi que ce soit d'autre?

J'ai essayé de pointer à la fois setupTestFrameworkScriptFile et une entrée de tableau setupFiles vers un fichier contenant celui-ci, mais aucun n'a fonctionné (même si j'ai confirmé que les deux s'exécutaient).

Alternativement, je lance ces tests avec un script npm

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

Existe-t-il une magie CLI par laquelle je peux simplement charger un module puis exécuter jest?


Modifier - les options testEnvironment et resolver me font me demander si cela utilise même la fonction Node require pour charger des modules, ou à la place en utilisant son propre module de chargement. Si c'est le cas, je me demande si c'est encore possible.

26
Adam Rackis

Donc celui-ci était un peu difficile à mettre en place. La solution est assez simple mais il m'a fallu un certain temps pour la faire fonctionner. Le problème est que chaque fois que vous utilisez un module en plaisantant

  • Fichiers d'installation
  • Fichiers de cadre de configuration
  • Fichiers de test
  • Fichiers de module

Ils sont tous chargés ci-dessous

({"Object.": Function (module, exports, require, __ dirname, __ filename, global, jest) {/* Code du module à l'intérieur */} });

Si vous regardez 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); donne à chaque module un objet require personnalisé. Donc, en tant que tel, vous n'obtenez pas du tout la fonction native native, n'importe où. Une fois que jest a démarré, chaque module chargé à partir de là aura la fonction require personnalisée de jest.

Lorsque nous chargeons un module, les méthodes requireModule du jest-runtime Sont appelées. Ci-dessous est un extrait du même

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

Comme vous pouvez voir si l'extension du fichier est .node, Il charge directement le module, sinon il appelle le _execModule. Cette fonction est le même code que j'ai posté plus tôt qui fait la transformation de code

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

Maintenant, quand nous voulons modifier la fonction require pour notre test, nous avons besoin de _execModule Pour exporter notre code directement. Le code devrait donc être similaire au chargement d'un module .node

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

Mais cela signifierait patcher le code, ce que nous voulons éviter. Donc, ce que nous faisons à la place, c'est d'éviter d'utiliser directement la commande jest et de créer notre propre jestload.js Et de l'exécuter. Le code pour charger la plaisanterie est 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');

Maintenant, nous voulons modifier le _execModule Avant le chargement du cli. Nous ajoutons donc ci-dessous le 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');

Il est maintenant temps pour un 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);
});

Et un fichier sum.mjs

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

Maintenant, nous exécutons le test

Jest Test

La solution est disponible sur le repo ci-dessous

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

Vous pouvez cloner et tester la solution en exécutant npm test.

16
Tarun Lalwani