Π£ ΠΌΠ΅Π½Ρ Π΅ΡΡΡ ΠΊΠ»Π°ΡΡ Π΄Π»Ρ Π½Π°ΡΡΡΠ°ΠΈΠ²Π°Π΅ΠΌΠΎΠΉ ΠΊΠ½ΠΎΠΏΠΊΠΈ:
import React, { Component } from 'react';
import { StyleSheet, View, TouchableHighlight, Text, Image } from 'react-native';
class NavBarBackButton extends Component {
static propTypes = {
onClick: React.PropTypes.func.isRequired,
buttonText: React.PropTypes.string,
customStyle: React.PropTypes.object
};
render() {
return (
<TouchableHighlight
style={[styles.backButton, this.props.customStyle]}
onPress={() => {this.props.onClick()}} >
<View style={{flexDirection: 'row'}}>
<Image
style={styles.backImage}
source={require('../img/back-128.png')}
/>
<Text style={styles.backButtonText}>
{this.props.buttonText}
</Text>
</View>
</TouchableHighlight>
);
}
}
const styles = StyleSheet.create({
backButton: {
justifyContent: 'center'
},
backButtonText: {
fontSize: 17,
textAlignVertical: 'center',
color: 'black',
},
backImage: {
width: 40,
height: 40
},
});
export default NavBarBackButton;
ΠΈ ΡΠ½ΠΈΠΌΠΎΠΊ ΡΠΎΠ·Π΄Π°Π΅ΡΡΡ Ρ ΠΏΠΎΠΌΠΎΡΡΡ ΡΡΠΎΠ³ΠΎ ΡΠ΅ΡΡΠ°:
import 'react-native';
import React from 'react';
import NavBarBackButton from '../navBarBackButton';
import renderer from 'react-test-renderer';
function doWork() {
console.log('Back button was clicked!');
}
it('renders all UI elements', () => {
const tree = renderer.create(
<NavBarBackButton onClick = {doWork}/>
).toJSON();
expect(tree).toMatchSnapshot();
});
Π½ΠΎ ΠΊΠΎΠ³Π΄Π° Ρ Π΄ΠΎΠ±Π°Π²Π»ΡΡ Π΅ΡΠ΅ ΠΎΠ΄Π½Ρ ΠΎΠΏΠΎΡΡ ΠΊ ΡΠ»Π΅ΠΌΠ΅Π½ΡΡ <TouchableHighlight/>
, Π½Π°ΠΏΡΠΈΠΌΠ΅Ρ:
underlayColor={'blue'}
ΠΈ ΠΏΠΎΠ²ΡΠΎΡΠ½ΠΎ Π·Π°ΠΏΡΡΡΠΈΡΠ΅ ΡΠ΅ΡΡ - Ρ Π½Π΅ ΠΏΠΎΠ»ΡΡΠ°Ρ ΡΠ°Π·Π½ΠΈΡΡ, ΠΏΠΎΠΊΠ°Π·ΡΠ²Π°ΡΡΠ΅ΠΉ, ΡΡΠΎ ΡΠ½ΠΈΠΌΠΎΠΊ Π½Π΅ ΠΎΠΆΠΈΠ΄Π°Π» ΡΡΠΎΠΉ Π΄ΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΡΠ½ΠΎΠΉ ΠΎΠΏΠΎΡΡ. Π€Π°ΠΊΡΠΈΡΠ΅ΡΠΊΠΈ, Π΅Π΄ΠΈΠ½ΡΡΠ²Π΅Π½Π½ΡΠΉ ΡΠ΅ΠΊΠ²ΠΈΠ·ΠΈΡ ΠΎΡΠ΅Π½ΠΈΠ» ΡΠ²Ρ ΠΊΠ°ΠΊ Β«ΡΡΠΈΠ»ΡΒ».
ΠΡΠ° ΡΠ°Π±ΠΎΡΠ° ΠΏΡΠΎΠ΄ΠΎΠ»ΠΆΠ°Π΅ΡΡΡ?
ΠΡΠΎΠΌΠ΅ ΡΠΎΠ³ΠΎ, ΠΏΠΎ ΡΠΎΠΎΡΠ²Π΅ΡΡΡΠ²ΡΡΡΠ΅ΠΌΡ ΠΏΡΠΈΠΌΠ΅ΡΠ°Π½ΠΈΡ - ΠΏΠΎΡΠ΅ΠΌΡ ΡΠΈΠΏ TouchableHighlight ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ°Π΅ΡΡΡ Π² ΠΌΠΎΠΌΠ΅Π½ΡΠ°Π»ΡΠ½ΠΎΠΌ ΡΠ½ΠΈΠΌΠΊΠ΅ (ΠΈ ΠΎΡΠ»Π°Π΄ΡΠΈΠΊΠ΅) ΠΊΠ°ΠΊ Β«ViewΒ», Π° Π½Π΅ Β«TouchableHightlightΒ»?
Π ΠΌΠΎΠ΅ΠΌ package.jason Ρ ΠΌΠ΅Π½Ρ Π΅ΡΡΡ:
{
"name": <my_project_name>,
"version": "0.0.1",
"private": true,
"scripts": {
"start": "node node_modules/react-native/local-cli/cli.js start",
"test": "jest"
},
"jest": {
"preset": "jest-react-native",
"collectCoverage": true,
"verbose": true,
"preprocessorIgnorePatterns": [
"node_modules/(?!react-native|<my_project_name>|react-native-button)"
]
},
"dependencies": {
"lodash": "^4.15.0",
"react": "^15.3.1",
"react-native": "^0.33.0",
},
"devDependencies": {
"babel-jest": "^15.0.0",
"babel-polyfill": "^6.13.0",
"babel-preset-react-native": "^1.9.0",
"jest": "^15.1.1",
"jest-cli": "^15.1.1",
"jest-react-native": "^15.0.0",
"react-addons-test-utils": "^15.2.1",
"react-shallow-testutils": "^2.0.0",
"react-test-renderer": "^15.3.1"
}
}
ΠΈ ΠΌΠΎΠΉ .babelrc Π² ΠΊΠΎΡΠ½Π΅Π²ΠΎΠΌ ΠΊΠ°ΡΠ°Π»ΠΎΠ³Π΅:
{
"presets": ["react-native"]
}
ΠΡ ΡΠΏΠ΅ΡΠΈΠ°Π»ΡΠ½ΠΎ Π½Π΅ ΠΈΠ·Π΄Π΅Π²Π°Π΅ΠΌΡΡ Π½Π°Π΄ TouchableHighlight. ΠΠ½ ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ°Π΅ΡΡΡ ΠΊΠ°ΠΊ View, ΠΏΠΎΡΠΎΠΌΡ ΡΡΠΎ ΡΡΠΎ ΡΠΎ, Π½Π° ΡΡΠΎ Π΅Π³ΠΎ ΠΎΡΡΠΈΡΠΎΠ²ΡΠ²Π°Π΅Ρ react-native.
ΠΠΎΡ ΠΎΠΆΠ΅, ΡΡΠΎ TouchableHighlight ΡΡΡΠ°Π½Π°Π²Π»ΠΈΠ²Π°Π΅Ρ ΡΠ΅ΠΊΠ²ΠΈΠ·ΠΈΡΡ Π½Π΅ΠΏΠΎΡΡΠ΅Π΄ΡΡΠ²Π΅Π½Π½ΠΎ Π½Π° ΡΠ²ΠΎΠΉ ΡΠΎΠ±ΡΡΠ²Π΅Π½Π½ΡΠΉ ΡΠ»Π΅ΠΌΠ΅Π½Ρ ΠΏΠΎΠ΄Π΄Π΅ΡΠΆΠΊΠΈ: https://github.com/facebook/react-native/blob/master/Libraries/Components/Touchable/TouchableHighlight.js#L200, ΠΈ Π²Π°ΠΌ ΠΏΠΎΠ½Π°Π΄ΠΎΠ±ΠΈΡΡΡ ΡΠΏΠ΅ΡΠΈΠ°Π»ΡΠ½ΡΠΉ ΠΌΠ°ΠΊΠ΅Ρ Π΄Π»Ρ ΡΠΎΠ³ΠΎ, ΡΡΠΎΠ±Ρ ΡΠ΄Π΅Π»Π°ΡΡ ΡΠ°ΠΊ, ΡΡΠΎΠ±Ρ Π²Π°ΡΠ° ΠΎΠΏΠΎΡΠ° ΠΎΡΠΎΠ±ΡΠ°ΠΆΠ°Π»Π°ΡΡ Π² Π²ΠΈΠ·ΡΠ°Π»ΠΈΠ·ΠΈΡΠΎΠ²Π°Π½Π½ΠΎΠΌ Π²ΡΠ²ΠΎΠ΄Π΅.
ΠΠ΄Π½Π° Π²Π΅ΡΡ, ΠΊΠΎΡΠΎΡΠ°Ρ ΠΌΠΎΠΆΠ΅Ρ ΡΡΠ°Π±ΠΎΡΠ°ΡΡ, - ΡΡΠΎ ΡΠΎΠ·Π΄Π°ΡΡ ΡΠ²ΠΎΠΉ ΡΠΎΠ±ΡΡΠ²Π΅Π½Π½ΡΠΉ ΠΌΠ°ΠΊΠ΅Ρ, ΠΊΠ°ΠΊ ΠΏΡΠ΅Π΄Π»ΠΎΠΆΠ΅Π½ΠΎ Π²ΠΎ Π²ΡΠΎΡΠΎΠΌ ΠΏΡΠΈΠΌΠ΅ΡΠ΅ Π½Π° Π²Π΅Π±-ΡΠ°ΠΉΡΠ΅: http://facebook.github.io/jest/docs/tutorial-react-native.html#mock -native-modules- ΠΈΡΠΏΠΎΠ»ΡΠ·ΠΎΠ²Π°Π½ΠΈΠ΅-ΡΡΡΠΊΠ°-ΠΈΠ·Π΄Π΅Π²Π°ΡΠ΅Π»ΡΡΡΠ²ΠΎ
jest.mock('TouchableHighlight', () => {
const jestReactNative = require('jest-react-native');
return jestReactNative.mockComponent('TouchableHighlight');
});
@cpojer Π‘ΠΏΠ°ΡΠΈΠ±ΠΎ Π·Π° Π±ΡΡΡΡΡΠΉ ΠΎΡΠ²Π΅Ρ! Π’Π΅ΠΏΠ΅ΡΡ ΠΌΠΎΠΉ ΡΠ½ΠΈΠΌΠΎΠΊ Π²ΡΠ³Π»ΡΠ΄ΠΈΡ Π½Π°ΠΌΠ½ΠΎΠ³ΠΎ ΡΠΈΡΠ΅.
ΠΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΡΠ½ΡΠΉ Π²ΠΎΠΏΡΠΎΡ - Π² Π½Π°ΡΡΠΎΡΡΠ΅Π΅ Π²ΡΠ΅ΠΌΡ ΠΌΠΎΠΉ Π²ΡΠ²ΠΎΠ΄ ΠΆΠ°Π»ΡΠ΅ΡΡΡ Π½Π° ΡΠΎ, ΡΡΠΎ Ρ Π½Π΅ ΠΏΠΎΠΊΡΡΠ²Π°Ρ ΡΡΡΠΎΠΊΡ, ΠΊΠΎΡΠΎΡΠ°Ρ ΡΠΊΠ°Π·ΡΠ²Π°Π΅Ρ onPress
prop ΠΊΠ°ΠΊ ΡΡΠ½ΠΊΡΠΈΡ, ΠΏΠ΅ΡΠ΅Π΄Π°Π½Π½ΡΡ Π²
static propTypes = {
onClick: React.PropTypes.func.isRequired,
...
};
<TouchableHighlight
onPress={() => {this.props.onClick()}} > //no coverage for this line of code in test
...
</TouchableHighlight>
ΠΡΡΡ ΠΈΠ΄Π΅ΠΈ, ΠΊΠ°ΠΊ ΠΈΠΌΠΈΡΠΈΡΠΎΠ²Π°ΡΡ Π½Π°ΠΆΠ°ΡΠΈΠ΅ ΠΊΠ½ΠΎΠΏΠΊΠΈ? ΠΠ»ΠΈ ΡΠ΄Π΅Π»Π°ΡΡ ΡΡΠΎ-Π½ΠΈΠ±ΡΠ΄Ρ, ΡΡΠΎΠ±Ρ ΠΏΠΎΠ»ΡΡΠΈΡΡ ΠΌΠΎΡ ΡΠ΅ΡΡΠΎΠ²ΡΡ ΠΎΠ±Π»ΠΎΠΆΠΊΡ onPress={() => {this.props.onClick()}} >
? Π― Π½Π΅ ΡΠΌΠΎΠ³ Π½Π°ΠΉΡΠΈ Π² Π²Π°ΡΠΈΡ
ΡΡΠΎΠΊΠ°Ρ
Π½ΠΈΡΠ΅Π³ΠΎ ΠΏΠΎ ΡΡΠΎΠΉ ΡΠ΅ΠΌΠ΅.
ΠΠ°ΡΠ°Π½Π΅Π΅ ΡΠΏΠ°ΡΠΈΠ±ΠΎ!
@rosiakr ΠΠ°, Π²Ρ ΠΌΠΎΠΆΠ΅ΡΠ΅ ΠΏΡΠΎΡΠ΅ΡΡΠΈΡΠΎΠ²Π°ΡΡ ΡΠΎΠ±ΡΡΠΈΠ΅ Π½Π°ΠΆΠ°ΡΠΈΡ ΠΊΠ½ΠΎΠΏΠΊΠΈ.
ΠΠΎΡ ΠΊΠΎΠ΄, ΠΊΠΎΡΠΎΡΡΠΉ Ρ Π½Π°ΠΏΠΈΡΠ°Π» Π΄Π»Ρ ΠΏΡΠΎΠ²Π΅ΡΠΊΠΈ Π½Π°ΠΆΠ°ΡΠΈΡ ΠΊΠ½ΠΎΠΏΠΊΠΈ.
class YourComponent extends Component {
handleButtonClick = () => {};
render() {
return <Button transparent onPress={() => this.handleButtonClick()}></Button>
}
}
//jest
it("Test Component", () => {
const component = renderer.create(
<YourComponent/>
);
// manually trigger the button click.
component.getInstance().handleButtonClick();
};
Π‘Π°ΠΌΡΠΉ ΠΏΠΎΠ»Π΅Π·Π½ΡΠΉ ΠΊΠΎΠΌΠΌΠ΅Π½ΡΠ°ΡΠΈΠΉ
@cpojer Π‘ΠΏΠ°ΡΠΈΠ±ΠΎ Π·Π° Π±ΡΡΡΡΡΠΉ ΠΎΡΠ²Π΅Ρ! Π’Π΅ΠΏΠ΅ΡΡ ΠΌΠΎΠΉ ΡΠ½ΠΈΠΌΠΎΠΊ Π²ΡΠ³Π»ΡΠ΄ΠΈΡ Π½Π°ΠΌΠ½ΠΎΠ³ΠΎ ΡΠΈΡΠ΅.
ΠΠΎΠΏΠΎΠ»Π½ΠΈΡΠ΅Π»ΡΠ½ΡΠΉ Π²ΠΎΠΏΡΠΎΡ - Π² Π½Π°ΡΡΠΎΡΡΠ΅Π΅ Π²ΡΠ΅ΠΌΡ ΠΌΠΎΠΉ Π²ΡΠ²ΠΎΠ΄ ΠΆΠ°Π»ΡΠ΅ΡΡΡ Π½Π° ΡΠΎ, ΡΡΠΎ Ρ Π½Π΅ ΠΏΠΎΠΊΡΡΠ²Π°Ρ ΡΡΡΠΎΠΊΡ, ΠΊΠΎΡΠΎΡΠ°Ρ ΡΠΊΠ°Π·ΡΠ²Π°Π΅Ρ
onPress
prop ΠΊΠ°ΠΊ ΡΡΠ½ΠΊΡΠΈΡ, ΠΏΠ΅ΡΠ΅Π΄Π°Π½Π½ΡΡ Π²ΠΡΡΡ ΠΈΠ΄Π΅ΠΈ, ΠΊΠ°ΠΊ ΠΈΠΌΠΈΡΠΈΡΠΎΠ²Π°ΡΡ Π½Π°ΠΆΠ°ΡΠΈΠ΅ ΠΊΠ½ΠΎΠΏΠΊΠΈ? ΠΠ»ΠΈ ΡΠ΄Π΅Π»Π°ΡΡ ΡΡΠΎ-Π½ΠΈΠ±ΡΠ΄Ρ, ΡΡΠΎΠ±Ρ ΠΏΠΎΠ»ΡΡΠΈΡΡ ΠΌΠΎΡ ΡΠ΅ΡΡΠΎΠ²ΡΡ ΠΎΠ±Π»ΠΎΠΆΠΊΡ
onPress={() => {this.props.onClick()}} >
? Π― Π½Π΅ ΡΠΌΠΎΠ³ Π½Π°ΠΉΡΠΈ Π² Π²Π°ΡΠΈΡ ΡΡΠΎΠΊΠ°Ρ Π½ΠΈΡΠ΅Π³ΠΎ ΠΏΠΎ ΡΡΠΎΠΉ ΡΠ΅ΠΌΠ΅.ΠΠ°ΡΠ°Π½Π΅Π΅ ΡΠΏΠ°ΡΠΈΠ±ΠΎ!