web-dev-qa-db-fra.com

Comment utiliser la plaisanterie avec webpack?

J'utilise webpack pour développer un composant React. Voici une version simple de celui-ci:

'use strict';

require('./MyComponent.less');

var React = require('react');

var MyComponent = React.createClass({
  render() {
    return (
      <div className="my-component">
        Hello World
      </div>
    );
  }
});

module.exports = MyComponent;

Maintenant, je voudrais tester ce composant en utilisant jest . Voici le bit pertinent de mon package.json:

"scripts": {
  "test": "jest"
},
"jest": {
  "rootDir": ".",
  "testDirectoryName": "tests",
  "scriptPreprocessor": "<rootDir>/node_modules/babel-jest",
  "unmockedModulePathPatterns": [
    "react"
  ]
}

Lors de l'exécution de npm test, j'obtiens le message d'erreur suivant:

SyntaxError: /Users/mishamoroshko/react-component/src/myComponent.js: jeton ILLEGAL

On dirait que webpack doit traiter require('./MyComponent.less') avant que jest puisse exécuter le test.

Je me demande si j'ai besoin d'utiliser quelque chose comme jest-webpack . Si oui, existe-t-il un moyen de spécifier plusieurs scriptPreprocessors? (notez que j'utilise déjà babel-jest)

46
Misha Moroshko

La solution la plus propre que j’ai trouvée pour ignorer un module requis est d’utiliser le config moduleNameMapper (fonctionne sur la dernière version 0.9.2).

La documentation est difficile à suivre. J'espère que ce qui suit aidera.

Ajoutez la clé moduleNameMapper à votre configuration packages.json. La clé d'un élément doit être une expression rationnelle de la chaîne requise. Exemple avec des fichiers '.less':

"moduleNameMapper": { "^.*[.](less|LESS)$": "EmptyModule" },

Ajoutez un fichier EmptyModule.js à votre dossier racine:

/**
 * @providesModule EmptyModule
 */
module.exports = '';

Le commentaire est important car moduleNameMapper utilise EmptyModule comme alias de ce module ( pour en savoir plus sur includesModule ).

Maintenant, chaque référence requise qui correspond à l'expression rationnelle sera remplacée par une chaîne vide.

Si vous utilisez la configuration moduleFileExtensions avec un fichier 'js', veillez également à ajouter le module EmptyModule à votre 'unmockedModulePathPatterns'.

Voici la configuration de plaisanterie avec laquelle je me suis retrouvé:

"jest": {
  "scriptPreprocessor": "<rootDir>/node_modules/babel-jest",
  "moduleFileExtensions": ["js", "json","jsx" ],
  "moduleNameMapper": {
    "^.*[.](jpg|JPG|gif|GIF|png|PNG|less|LESS|css|CSS)$": "EmptyModule"
  },
  "preprocessorIgnorePatterns": [ "/node_modules/" ],
  "unmockedModulePathPatterns": [
    "<rootDir>/node_modules/react",
    "<rootDir>/node_modules/react-dom",
    "<rootDir>/node_modules/react-addons-test-utils",
    "<rootDir>/EmptyModule.js"
  ]
}
21
ZahiC

J'ai fini avec le hack suivant:

// package.json

"jest": {
  "scriptPreprocessor": "<rootDir>/jest-script-preprocessor",
  ...
}


// jest-script-preprocessor.js
var babelJest = require("babel-jest");

module.exports = {
  process: function(src, filename) {
    return babelJest.process(src, filename)
      .replace(/^require.*\.less.*;$/gm, '');
  }
};

Mais je me demande toujours quelle est la bonne solution à ce problème.

19
Misha Moroshko

Je viens de découvrir que c'est encore plus simple avec la configuration moduleNameMapper de Jest.

// package.json

"jest": {
    "moduleNameMapper": {
      "^.+\\.scss$": "<rootDir>/scripts/mocks/style-mock.js"
    }
}

// style-mock.js

module.exports = {};

Plus de détails sur la page de tutoriel de Jest .

9
Tien Do

J'ai récemment publié Jestpack qui pourrait aider. Il construit d’abord vos fichiers de test avec Webpack pour que tous les résolutions/chargeurs/plugins, etc. Il fournit ensuite un chargeur de module personnalisé pour Jest, qui comprend l'exécution du module Webpack.

4
riscarrott

De Jest docs :

// in terminal, add new dependency: identity-obj-proxy
npm install --save-dev identity-obj-proxy

// package.json (for CSS Modules)
{
  "jest": {
    "moduleNameMapper": {
      "\\.(css|less)$": "identity-obj-proxy"
    }
  }
}

L'extrait ci-dessus acheminera tous les fichiers .less vers la nouvelle dépendance identity-obj-proxy, qui renverra une chaîne portant le nom de la classe lors de l'appel, par exemple. 'styleName' pour styles.styleName.

3
tbraun

Je pense qu'une solution moins astucieuse consisterait à envelopper votre préprocesseur de manière conditionnelle à ce que le nom de fichier corresponde à un fichier javascript:

if (filename.match(/\.jsx?$/)) {
    return babelJest.process(src, filename);
} else {
    return '';
}

Cela fonctionne même si vous ne définissez pas explicitement l'extension dans la ligne require et ne nécessite pas de substitution de regex sur la source.

2
Krustal

J'ai rencontré le même problème avec ce type de motif 

import React, { PropTypes, Component } from 'react';
import styles from './ContactPage.css';
import withStyles from '../../decorators/withStyles';

@withStyles(styles)
class ContactPage extends Component {

voir l'exemple à https://github.com/kriasoft/react-starter-kit/blob/9204f2661ebee15dcb0b2feed4ae1d2137a8d213/src/components/ContactPage/ContactPage.js#L4-L7

Pour exécuter Jest I a 2 problèmes:

  • importation de .css
  • appliquer le décorateur @withStyles (TypeError: <...> (0 , _appDecoratorsWithStyles2.default)(...) is not a function)

Le premier a été résolu en moquant .css lui-même dans le préprocesseur de script.

Le second a été résolu en excluant les décorateurs de l'autoblocage à l'aide de unmockedModulePathPatterns

module.exports = {
  process: function (src, filename) {

    ...

    if (filename.match(/\.css$/)) src = '';

    ...

    babel.transform(src, ...
  }
}

exemple basé sur https://github.com/babel/babel-jest/blob/77a24a71ae2291af64f51a237b2a9146fa38b136/index.js

Remarque également: lorsque vous travaillez avec le préprocesseur jest, vous devez nettoyer le cache:

$ rm node_modules/jest-cli/.haste_cache -r
1
x'ES

Nous avons eu un problème similaire avec les fichiers CSS. Comme vous l'avez dit précédemment, jest-webpack résoud ce problème très bien. Vous n'aurez pas à vous moquer ni à utiliser les mappeurs de modules. Pour nous, nous avons remplacé notre commande de test npm de jest à jest-webpack et cela a fonctionné.

0
Joseph Fehrman

Si vous utilisez babel, vous pouvez supprimer les importations non souhaitées pendant la transformation babel en utilisant quelque chose comme https://github.com/Shyp/babel-plugin-import-noop et en configurant votre .babelrctest env pour utiliser le plugin. , ainsi:

{
  "env": {
    "development": {
      ...
    },
    "test": {
      "presets": [ ... ],
      "plugins": [
        ["import-noop", {
          "extensions": ["scss", "css"]
        }]
      ]
    }
  }
}
0
Tarrence

Webpack est un excellent outil, mais je n'ai pas besoin de tester son comportement avec mes tests unitaires Jest, et ajouter une version Webpack avant d'exécuter des tests unitaires ne fera que ralentir le processus. La réponse du manuel consiste à simuler des dépendances non liées au code à l'aide de l'option "moduleNameMapper"

https://facebook.github.io/jest/docs/webpack.html#handling-static-assets

0
Samjones

En m'inspirant de la réponse de Misha, j'ai créé un package NPM qui résout ce problème tout en gérant quelques scénarios supplémentaires:

webpack-babel-jest

Espérons que cela puisse économiser quelques heures à la personne suivante.

0
Carlos Atencio