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 scriptPreprocessor
s? (notez que j'utilise déjà babel-jest
)
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"
]
}
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.
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 .
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.
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
.
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.
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:
.css
@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
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é.
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 .babelrc
test
env pour utiliser le plugin. , ainsi:
{
"env": {
"development": {
...
},
"test": {
"presets": [ ... ],
"plugins": [
["import-noop", {
"extensions": ["scss", "css"]
}]
]
}
}
}
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
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:
Espérons que cela puisse économiser quelques heures à la personne suivante.