Jest: рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рджреЗрд╢реА рдХреЗ рд▓рд┐рдП рдЬреЗрд╕реНрдЯ рдХреЗ рд▓рд┐рдП рд╕рднреА рд╕рд╣рд╛рд░рд╛ рдирд╣реАрдВ рдкрд╣рдЪрд╛рдирддрд╛<touchablehighlight/>

рдХреЛ рдирд┐рд░реНрдорд┐рдд 16 рд╕рд┐рддре░ 2016  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ  ┬╖  рд╕реНрд░реЛрдд: facebook/jest

рдореЗрд░реЗ рдкрд╛рд╕ рдореЗрд░реЗ рдХрд╕реНрдЯрдо рдмрдЯрди рдХреЗ рд▓рд┐рдП рдПрдХ рдХрдХреНрд╖рд╛ рд╣реИ:

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

рдФрд░ рдкрд░реАрдХреНрд╖рдг рдХреЛ рдлрд┐рд░ рд╕реЗ рдЪрд▓рд╛рдПрдВ - рдореБрдЭреЗ рдпрд╣ рджрд┐рдЦрд╛рдиреЗ рдореЗрдВ рдХреЛрдИ рдЕрдВрддрд░ рдирд╣реАрдВ рд╣реИ рдХрд┐ рд╕реНрдиреИрдкрд╢реЙрдЯ рдиреЗ рдЗрд╕ рдЕрддрд┐рд░рд┐рдХреНрдд рдкреНрд░реЛрдк рдХреА рдЙрдореНрдореАрдж рдирд╣реАрдВ рдХреА рдереАред рд╡рд╛рд╕реНрддрд╡ рдореЗрдВ, рдПрдХрдорд╛рддреНрд░ рдкреНрд░реЛрдк рдиреЗ "рд╕реНрдЯрд╛рдЗрд▓" рд╣реЛрдиреЗ рдХреЗ рд▓рд┐рдП рд╕реАрдо рдХрд╛ рдореВрд▓реНрдпрд╛рдВрдХрди рдХрд┐рдпрд╛ред
рдХреНрдпрд╛ рдпрд╣ рдХрд╛рд░реНрдп рдкреНрд░рдЧрддрд┐ рдкрд░ рд╣реИ?
рд╕рд╛рде рд╣реА, рд╕рдВрдмрдВрдзрд┐рдд рдиреЛрдЯ рдкрд░ - рд╕реНрдиреИрдкрд╢реЙрдЯ (рдФрд░ рдбреАрдмрдЧрд░) рдореЗрдВ рдЯрдЪ рдХрд░рдиреЗ рдпреЛрдЧреНрдп рд╣рд╛рдЗрд▓рд╛рдЗрдЯ рдХрд╛ рдкреНрд░рдХрд╛рд░ 'рд╡реНрдпреВ' рдХреЗ рд░реВрдк рдореЗрдВ рдХреНрдпреЛрдВ рджрд┐рдЦ рд░рд╣рд╛ рд╣реИ, рди рдХрд┐ 'рдЯрдЪреЗрдмрд▓ рд╣рд╛рдЗрдЯрд▓рд╛рдЗрдЯ'?

рдореЗрд░реЗ 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"]
}

рд╕рдмрд╕реЗ рдЙрдкрдпреЛрдЧреА рдЯрд┐рдкреНрдкрдгреА

@cpojer рддреНрд╡рд░рд┐рдд рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛ рдХреЗ рд▓рд┐рдП рдзрдиреНрдпрд╡рд╛рдж! рдореЗрд░рд╛ рд╕реНрдиреИрдкрд╢реЙрдЯ рдЕрдм рдмрд╣реБрдд рд╕рд╛рдл рджрд┐рдЦрддрд╛ рд╣реИред
рдЕрддрд┐рд░рд┐рдХреНрдд рдкреНрд░рд╢реНрди - рд╡рд░реНрддрдорд╛рди рдореЗрдВ рдореЗрд░рд╛ рдЖрдЙрдЯрдкреБрдЯ рд╢рд┐рдХрд╛рдпрдд рдХрд░рддрд╛ рд╣реИ рдХрд┐ рдореИрдВ рдПрдХ рд▓рд╛рдЗрди рдХреЛ рдХрд╡рд░ рдирд╣реАрдВ рдХрд░ рд░рд╣рд╛ рд╣реВрдВ рдЬреЛ onPress рдкреНрд░реЛрдк рдХреЛ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд░реВрдк рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рддрд╛ рд╣реИ

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()}} > ? рдореБрдЭреЗ рдЗрд╕ рд╡рд┐рд╖рдп рдкрд░ рдЖрдкрдХреЗ рдЯреНрдпреВрдЯреЛрд░рд┐рдпрд▓ рдореЗрдВ рдХреБрдЫ рднреА рдирд╣реАрдВ рдорд┐рд▓рд╛ред

рдЕрдЧреНрд░рд┐рдо рдореЗрдВ рдзрдиреНрдпрд╡рд╛рдж!

рд╕рднреА 3 рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

рд╣рдо рд╡рд┐рд╢реЗрд╖ рд░реВрдк рд╕реЗ TouchableHighlight рдХрд╛ рдордЬрд╛рдХ рдирд╣реАрдВ рдЙрдбрд╝рд╛рддреЗ рд╣реИрдВред рдЗрд╕реЗ рд╡реНрдпреВ рдХреЗ рд░реВрдк рдореЗрдВ рдкреНрд░рд╕реНрддреБрдд рдХрд┐рдпрд╛ рдЬрд╛рддрд╛ рд╣реИ рдХреНрдпреЛрдВрдХрд┐ рдпрд╣реА рдкреНрд░рддрд┐рдХреНрд░рд┐рдпрд╛-рдореВрд▓ рдЗрд╕реЗ рдкреНрд░рд╕реНрддреБрдд рдХрд░рддрд╛ рд╣реИред

рдРрд╕рд╛ рд▓рдЧрддрд╛ рд╣реИ рдЬреИрд╕реЗ 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 рдкреНрд░реЛрдк рдХреЛ рдПрдХ рдлрд╝рдВрдХреНрд╢рди рдХреЗ рд░реВрдк рдореЗрдВ рдирд┐рд░реНрджрд┐рд╖реНрдЯ рдХрд░рддрд╛ рд╣реИ

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();
};
рдХреНрдпрд╛ рдпрд╣ рдкреГрд╖реНрда рдЙрдкрдпреЛрдЧреА рдерд╛?
0 / 5 - 0 рд░реЗрдЯрд┐рдВрдЧреНрд╕

рд╕рдВрдмрдВрдзрд┐рдд рдореБрджреНрджреЛрдВ

Antho2407 picture Antho2407  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

stephenlautier picture stephenlautier  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

benmccormick picture benmccormick  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

ticky picture ticky  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ

gustavjf picture gustavjf  ┬╖  3рдЯрд┐рдкреНрдкрдгрд┐рдпрд╛рдБ