How to mock e.preventDefault in react component

2019-04-03 06:26发布

问题:

I don't really know how to mock inline function in react component's child

My stack: sinon, chai, enzyme;

Component usage:

<ListItem onClick={() => someFn()} />

Component's render:

render() {
    return (
      <li>
        <a href="#" onClick={e => {
            e.preventDefault();
            this.props.onClick();
          }}
        > whatever </a>
      </li>
    );
  }

Here we have onClick that calls e.preventDefault(). How to tell for <a href>(link) to not call e.preventDefault()? How can I mock that onClick?

Below what I have try in tests:

Shallow copy setup

function setup() {
  const someFn = sinon.stub();

  const component = shallow(
    <ListItem
      onClick={() => {
        someFn();
      }}
    />
  );

  return {
    component: component,
    actions: someFn,
    link: component.find('a'),
    listItem: component.find('li'),
  }
}

And the test

  it('simulates click events', () => {
    const { link, actions } = setup();
    link.simulate('click'); //Click on <a href>
    expect(actions).to.have.property('callCount', 1); //would be good if we'll remove e.preventDefault()
  });

Test's output error:

TypeError: Cannot read property 'preventDefault' of undefined

回答1:

Try this

link.simulate('click', {
  preventDefault: () => {
  }
 });


回答2:

Just to note that this is an issue only when using shallow enzyme renderer. In case of full DOM renderer mount, the event object contains the preventDefault method, therefore you don't have to mock it.



回答3:

 test('simulates click events', () => {
    const e = { stopPropagation: jest.fn() };
    const component = shallow(<ListItem{...props} />);
    const li = component.find('li').at(0).childAt(0)
    li.props().onClick(e)

    expect();
  });


回答4:

I would suggest to create new object based on jest.fn() with

const event = Object.assign(jest.fn(), {preventDefault: () => {}})

then use it:

element.simulate('click', event);


回答5:

For those using Jest and react-testing-librarys fireEvent, you need to provide an initialised event object, otherwise the event can't be dispatched via your element.

One can then assert on e.preventDefault being called by assigning a property to that initialised event:

test('prevents default on click', () => {
  const {getByText} = render(<MyComponent />);
  const button = getByText(/click me/);

  // initialise an event, and assign your own preventDefault
  const clickEvent = new MouseEvent('click');
  Object.assign(clickEvent, {preventDefault: jest.fn()});

  fireEvent(button, clickEvent);

  expect(event.preventDefault).toHaveBeenCalledTimes(1);
});

Similarly for stopPropagation.

Anton Karpenko's answer for Jest was useful.