在Jest中测试onChange函数

时间:2018-01-10 04:51:01

标签: reactjs enzyme jest

我对Jest和一般测试都比较新。我有一个带有输入元素的组件:

import * as React from "react";

export interface inputProps{
    placeholder: string;
    className: string;
    value: string;
    onSearch: (depID: string) => void;
}

onSearch(event: any){
    event.preventDefault();
    //the actual onclick event is in another Component
    this.props.onSearch(event.target.value.trim());
}

export class InputBox extends React.Component<inputProps, searchState> {
  render() {
        return (
            <input
                onChange={this.onSearch} //need to test this
                className={this.props.className} 
                type="text"
                value={this.props.value}
                placeholder={this.props.placeholder} />
        );
    }
}

我想要一个测试来检查输入元素的onChange是否是一个以输入元素的value属性作为参数的函数。到目前为止我已经走了多远:

//test to see the input element's onchange 
//returns a function that takes its value as a param
it("onChange param is the same value as the input value", () => {
    const mockFn = jest.fn();
    const input = enzyme.shallow(<InputBox 
                                    value="TestVal"
                                    placeholder="" 
                                    className="" 
                                    onSearch={mockFn}/>);


       input.find('input').simulate('change',  { preventDefault() {} });
       expect(mockFn.mock.calls).toBe("TestVal");
    });

我将在这里找到第一个解决方案Simulate a button click in Jest 并且:https://facebook.github.io/jest/docs/en/mock-functions.html

编辑:运行上述操作会引发以下错误:

 TypeError: Cannot read property 'value' of undefined

5 个答案:

答案 0 :(得分:16)

我认为代码片段上的语法应该是:

preventDefault

测试失败,因为同样在事件对象上定义onSearch函数,您还必须定义it('should call onChange prop', () => { const onSearchMock = jest.fn(); const event = { preventDefault() {}, target: { value: 'the-value' } }; const component = enzyme.shallow(<InputBox onSearch={onSearchMock} />); component.find('input').simulate('change', event); expect(onSearchMock).toBeCalledWith('the-value'); }); 函数上使用的其他属性。

onSearch

以前的测试代码需要定义事件形状,因为您使用的是浅层渲染。如果您想要测试enzyme.mount函数上使用的实际输入值,则需要尝试使用it('should call onChange prop with input value', () => { const onSearchMock = jest.fn(); const component = enzyme.mount(<InputBox onSearch={onSearchMock} value="custom value" />); component.find('input').simulate('change'); expect(onSearchMock).toBeCalledWith('custom value'); }); 进行完整渲染:

footer { margin: 0 0 -50px 0;}

答案 1 :(得分:4)

对于使用TypeScript(并从以上答案中借用)的测试,您需要执行类型强制(as React.ChangeEvent<HTMLInputElement>),以确保短绒可以将签名视为兼容:

反应文件

export class InputBox extends React.Component<inputProps, searchState> {
  onSearch(event: React.ChangeEvent<HTMLInputElement>){
    event.preventDefault();
    //the actual onclick event is in another Component
    this.props.onSearch(event.target.value.trim());
  }

  render() {
    return (
      <input
        onChange={this.onSearch} //need to test this
        className={this.props.className} 
        type="text"
        value={this.props.value}
        placeholder={this.props.placeholder} />
      );
  }
}

测试文件

it('should call onChange prop', () => {
  const onSearchMock = jest.fn();
  const event = {
    target: { value: 'the-value' }
  } as React.ChangeEvent<HTMLInputElement>;
  const component = enzyme.shallow(<InputBox onSearch={onSearchMock} />);
  component.find('input').simulate('change', event);
  expect(onSearchMock).toBeCalledWith('the-value');
});

或者

it('should call onChange prop', () => {
  const onSearchMock = jest.fn();
  const event = {
    target: { value: 'the-value' }
  } as React.ChangeEvent<HTMLInputElement>;
  const component = enzyme.mount<InputBox>(<InputBox onSearch={onSearchMock} />);
  const instance = component.instance();
  instance.onSearch(event);
  expect(onSearchMock).toBeCalledWith('the-value');
});

答案 2 :(得分:2)

我找到了解决方案。

因此,我们不得不传递InputBox内的值,而是将其传递到simulate的第二个参数中,如下所示。然后我们只是检查第一次调用mockFn的第一个arg是否相等。此外,我们可以摆脱event.preventDefault();

it("onChange param is the same value as the input element's value property", () => {
    const mockFn = jest.fn();
    const input = enzyme.shallow(<InputBox 
                                    value=""
                                    placeholder="" 
                                    className="" 
                                    onSearch={mockFn}/>);

    input.find('input').simulate('change', {target: {value: 'matched'} });
    expect(mockFn.mock.calls[0][0]).toBe('matched');
});

答案 3 :(得分:0)

这个怎么样?我使用酶模拟变化事件并执行快照测试。 组件

import React, { FunctionComponent, useState } from 'react';

const Index: FunctionComponent = () => {

  const [val, setVal] = useState('');

  const onInputChange = e => {
    e.preventDefault();
    setVal(e.target.value);
  };

  return (
    <input type='text' onChange={onInputChange} value={val} />
  );
};

export default Index;

单元测试

describe('Index with enzyme', () => {
  it('Should set value to state when input is changed', () => {
    const container = shallow(<Index />);
    const input = container.find('input');
    input.simulate('change', { preventDefault: jest.fn, target: { value: "foo" } });
    expect(container).toMatchSnapshot();
  });
});

快照

exports[`Index with enzyme Should set value to state when input is changed 1`] = `
  <input
    onChange={[Function]}
    type="text"
    value="foo"
  />
`;

答案 4 :(得分:0)

我为此挣扎了几个小时。另外,因为我在一页上有多个选择字段。我发现 Textfield 解决方案的工作方式与文档中给出的 Select.test 不同。

在代码中,我用 id 定义了 SelectProps。 (你也可以用data-testid)

我只能通过单击此字段来触发下拉菜单。

<TextField
  select
  variant = "outlined"
  value = { input.value || Number(0) }
  onChange = { value => input.onChange(value) }
  error = { Boolean(meta.touched && meta.error) }
  open = { open }
  SelectProps = {
    {
      id: `${input.name}-select`,
      MenuProps: {
        anchorOrigin: {
          vertical: "bottom",
          horizontal: "left"
        },
        transformOrigin: {
          vertical: "top",
          horizontal: "left"
        },
        getContentAnchorEl: null
      }
    }
  } 
  { ...props} >

  //yourOptions Goes here

 </TextField>

在我的测试中。

const pickUpAddress = document.getElementById("address-select");

UserEvent.click(pickUpAddress);
UserEvent.click(screen.getByTestId("address-select-option-0"));

之后的工作就像一个魅力。希望这会有所帮助。