如何测试更改组件状态的函数?

时间:2019-01-23 17:20:00

标签: javascript reactjs ecmascript-6 jestjs enzyme

我有这个组件:

// imports

class FiltersModal extends React.Component {
  state = {
    status: '',
    carrier: '',
  };

  applyFilters = () => {
    const { applyFilters } = this.props;
    const {
      status,
      carrier,
    } = this.state;

    applyFilters({
      status,
      carrier,
    });
  };

  handleChange = field => ev => {
    this.setState({ [field]: ev.target.value });
  };

  render() {
    const { t, isFiltersModalOpened, toggleFiltersModal } = this.props;
    const { shippedDate } = this.state;

    return (
      <Modal
        open={isFiltersModalOpened}
        onRequestClose={toggleFiltersModal}
        onRequestSubmit={this.applyFilters}
      >
        <Form>

          <StatusesSelect handleStatus={this.handleChange('status')} />
          <GetAllCouriers handleCouriers={this.handleChange('carrier')} />

        </Form>
      </Modal>
    );
  }
}

FiltersModal.propTypes = {
  t: PropTypes.func.isRequired,
  isFiltersModalOpened: PropTypes.bool.isRequired,
  toggleFiltersModal: PropTypes.func.isRequired,
  applyFilters: PropTypes.func.isRequired,
};

export default translate()(FiltersModal);

这个测试:

import React from 'react';
import { shallow } from 'enzyme';
import FiltersModal from '../../FiltersModal';

jest.mock('react-i18next', () => ({
  // this mock makes sure any components using the translate HoC receive the t function as a prop
  translate: () => Component => {
    Component.defaultProps = { ...Component.defaultProps, t: key => key }; // eslint-disable-line
    return Component;
  },
}));

describe('FiltersModal component test', () => {
  let props;

  beforeEach(() => {
    props = {
      t: k => k,
      isFiltersModalOpened: false,
      toggleFiltersModal: jest.fn(() => k => k),
      removeFilter: jest.fn(() => k => k),
      applyFilters: jest.fn(() => k => k),
      softlayerAccountId: '232279',
      filters: {
        carrier: 'UPS',
        shipmentId: '1234',
        shipmentType: '',
        shippedDate: '',
        shippedFrom: '',
        shippedTo: '',
        status: '',
      },
    };
  });

  it('should render without errors', () => {
    const wrapper = shallow(<FiltersModal {...props} />);

    expect(wrapper.find('Modal')).toHaveLength(1);
    expect(wrapper.find('Form')).toHaveLength(1);
  });

  it('should change state', () => {
    const wrapper = shallow(<FiltersModal {...props} />);

    wrapper.setState({ carrier: 'UPS' });

    wrapper.instance().applyFilters();
    wrapper.instance().handleChange('status');

    expect(props.applyFilters).toHaveBeenCalledTimes(1);
    expect(wrapper.instance().handleChange).toHaveBeenCalledTimes(1);
  });
});

我需要调用函数handleChange,但出现此错误:

 FAIL  src/client/pages/Shipments/__tests__/components/FiltersModal-test.js
  FiltersModal component test
    ✓ should render without errors (15ms)
    ✕ should change state (12ms)

  ● FiltersModal component test › should change state

    expect(jest.fn())[.not].toHaveBeenCalledTimes()

    jest.fn() value must be a mock function or spy.
    Received:
      function: [Function anonymous]

      51 | 
      52 |     expect(props.applyFilters).toHaveBeenCalledTimes(1);
    > 53 |     expect(wrapper.instance().handleChange).toHaveBeenCalledTimes(1);
         |                                             ^
      54 |   });
      55 | });
      56 | 

我想念什么?

3 个答案:

答案 0 :(得分:2)

handleChange是一个实际函数,而不是模拟或间谍(如错误所示)。

如果您不想模拟该函数,则可以使用a spy来检查它是否已被调用:

const spy = jest.spyOn(wrapper.instance(), "handleChange");

wrapper.instance().handleChange("status");

expect(spy).toHaveBeenCalledTimes(1);

答案 1 :(得分:2)

我相信您不需要。与实际项目一样,您通常也不会从外部与组件的方法通信(ref来调用实例的方法是一个例外)。相反,您依赖于render()的返回结果。

因此,我建议您确保更改后的值通过applyFilters外传:

it('should change state', () => {
  const applyFiltersMock = jest.fn();
  const wrapper = shallow(<FiltersModal {...props} applyFilters={applyFiltersMock} />);
  wrapper.find(StatusesSelect).props().handleStatus({ target: {value: '2'} });
  wrapper.find(GetAllCouriers ).props().handleCouriers({ target: {value: '3'} });

  wrapper.find(Modal).props().onRequestSubmit();
  expect(applyFiltersMock).toHaveBeenCalledTimes(1);
  expect(applyFiltersMock).toHaveBeenCalledWith({status: '2', carrier: '3'});
});

答案 2 :(得分:0)

您可以使用state检查组件的状态。触发handleChange后,检查组件的状态,如果状态更改为所需状态,则应通过测试