Tester des Applications React Native
Chez Facebook, nous utilisons Jest pour tester les applications React Native.
Découvrez plus en détail comment tester un exemple d'application React Native fonctionnelle en lisant la série suivante : Partie 1 : Jest - Les snapshots entrent en jeu et Partie 2 : Jest - Les snapshots Redux pour vos actions et vos réducteurs.
Configuration
A partir de la version 0.38 de react-native, l'installation de Jest est inclus lorsque vous exécutez react-native init
. La configuration suivante devrait être automatiquement ajoutée à votre fichier package.json :
{
"scripts": {
"test": "jest"
},
"jest": {
"preset": "react-native"
}
}
Exécutez yarn test
pour exécuter des tests avec Jest.
If you are upgrading your react-native application and previously used the jest-react-native
preset, remove the dependency from your package.json
file and change the preset to react-native
instead.
Test Snapshot
Créons un test snapshot pour un petit composant intro avec quelques vues et composants de texte et quelques styles :
import React, {Component} from 'react';
import {StyleSheet, Text, View} from 'react-native';
class Intro extends Component {
render() {
return (
<View style={styles.container}>
<Text style={styles.welcome}>Bienvenue sur React Native !</Text>
<Text style={styles.instructions}>
C'est un test de snapshot pour React Native.
</Text>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
alignItems: 'center',
backgroundColor: '#F5FCFF',
flex: 1,
justifyContent: 'center',
},
instructions: {
color: '#333333',
marginBottom: 5,
textAlign: 'center',
},
welcome: {
fontSize: 20,
margin: 10,
textAlign: 'center',
},
});
export default Intro;
Utilisons maintenant le moteur de rendu de React and la fonctionnalité de snapshot de Jest pour capturer le rendu du composant dans un fichier:
import React from 'react';
import renderer from 'react-test-renderer';
import Intro from '../Intro';
test('rend correctement', () => {
const tree = renderer.create(<Intro />).toJSON();
expect(tree).toMatchSnapshot();
});
Lorsque vous exécutez yarn test
ou jest
, cela produira un fichier de sortie comme ceci :
exports[`Intro renders correctly 1`] = `
<View
style={
Object {
"alignItems": "center",
"backgroundColor": "#F5FCFF",
"flex": 1,
"justifyContent": "center",
}
}>
<Text
style={
Object {
"fontSize": 20,
"margin": 10,
"textAlign": "center",
}
}>
Bienvenue sur React Native !
</Text>
<Text
style={
Object {
"color": "#333333",
"marginBottom": 5,
"textAlign": "center",
}
}>
C'est un test de snapshot pour React Native.
</Text>
</View>
`;
La prochaine fois que vous exécuterez les tests, la sortie rendue sera comparée au snapshot précédemment créé. Le snapshot doit être committé avec les changements de code. Lorsqu'un test de snapshot échoue, vous devez vérifier s'il s'agit d'un changement intentionnel ou non intentionnel. Si le changement est attendu, vous pouvez appeler Jest avec jest -u
pour écraser le snapshot existant.
The code for this example is available at examples/react-native.
Configuration prédéfinie
Le préréglage définit l'environnement et il est très subjectif et basé sur ce que nous avons trouvé d'utile sur Facebook. Toutes les options de configuration peuvent être écrasées tout comme elles peuvent être personnalisées si aucun préréglage n'est utilisé.
Environnement
react-native
est livré avec un preset de Jest, donc le champ jest.preset
de votre package.json
devrait pointer vers react-native
. Le preset est un environnement node qui imite l'environnement d'une application React Native. Parce qu'il ne charge pas d'API DOM ou de navigateur, cela améliore grandement le temps de démarrage de Jest.
Personnalisation de transformIgnorePatterns
L'option transformIgnorePatterns
peut être utilisée pour spécifier quels fichiers doivent être transformés par Babel. Malheureusement, beaucoup de modules npm react-native
ne compilent pas leur code source avant la publication.
Par défaut, le preset jest-react-native
ne traite que les propres fichiers source du projet et react-native
. Si vous avez des dépendances npm qui doivent être transformées, vous pouvez personnaliser cette option de configuration en incluant des modules autres que react-native
en les regroupant et en les séparant avec l'opérateur |
:
{
"transformIgnorePatterns": [
"node_modules/(?!(react-native|my-project|react-native-button)/)"
]
}
Vous pouvez tester quels chemins correspondent (et donc qui sont exclus de la transformation) avec un outil comme celui-ci.
transformIgnorePatterns
exclura un fichier de transformation si le chemin correspond à un pattern fourni. Le découpage en plusieurs patterns pourrait donc avoir des résultats inattendus si vous ne faites pas attention. Dans l'exemple ci-dessous, l'exclusion (également connue sous le nom d'assertion prévisionnelle négative) pour foo
et bar
s'annulent mutuellement :
{
"transformIgnorePatterns": ["node_modules/(?!foo/)", "node_modules/(?!bar/)"] // pas ce que vous voulez
}
setupFiles
Si vous souhaitez fournir une configuration supplémentaire pour chaque fichier de test, l'option de configuration setupFiles
peut être utilisée pour spécifier des scripts de configuration.
moduleNameMapper
Le module moduleNameMapper
peut être utilisé pour mapper un chemin de module à un autre module. Par défaut, le preset fait correspondre toutes les images à un module de base d'image, mais si un module ne peut être trouvé, cette option de configuration peut aider :
{
"moduleNameMapper": {
"my-module.js": "<rootDir>/path/to/my-module.js"
}
}
Astuces
Simuler des modules natifs en utilisant jest.mock
Le preset Jest intégré dans react-native
est fourni avec quelques simulations par défaut qui sont appliquées sur un dépôt react-native. Cependant, certains composants ou composants tiers reposent sur du code natif pour être rendus. Dans de tels cas, le système de simulation manuelle de Jest peut aider à déchiffrer l'implémentation sous-jacente.
Par exemple, si votre code dépend d'un composant vidéo natif tiers appel é react-native-video
, vous pourriez vouloir le remplacer par une simulation manuelle comme celle-ci :
jest.mock('react-native-video', () => 'Video');
Cela rendra le composant en tant que <Video {...props} />
avec tous ses props dans la sortie de l'instantané. Consultez aussi les avertissements autour d'Enzyme et React 16.
Parfois, vous devez fournir une simulation manuelle plus complexe. Par exemple, si vous souhaitez transférer les types de prop ou les champs statiques d'un composant natif vers une simulation, vous pouvez retourner un composant React différent d'une simulation à travers cette fonction d'aide de jest-react-native :
jest.mock('path/to/MyNativeComponent', () => {
const mockComponent = require('react-native/jest/mockComponent');
return mockComponent('path/to/MyNativeComponent');
});
Ou si vous souhaitez créer votre propre simulation manuelle, vous pouvez faire quelque chose comme ceci :
jest.mock('Text', () => {
const RealComponent = jest.requireActual('Text');
const React = require('react');
class Text extends React.Component {
render() {
return React.createElement('Text', this.props, this.props.children);
}
}
Text.propTypes = RealComponent.propTypes;
return Text;
});
Dans d'autres cas, vous pouvez souhaiter simuler un module natif qui n'est pas un composant React. La même technique peut être appliquée. Nous recommandons d'inspecter le code source du module natif et de journaliser le module lors de l'exécution d'une application react native sur un appareil bien réel, puis de modéliser une simulation manuelle d'après le module réel.
Si vous finissez par simuler les mêmes modules encore et encore, il est recommandé de définir ces simulations dans un fichier séparé et de l'ajouter à la liste de setupFiles
.