目標
既存のReactNativeで開発したアプリに、Jest, Enzymeを導入し、「多面!フラッシュ暗算」というテキストが正しく表示できるかをテストする。
import React from 'react';
import { StyleSheet, Text } from 'react-native';
import {
widthPercentageToDP as wp,
heightPercentageToDP as hp
} from 'react-native-responsive-screen';
const HomeTitle: React.FC = () => {
return <Text style={styles.title}>多面!フラッシュ暗算</Text>;
};
export default HomeTitle;
const styles = StyleSheet.create({
title: {
color: '#fff',
fontSize: wp('7%')
}
});
初期状態は、TypeScriptで開発できる環境は整っているが、Jest, Enzymeはインストールすらされていない。
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject",
"prettier": "npx prettier --write '**/*.{ts,tsx}'"
},
Jestの導入
[参考]
https://reactnative.dev/blog/2018/05/07/using-typescript-with-react-native
公式通りにts-jest
をインストールし、package.json
にJestの設定を書いていく。
$ npm i --save-dev ts-jest
"jest": {
"preset": "react-native",
"moduleFileExtensions": [
"ts",
"tsx",
"js"
],
"transform": {
"^.+\\.(js)$": "<rootDir>/node_modules/babel-jest",
"\\.(ts|tsx)$": "<rootDir>/node_modules/ts-jest/preprocessor.js"
},
"testRegex": "(/__tests__/.*|\\.(test|spec))\\.(ts|tsx|js)$",
"testPathIgnorePatterns": [
"\\.snap$",
"<rootDir>/node_modules/"
],
"cacheDirectory": ".jest/cache"
},
次も公式通りに必要なパッケージをインストールする。
$ npm i --save-dev @types/jest @types/react-test-renderer
ここで試しにjest
コマンドを打ってテストが走るかどうかを確認する。
babel-jest
がないようなので、インストールする。
$ npm i --save-dev babel-jest
jest
コマンドを叩いて、テストが走るかを確認する。
無事に走っているようなので、試しに__tests__
フォルダを作成して、JavaScriptで簡単なテストを試してみる。
it(' 1+2=3 である', () => {
expect(1+2).toBe(3)
})
無事にテストが通ったので、package.json
に設定した"transform"
がうまく機能するか確かめるため、TypeScriptで簡単なテストを試してみる。
export const sum = (x: number, y: number) => x + y
import { sum } from '../sum'
it(' 1+2=3 である', () => {
expect(sum(1, 2)).toBe(3)
})
いろいろと警告が出ているが、テストは通っているので一旦無視しておく。
.jest
フォルダが作られているので、gitに反映させないように.gitignore
に追記する。
# jest
.jest
目的である、HomeTitle
コンポーネントのテストをするため、公式通りに必要なパッケージをインストールし、テストを書いて試してみる。
$ npm i --save-dev react-addons-test-utils
import React from 'react'
import renderer from 'react-test-renderer'
import HomeTitle from '../elements/HomeTitle'
it('renders correctly with defaults', () => {
const title = renderer
.create(<HomeTitle />)
.toJSON()
expect(title).toMatchSnapshot()
})
jest
コマンドを実行していろいろ試すと、下記の3パターンのエラーが起こった。
私の場合は、react-test-renderer
をインストールしていなかった(@types/react-test-renderer
をインストールしていた)、jest.config.js
の設定をしていなかった、ということが問題だった。
[参考]
https://github.com/kulshekhar/ts-jest/issues/937
https://github.com/storybookjs/storybook/issues/1409
エラーを解消するため、下記のインストールと設定を行う。
$ npm i react-test-renderer
module.exports = {
preset: 'react-native',
transform: {
'^.+\\.tsx?$': 'babel-jest',
},
}
再びjest
コマンドを実行すると、テストが通り、__snapshots__
フォルダが作成された。
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`renders correctly with defaults 1`] = `
<Text
style={
Object {
"color": "#fff",
"fontSize": 52.5,
}
}
>
多面!フラッシュ暗算
</Text>
`;
HomeTitle.tsx
の「!」を半角に変えてから再びテストを実行すると、差分が検知された。
Enzymeの導入
せっかくだからEnzymeも導入してみた。
[参考]
https://enzymejs.github.io/enzyme/docs/guides/react-native.html
https://medium.com/@hdsenevi/unit-testing-in-react-native-with-jest-and-enzyme-40cd7dabb6f1
必要なパッケージをインストールしていく。
$ npm i --save-dev enzyme enzyme-adapter-react-16 react-dom
TypeScriptで書いている場合はこちらも必要なようです。
$ npm i --save-dev @types/enzyme @types/enzyme-adapter-react-16 @types/react-dom
同じくHomeTitle
コンポーネントのテストをするため、試しにデバッグを実行してみる。
import React from 'react'
import { configure, shallow } from 'enzyme'
import Adapter from 'enzyme-adapter-react-16';
import HomeTitle from '../elements/HomeTitle'
configure({ adapter: new Adapter() });
it('Should render HomeTitle', () => {
const component = shallow(<HomeTitle />)
console.log(component.debug())
})
うまくEnzymeが導入できていることがわかる。
今回は、<Text>
コンポーネントが正しくレンダリングされているかをテストするため、テスト用にdata-test="homeTitle"
を付加し、テストを実行する。
...
const HomeTitle: React.FC = () => {
return <Text style={styles.title} data-test="homeTitle">多面!フラッシュ暗算</Text>;
};
...
...
it('Should render HomeTitle', () => {
const component = shallow(<HomeTitle />)
const wrapper = component.find(`[data-test='homeTitle']`)
expect(wrapper.length).toBe(1)
})
HomeTitle-enzyme.test.tsx
は通っているが、data-test="homeTitle"
を付加したため、先ほどJestで書いたスナップショットテストが通っていない。
テスト実行時にスナップショットを更新するために、-u
オプションをつけて実行する。
jest -u
無事にテストが通る。
Huskyを導入
せっかくテストを書いたので、git push
時にテストが走るようにしていく。
[参考]
https://github.com/typicode/husky
まずは、npm run test
でJestを実行するscriptをpackage.json
に追記する。
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject",
"prettier": "npx prettier --write '**/*.{ts,tsx}'",
"test": "jest" // 追加
},
npm run test
を実行して確認する。
Huskyをインストールする。
$ npm i --save-dev husky
package.json
にHuskyの設定を追記する。
"husky": {
"hooks": {
"pre-push": "CI=true npm run test"
}
},
まとめ
とりあえず Jest, Enzyme, Husky の導入はできた。
正直、スナップショットテストもEnzymeの仕様も深くは知らないので、これを機に深めていきたい。
Jest, Enzymeは下のyoutubeの動画の教材がとても分かりやすかった。
React Redux Unit & Integration Testing with Jest and Enzyme