Aller au contenu principal
Version : 26.x

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

Remarque : Si vous mettez à jour votre application react-native et que vous utilisiez précédemment le preset jest-react-native, supprimez la dépendance de votre fichier package.json et modifiez le preset en react-native à la place.

Exécutez yarn test pour exécuter des tests avec Jest.

Test Snapshot

Créons un test snapshot pour un petit composant intro avec quelques vues et composants de texte et quelques styles :

Intro.js
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:

__tests__/Intro-test.js
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 :

__tests__/__snapshots__/Intro-test.js.snap
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.

Le code pour cet exemple est disponible dans 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.