跳至主要內容
版本:29.7

測試 React Native 應用程式

在 Facebook,我們使用 Jest 來測試 React Native 應用程式。

透過閱讀以下系列文章,深入了解測試一個可運作的 React Native 應用程式範例:第 1 部分:Jest – Snapshot 應運而生第 2 部分:Jest – Redux Snapshots,用於您的動作和簡約器

設定

從 react-native 版本 0.38 開始,執行 react-native init 時會預設包含 Jest 設定。以下設定應會自動新增至您的 package.json 檔案

{
"scripts": {
"test": "jest"
},
"jest": {
"preset": "react-native"
}
}

執行 yarn test 以使用 Jest 執行測試。

提示

如果您正在升級您的 react-native 應用程式,且之前使用過 jest-react-native 預設值,請從您的 package.json 檔案中移除相依性,並將預設值變更為 react-native

快照測試

讓我們為一個小型 Intro 元件建立一個快照測試,其中包含一些檢視和文字元件,以及一些樣式

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

現在,讓我們使用 React 的測試渲染器和 Jest 的快照功能與元件互動,並擷取已渲染的輸出,並建立一個快照檔案

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

當您執行 yarn testjest 時,將會產生類似這樣的輸出檔案

__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",
}
}>
Welcome to React Native!
</Text>
<Text
style={
Object {
"color": "#333333",
"marginBottom": 5,
"textAlign": "center",
}
}>
This is a React Native snapshot test.
</Text>
</View>
`;

下次執行測試時,已渲染的輸出將與先前建立的快照進行比較。快照應與程式碼變更一起提交。當快照測試失敗時,您需要檢查它是有意還是無意的變更。如果變更符合預期,您可以使用 jest -u 呼叫 Jest 來覆寫現有的快照。

此範例的程式碼可在 examples/react-native 中取得。

預設設定

預設設定會設定環境,並基於我們在 Facebook 中發現有用的內容,非常具有主觀性。所有設定選項都可以覆寫,就像在不使用預設設定時可以自訂一樣。

環境

react-native 附帶一個 Jest 預設設定,因此 package.jsonjest.preset 欄位應指向 react-native。預設設定是一個節點環境,模擬 React Native 應用程式的環境。由於它不會載入任何 DOM 或瀏覽器 API,因此大幅縮短了 Jest 的啟動時間。

transformIgnorePatterns 自訂

transformIgnorePatterns 選項可用於指定哪些檔案應由 Babel 轉換。不幸的是,許多 react-native npm 模組在發佈前並未預先編譯其原始碼。

預設情況下,jest-react-native 預設值僅處理專案本身的原始檔和 react-native。如果您有必須轉換的 npm 依賴項,您可以透過將 react-native 以外的模組分組並用 | 算子分隔,自訂此組態選項

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

您可以使用 類似此工具 來測試哪些路徑會相符(因此會從轉換中排除)。

如果路徑與提供的 任何 模式相符,transformIgnorePatterns 會將檔案從轉換中排除。因此,如果您不小心,拆分為多個模式可能會產生意外的結果。在以下範例中,foobar 的排除(也稱為負向先行斷言)會互相抵消

{
"transformIgnorePatterns": ["node_modules/(?!foo/)", "node_modules/(?!bar/)"] // not what you want
}

setupFiles

如果您想為每個測試檔案提供其他組態,可以使用 setupFiles 組態選項 來指定設定指令碼。

moduleNameMapper

moduleNameMapper 可以用來將模組路徑對應到不同的模組。預設情況下,預設值會將所有影像對應到影像 stub 模組,但如果找不到模組,此組態選項可以提供協助

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

提示

使用 jest.mock 模擬原生模組

內建於 react-native 的 Jest 預設值附帶一些預設模擬,這些模擬會套用在 react-native 儲存庫上。不過,有些 react-native 元件或第三方元件仰賴原生程式碼才能呈現。在這種情況下,Jest 的手動模擬系統可以協助模擬底層實作。

例如,如果您的程式碼仰賴名為 react-native-video 的第三方原生影片元件,您可能想使用類似以下的手動模擬來將其 stub 化

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

這會將元件呈現為 <Video {...props} />,並在快照輸出中包含其所有 props。另請參閱 Enzyme 和 React 16 周圍的注意事項

有時您需要提供更複雜的手動模擬。例如,如果您想將原生元件的 prop 類型或靜態欄位轉送至模擬,您可以透過 jest-react-native 的這個輔助程式,從模擬傳回不同的 React 元件

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 清單中。