2017-09-26 54 views
21

TL; DR:Podaj kod do uruchomienia przed każdym setup żartem dzieje

1) Jak mogę mieć żartem użyć natywną require funkcji załadować wszystkie moduły w moich testów w dowolnym miejscu.

2) Gdzie/w jaki sposób chciałbym zmodyfikować (tj. Wymienić za pomocą programu ładującego esm) https://github.com/standard-things/esm wymaganą funkcję w jednym miejscu, przed uruchomieniem jakichkolwiek testów, aby wszystkie testy używały zmodyfikowanego wymagania.


Chciałbym użyć esm-loader z moimi plikami testowymi Jest. Aby to zrobić, trzeba załatać funkcji wymaga globalnie, zanim jakikolwiek kod testowy działa, coś jak

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

Jak mówię żartem, aby wykonać ten kod, zanim cokolwiek zostanie dotknięta lub wniosek?

Próbowałem wskazać zarówno pozycję tablicy setupTestFrameworkScriptFile, jak i setupFiles w pliku z nią zawartym, ale żaden z nich nie zadziałał (chociaż potwierdziłem, że oba zostały uruchomione).

Alternatywnie, jestem wystrzelenie te testy ze skryptu npm

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

Czy istnieje jakiś magiczny CLI czym mogę tylko załadować moduł a następnie bieg jest?


Edycja - opcje testEnvironment i resolver sprawiają, że zastanawiam się czy to w ogóle nawet przy założeniu Węzeł require funkcji załadować moduły, lub zamiast przy użyciu własnego modułu ładującego. Jeśli tak, zastanawiam się, czy to nawet możliwe.

+0

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

+0

@ Orb - dzięki, ale nie, niestety. Potrzebuję niższego poziomu. U chcesz zamienić program ładujący węzła głównego na ładowany, który obsługuje ES6. Ale biorąc pod uwagę moją edycję, nie jestem nawet pewien, czy Node używa głównego narzędzia do rozpoznawania węzłów, więc to może nie być możliwe. –

+0

Z twojego użycia skryptu npm, [jest-cli] (https://github.com/facebook/jest /blob/77744a24816d0978b6c478987426c36d615864bd/packages/jest-cli/bin/jest.js) powinien być pierwszą rzeczą, która działa. Możesz spróbować edytować ten plik lokalnie, łatając funkcję require za pomocą 'require (" @ std/esm ")', przed 'require ('../ build/cli'). Run();'. Jeśli to zadziała, możesz przynajmniej potwierdzić, że twój pomysł brzmi dobrze. –

Odpowiedz

10

Więc ten był trochę trudny do pracy. Rozwiązanie jest dość proste, ale zajęło mi trochę czasu, aby działało.Problemem jest to, że przy każdym użyciu dowolnego modułu żartem

  • pliki instalatora
  • Konfiguracja Framework Pliki Pliki
  • test
  • Moduł pliki

Wszystkie są ładowane poniżej sposób

({"Obiekt.": Funkcja (moduł, eksport, wymagane, __ nazwa_dokumentu, __ filen ame, global, jest) {/* Kod modułu wewnątrz */ }});

Jeśli spojrzeć na 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); daje każdy moduł wymaga niestandardowego obiektu. Więc ty jako taki nie masz nigdzie wymagać funkcji, wszędzie. Po rozpoczęciu żartu każdy moduł załadowany od tego momentu będzie miał niestandardową funkcję żartu require.

Po załadowaniu modułu wywoływane są metody requireModule z jest-runtime. Poniżej znajduje się fragment z tego samego

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

Jak widać, jeśli rozszerzenie pliku jest .node ładuje moduł bezpośrednio, inny wywołuje _execModule. Funkcja ta jest ten sam kod, który napisałem wcześniej, który robi transformacji kodu

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

Teraz, gdy chcemy zmodyfikować require funkcję dla naszego testu, musimy _execModule bezpośredni eksport naszego kodu. Więc kod powinien być podobny do ładunkowej .node modułów

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

Ale robi to oznaczałoby łatanie kod, który chcemy uniknąć. Zamiast tego używajmy polecenia dowcip bezpośrednio i stwórzmy własny jestload.js i uruchommy to. Kod do załadunku żartem jest prosta

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

Teraz chcemy zmodyfikować _execModule przed CLI obciążeń.Więc dodać poniżej kodu

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

nadszedł czas na 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); 
}); 

i plik sum.mjs

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

Teraz możemy uruchomić test

Jest Test

Rozwiązaniem jest dostępny na poniżej repo

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

można sklonować i przetestować rozwiązania uruchamiając npm test.

0

Próbowałem użyć node -r @std/esm run.js gdzie run.js to po prostu skrypt, który nazywa się żart, ale to nie działa i zawiesza się tutaj: https://github.com/facebook/jest/blob/master/packages/jest-runtime/src/script_transformer.js#L305.

Z tego co rozumiem z tej linii oznacza, że ​​nie jest to możliwe, ponieważ jest ona kompilowana przez moduł przy użyciu natywnego modułu vm. Powyższe linie (290):

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


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

to kod wywoływany podczas określania transformacji w twojej konfiguracji.

Wniosek: do czasu, gdy esm są obsługiwane (i będą one objęte rozszerzeniem .mjs), nie można importować modułów es w wersji bez określenia transformacji przez. Możesz spróbować łatać małpy vm, ale naprawdę odradzam tę opcję.

Określanie żart przekształcić naprawdę nie jest takie trudne, a dla modułów es to naprawdę tak proste, jak przy użyciu babel-jest z prawej babel config:

Poniżej package.json z minimalnymi ustawieniami

{ 
    "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"] 
    } 
}