Тестирование приложений React Native
В Facebook мы используем Jest для тестирования приложений React Native.
Чтобы подробнее узнать о тестировании работающего приложения React Native, ознакомьтесь со следующей серией статей:
Настройка
Начиная с версии react-native 0.38, настройка Jest включена по умолчанию при запуске npx @react-native-community/cli init. Следующая конфигурация должна автоматически добавляться в файл jest.config.js вашего React Native:
module.exports = {
preset: 'react-native',
};
Запустите yarn test, чтобы выполнить тесты с Jest.
Если вы обновляете приложение react-native, в котором ранее использовался пресет jest-react-native или react-native, удалите эту зависимость из файла package.json и вместо этого задайте для пресета значение react-native в jest.config.js.
В последних версиях React Native пресет был вынесен в отдельный пакет — @react-native/jest-preset. Если в вашем jest.config.js по-прежнему указано preset: 'react-native' и Jest не может его найти, установите @react-native/jest-preset и вместо этого задайте для пресета значение @react-native/jest-preset.
Снимочный тест
Создадим снимочный тест для небольшого вводного компонента с несколькими представлениями, текстовыми компонентами и стилями:
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}>Welcome to React Native!</Text>
<Text style={styles.instructions}>
This is a React Native snapshot test.
</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;
Теперь воспользуемся @testing-library/react-native и функцией создания снимков Jest, чтобы отобразить компонент и сохранить результат рендеринга в файл снимка. @testing-library/react-native заменяет устаревший react-test-renderer; вместе с ним необходимо установить test-renderer как одноранговую зависимость:
yarn add --dev @testing-library/react-native test-renderer
import {render, screen} from '@testing-library/react-native';
import React from 'react';
import Intro from '../Intro';
test('renders correctly', async () => {
await render(<Intro />);
expect(screen.toJSON()).toMatchSnapshot();
});
При запуске yarn test или jest будет создан файл с таким содержимым:
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",
}
}>
Welcome to React Native!
</Text>
<Text
style={
Object {
"color": "#333333",
"marginBottom": 5,
"textAlign": "center",
}
}>
This is a React Native snapshot test.
</Text>
</View>
`;
При следующем запуске тестов результат рендеринга будет сравнен с ранее созданным снимком. Снимок следует добавлять в систему контроля версий вместе с изменениями кода. Если снимочный тест завершился с ошибкой, необходимо проверить, является ли изменение ожидаемым. Если изменение ожидаемо, можно запустить Jest с параметром jest -u, чтобы перезаписать существующий снимок.
Код этого примера доступен в разделе examples/react-native.
Настройка пресета
Пресет настраивает среду и содержит множество предустановленных параметров, основанных на том, что мы сочли полезным в Facebook. Все параметры конфигурации можно переопределить — так же, как и настроить их при использовании без пресета.
Среда
react-native включает пресет Jest, поэтому поле preset в вашем jest.config.js должно указывать на react-native (или, в последних версиях React Native, на отдельный пакет @react-native/jest-preset). Пресет использует среду Node, имитирующую среду приложения React Native. Поскольку он не загружает DOM или API браузера, время запуска Jest значительно сокращается.
Настройка transformIgnorePatterns
Параметр transformIgnorePatterns позволяет указать, какие файлы следует преобразовывать с помощью Babel. К сожалению, многие npm-модули react-native не компилируют исходный код перед публикацией.
По умолчанию пресет jest-react-native обрабатывает только собственные исходные файлы проекта и react-native. Если среди ваших зависимостей npm есть те, которые необходимо преобразовывать, вы можете настроить этот параметр, указав модули, отличные от react-native, сгруппировав их и разделив оператором |:
{
"transformIgnorePatterns": ["node_modules/(?!((@)?react-native|my-project)/)"]
}
Проверить, каким путям соответствует шаблон (и, следовательно, какие пути будут исключены из преобразования), можно с помощью этого инструмента.
transformIgnorePatterns исключит файл из преобразования, если его путь соответствует любому из указанных шаблонов. Поэтому разделение на несколько шаблонов может привести к непредвиденным результатам, если не проявить осторожность. В приведенном ниже примере исключения (также известные как утверждения отрицательного опережающего просмотра) для foo и bar взаимно отменяют друг друга:
{
"transformIgnorePatterns": ["node_modules/(?!foo/)", "node_modules/(?!bar/)"] // not what you want
}
setupFiles
Чтобы задать дополнительную конфигурацию для каждого тестового файла, можно использовать параметр конфигурации setupFiles для указания скриптов настройки.
moduleNameMapper
Параметр moduleNameMapper позволяет сопоставить путь к модулю с другим модулем. По умолчанию пресет сопоставляет все изображения с модулем-заглушкой изображения, но этот параметр поможет, если модуль не удается найти:
{
"moduleNameMapper": {
"my-module.js": "<rootDir>/path/to/my-module.js"
}
}
Советы
Имитация нативных модулей с помощью jest.mock
Встроенный в react-native пресет Jest содержит несколько заглушек, применяемых в репозитории react-native. Однако для рендеринга некоторых компонентов react-native и сторонних компонентов требуется нативный код. В таких случаях можно использовать систему ручной имитации Jest, чтобы подменить базовую реализацию.
Например, если ваш код зависит от стороннего нативного видеокомпонента под названием react-native-video, его можно заменить заглушкой вручную, например так:
jest.mock('react-native-video', () => 'Video');
Компонент будет отображен как <Video {...props} /> со всеми его свойствами в снимке. См. также особенности использования Enzyme и React 16.
Иногда требуется создать более сложную ручную заглушку. Например, если вы хотите передать типы свойств или статические поля нативного компонента заглушке, можно вернуть из заглушки другой компонент React с помощью этого вспомогательного средства из jest-react-native:
jest.mock('path/to/MyNativeComponent', () => {
const mockComponent = require('react-native/jest/mockComponent');
return mockComponent('path/to/MyNativeComponent');
});
Чтобы создать собственную ручную заглушку, можно сделать примерно следующее:
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;
});
В других случаях может потребоваться имитировать нативный модуль, который не является компонентом React. Можно применить тот же подход. Рекомендуем изучить исходный код нативного модуля и вывести модуль в журнал при запуске приложения react native на реальном устройстве, а затем создать ручную заглушку на основе настоящего модуля.
Если вы многократно имитируете одни и те же модули, рекомендуется определить эти заглушки в отдельном файле и добавить его в список setupFiles.
© 2022 Facebook, Inc.
Licensed under the MIT License.
https://jestjs.io/docs/tutorial-react-native