2017-09-26 1 views
21

Le tl; dr est:Spécifiez le code à exécuter avant toute installation Jest se

1) Comment puis-je avoir Jest utiliser la fonction native require pour charger tous les modules dans mes tests partout.

2) Où/comment devrais-je modifier (ie remplacer avec le chargeur esm) https://github.com/standard-things/esm la fonction require en un seul endroit, avant que les tests ne soient exécutés, donc tous les tests utiliseront le require modifié.


Je voudrais utiliser le esm-loader avec mes fichiers de test Jest. Pour ce faire, je dois patcher le monde entier fonction exigent, avant que le code de test fonctionne, avec quelque chose comme

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

Comment puis-je dire Jest d'exécuter ce code avant toute autre chose est touché ou demandé?

J'ai essayé de pointer à la fois setupTestFrameworkScriptFile et une entrée de tableau setupFiles dans un fichier avec celui-ci, mais ni travaillé (même si j'ai confirmé que les deux couraient).

Sinon, je tirer de ces tests avec un script NPM

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

Y at-il quelque chose de magique CLI où je peux charger un module puis run jest?


Edit - les testEnvironment et les options resolver me font me demande si cela est toujours, même en utilisant la fonction nœud require réelle pour charger des modules, ou au lieu d'utiliser son propre chargeur de module. Si oui, je me demande si c'est même possible.

+0

['transformer'] (https://facebook.github.io/jest/docs/fr/configuration.html#transform-object-string-string)? –

+0

@OrB - merci, mais non, malheureusement. Ce dont j'ai besoin, c'est d'un niveau inférieur. Vous voulez remplacer le Node racine par un loader avec un loader qui supporte ES6. Mais compte tenu de mon édition, je ne suis même pas certain que Node utilise le résolveur de nœud racine, donc cela peut même pas être possible –

+0

De votre utilisation de script npm, le [jest-cli] (https://github.com/facebook/jest /blob/77744a24816d0978b6c478987426c36d615864bd/packages/jest-cli/bin/jest.js) devrait être la première chose qui fonctionne. Vous pouvez essayer de modifier ce fichier localement, en corrigeant la fonction require avec 'require (" @ std/esm ")', avant 'require ('../ build/cli'). Run();'. Si cela fonctionne, vous pouvez au moins confirmer que votre idée est bonne. –

Répondre

10

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

  • Configuration Fichiers
  • Framework Setup Files
  • test Fichiers
  • fichiers Module

Ils sont tous chargés en dessous de façon

({"Objet.": Fonction (module, exportations, require, __ dirname, __ filen ame, global, jest) {/* Code du module à l'intérieur */ }});

Si vous avez un oeil à 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 tous les modules d'une commande nécessite objet. Donc, en tant que tel, vous n'obtenez pas la fonction natif nécessaire du tout, n'importe où. Une fois que jest a commencé, chaque module chargé à partir de ce moment aura la fonction require personnalisée de jest.

Lorsque nous chargeons un module, les méthodes requireModule du jest-runtime sont appelées. Voici un extrait de la 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 le voir si l'extension du fichier est .node il charge le module directement, sinon il appelle le _execModule. Cette fonction est le même code que je 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 require fonction pour notre test, nous avons besoin _execModule d'exporter notre code directement. Ainsi, le code devrait être similaire au chargement d'un .node modules

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

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

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 courons le test

Jest Test

La solution est disponible sur ci-dessous repo

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

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

0

J'ai essayé d'utiliser node -r @std/esm run.js où run.js est juste un script qui appelle jest, mais cela ne fonctionne pas et plante ici: https://github.com/facebook/jest/blob/master/packages/jest-runtime/src/script_transformer.js#L305. D'après ce que je comprends de cette ligne signifie que ce n'est pas possible parce que jest compile le module en utilisant le module natif vm. Les lignes ci-dessus (290):

if (willTransform) { 
    const transformedSource = this.transformSource(
    filename, 
    content, 
    instrument, 
    !!(options && options.mapCoverage)); 


    wrappedCode = wrap(transformedSource.code); 
    sourceMapPath = transformedSource.sourceMapPath; 
    } else { 

est le code appelé lorsque vous spécifiez dans votre config se transforme en plaisanterie. Conclusion: jusqu'à ce que esm soit pris en charge (et qu'ils soient sous l'extension .mjs), vous ne pouvez pas importer les modules dans sans spécifiant une transformation. Vous pouvez essayer de corriger le singe vm mais je déconseille vraiment cette option.

La spécification d'une plaisanterie de transformation est vraiment pas difficile, et pour les modules es, il est vraiment aussi simple que l'utilisation babel-jest avec la configuration droite babel:

Ci-dessous un package.json avec un minimum de paramètres

{ 
    "dependencies": { 
     "babel-jest": "^21.2.0", 
     "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0", 
     "jest": "^21.2.1" 
    }, 
    "jest": { 
     "testMatch": [ 
      "<rootDir>/src/**/__tests__/**/*.js?(x)", 
      "<rootDir>/src/**/?(*.)(spec|test).js?(x)" 
     ], 
     "transform": { 
      "^.+\\.(js|jsx)$": "<rootDir>/node_modules/babel-jest" 
     }, 
     "testEnvironment": "node", 
     "testURL": "http://localhost", 
     "moduleFileExtensions": [ 
      "js", 
      "json" 
     ] 
    }, 
    "babel": { 
     "plugins": ["babel-plugin-transform-es2015-modules-commonjs"] 
    } 
}