首页 > 解决方案 > 使用 Jest Uncovered 行测试 React 组件

问题描述

我正在学习 React 中的 TDD,所以我制作了一个简单的应用程序,其中包含 2 个组件和一些来自 json 的虚拟数据,并且我已经为这些组件编写了测试,但我仍然有一些未覆盖的行而且我没有知道如何测试它们。这是我的代码和我的报道截图: 在此处输入图像描述 App.js

import React from 'react'
import './App.css'
import data from './data/users-data.json'
import User from './components/User/User'

export default class App extends React.Component {
  constructor() {
    super()
    this.state = {users: data}
    this.clickFollowHandler = this.clickFollowHandler.bind(this)
    this.clickStarHandler = this.clickStarHandler.bind(this)
  }

  clickFollowHandler(id) {
    this.setState(prevState => {
        const updatedUsers = prevState.users.map(user => {
            if (user.id === id) {
              user.isFollowed === 'active' ? user.isFollowed = 'idle' : user.isFollowed = 'active'
            }
            return user
        })
        return {
            users: updatedUsers
        }
    })
  }

  clickStarHandler(id) {
    this.setState(prevState => {
        const updatedUsers = prevState.users.map(user => {
            if (user.id === id) {
              user.isStared === 'active' ? user.isStared = 'idle' : user.isStared = 'active'
            }
            return user
        })
        return {
            users: updatedUsers
        }
    })
  }

  render() {
    return (
      <div>
        {this.state.users.map(u => {
          return (
            <User 
              key={u.id}
              id={u.id}
              name={u.name}
              date={u.date}
              readingTime={u.readingTime}
              isStared={u.isStared}
              isFollowed={u.isFollowed}
              image={u.image}
              handleFollowClick={this.clickFollowHandler}
              handleStarClick={this.clickStarHandler}
            />
          )
        })}
      </div>
    )
  }
}

应用程序.test.js

import React from 'react';
import ReactDOM from 'react-dom';
import {shallow, mount} from './enzyme';
import App from './App';

jest.mock('./data/users-data.json')
let {user} = require('./data/users-data.json')

// it('renders without crashing', () => {
//   const div = document.createElement('div');
//   ReactDOM.render(<App />, div);
//   ReactDOM.unmountComponentAtNode(div);
// });

describe('App Component', () => {
  it('calling the clickFollowHandler method from App Component has the expected effect on the state of the first user', () => {
    const AppComponent = shallow(<App />)
    const wrapper = AppComponent.instance()
    wrapper.clickFollowHandler('5d552d0058f193f2795fc814')
    wrapper.clickStarHandler()
    expect(wrapper.state.users[0].isFollowed).toEqual('idle')
  })
})




describe('App Component', () => {
  it('calling the clickStarHandler method from App Component has the expected effect on the state of the second user', () => {
    const AppComponent = shallow(<App />)
    const wrapper = AppComponent.instance()
    wrapper.clickStarHandler('5d552d00b20b141dff10d2a2')
    expect(wrapper.state.users[1].isStared).toEqual('idle')
  })
})

用户.js

import React from 'react'
import classes from './User.module.css'
import myImage from '../../assets/images/avatar.png'
import PropTypes from 'prop-types'


const User = props => {

    return(
      <div className={classes.container} key={props.id}>
        <img className={classes.imageContainer} src={myImage} alt={props.name} />
        <div className={classes.contentContainer}>
          <div className={classes.name}>name: {props.name}</div>
          <button onClick={() => props.handleFollowClick(props.id)}>
            {props.isFollowed === 'active' ? 'Unfollow' : 'Follow'}
          </button>
          <input 
            className={classes.hvrIconPop}
            checked={props.isStared === 'active' ? true : false} 
            onChange={() => props.handleStarClick(props.id)}
            type='checkbox' 
          />
          <div className={classes.date}>date: {props.date}</div>
          <div className={classes.time}>reading time: {props.readingTime}</div>
        </div>
      </div>
    )

}

User.propTypes = {
  handleFollowClick: PropTypes.func.isRequired,
  handleStarClick: PropTypes.func.isRequired,
}

export default User

用户.test.js

import React from 'react';
import renderer from 'react-test-renderer';
import {shallow, mount} from '../../enzyme';

import User from './User';

const users = {
  "id": "5d552d0058f193f2795fc814",
  "isFollowed": "active",
  "isStared": "idle",
  "image": "./assets/images/avata.png",
  "readingTime": 20,
  "name": "Walton Morton",
  "date": "Aug 9"
};

it('renders correctly when there are no users', () => {
  const tree = renderer.create(<User 
    key={''}
    id={''}
    name={''}
    date={''}
    readingTime={''}
    isStared={''}
    isFollowed={''}
    image={''}
    handleFollowClick={() => {}}
    handleStarClick={() => {}} 
  />).toJSON();
  expect(tree).toMatchSnapshot();
});

it('renders correctly when there is one user', () => {

  const tree = renderer.create(<User 
    key={users.id}
    id={users.id}
    name={users.name}
    date={users.date}
    readingTime={users.readingTime}
    isStared={users.isStared}
    isFollowed={users.isFollowed}
    image={users.image}
    handleFollowClick={() => 'test'}
    handleStarClick={() => {}}
  />).toJSON();
  expect(tree).toMatchSnapshot();
});




it('when the follow button is clicked a callback is executed', () => {
  const mockFollowClick = jest.fn();
  const mockStarClick = jest.fn();

  const tree = renderer.create(<User 
    key={users.id}
    id={users.id}
    name={users.name}
    date={users.date}
    readingTime={users.readingTime}
    isStared={users.isStared}
    isFollowed={users.isFollowed}
    image={users.image}
    handleFollowClick={mockFollowClick}
    handleStarClick={mockStarClick}
  />)

  const button = tree.root.findByType('button');
  const input = tree.root.findByType('input');

  button.props.onClick();
  expect(mockFollowClick).toHaveBeenCalled();

  button.props.onClick();
  expect(mockFollowClick).toHaveBeenCalledWith('5d552d0058f193f2795fc814');

  input.props.onChange();
  expect(mockStarClick).toHaveBeenCalled();
})





describe('User Component', () => {
  it('clicking on the button will trigger the click handler', () => {
    const mockFollowHandler = jest.fn();
    const mockStarHandler = jest.fn();
    const wrapper = mount(<User 
      key={users.id}
      id={users.id}
      name={users.name}
      date={users.date}
      readingTime={users.readingTime}
      isStared={users.isStared}
      isFollowed={users.isFollowed}
      image={users.image}
      handleFollowClick={mockFollowHandler} 
      handleStarClick={mockStarHandler} 
    />)
    wrapper.find('button').simulate('click');
    expect(mockFollowHandler).toHaveBeenCalledWith('5d552d0058f193f2795fc814')
  })

  it('changing the star checkbox will trigger an onChange handler', () => {
    const mockFollowHandler = jest.fn();
    const mockStarHandler = jest.fn();
    const wrapper = mount(<User 
      key={users.id}
      id={users.id}
      name={users.name}
      date={users.date}
      readingTime={users.readingTime}
      isStared={users.isStared}
      isFollowed={users.isFollowed}
      image={users.image}
      handleFollowClick={mockFollowHandler} 
      handleStarClick={mockStarHandler} 
    />)
    wrapper.find('input').simulate('change');
    expect(mockStarHandler).toHaveBeenCalledWith('5d552d0058f193f2795fc814');
  })
});

标签: reactjsjestjsenzyme

解决方案


package.json添加到以下行中的脚本部分

"test:coverage": "jest --watch --coverage",

然后从您的终端,根据您使用的内容,使用 yarn 或 npm 触发该脚本。它会提示您转到浏览器中的特定地址,您会发现那里有完整的代码覆盖率,其中未测试的行被涂成红色。


推荐阅读