Aller au contenu principal
Version: 27.2

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('renders correctly', () => {
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.

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 ships with a Jest preset, so the jest.preset field of your package.json should point to react-native. The preset is a node environment that mimics the environment of a React Native app. Because it doesn't load any DOM or browser APIs, it greatly improves Jest's startup time.

Personnalisation de transformIgnorePatterns#

The transformIgnorePatterns option can be used to specify which files shall be transformed by Babel. Many react-native npm modules unfortunately don't pre-compile their source code before publishing.

By default the jest-react-native preset only processes the project's own source files and react-native. If you have npm dependencies that have to be transformed you can customize this configuration option by including modules other than react-native:

{
"transformIgnorePatterns": [
"node_modules/(?!(react-native|my-project|react-native-button)/)"
]
}

setupFiles#

If you'd like to provide additional configuration for every test file, the setupFiles configuration option can be used to specify setup scripts.

moduleNameMapper#

The moduleNameMapper can be used to map a module path to a different module. By default the preset maps all images to an image stub module but if a module cannot be found this configuration option can help:

{
"moduleNameMapper": {
"my-module.js": "<rootDir>/path/to/my-module.js"
}
}

Astuces#

Simuler des modules natifs en utilisant jest.mock#

The Jest preset built into react-native comes with a few default mocks that are applied on a react-native repository. However, some react-native components or third party components rely on native code to be rendered. In such cases, Jest's manual mocking system can help to mock out the underlying implementation.

For example, if your code depends on a third party native video component called react-native-video you might want to stub it out with a manual mock like this:

jest.mock('react-native-video', () => 'Video');

This will render the component as <Video {...props} /> with all of its props in the snapshot output. See also caveats around Enzyme and React 16.

Sometimes you need to provide a more complex manual mock. For example if you'd like to forward the prop types or static fields of a native component to a mock, you can return a different React component from a mock through this helper from jest-react-native:

jest.mock('path/to/MyNativeComponent', () => {
const mockComponent = require('react-native/jest/mockComponent');
return mockComponent('path/to/MyNativeComponent');
});

Or if you'd like to create your own manual mock, you can do something like this:

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

In other cases you may want to mock a native module that isn't a React component. The same technique can be applied. We recommend inspecting the native module's source code and logging the module when running a react native app on a real device and then modeling a manual mock after the real module.

If you end up mocking the same modules over and over it is recommended to define these mocks in a separate file and add it to the list of setupFiles.