enzymejs / enzyme

JavaScript Testing utilities for React
https://enzymejs.github.io/enzyme/
MIT License
19.95k stars 2.01k forks source link

Cannot test reset button on form #2480

Closed benwainwright closed 3 years ago

benwainwright commented 3 years ago

I'm trying to write a test to confirm that a reset button in a form correctly results in the form being reset. The code was originally written using the Grommet component framework, but I've reduced it down to a minimal example using basic DOM elements.

import React from "react";
import { mount } from "enzyme";
import { act } from "react-dom/test-utils";

const Component = (props) => {
  const [value, setValue] = React.useState(props.value);
  return (
    <form onReset={() => setValue(props.value)}>
      <input
        type="text"
        value={value}
        onChange={(event) => {
          setValue(event.target.value);
        }}
      />
      <button type="reset">Reset</button>
    </form>
  );
};

test("The form reset", () => {
  const wrapper = mount(<Component value={"foobar"} />);
  wrapper.find("input").simulate("change", { target: { value: "hello" } });
  wrapper.update();
  wrapper.find("button[type='reset']").simulate("click");
  wrapper.update();
  expect(wrapper.find("input").prop("value")).toEqual("foobar");
});

Current behavior

Expected behavior

Your environment

API

Version

The reason there are two different sets of numbers here is because my local project is running on React 17, so I'm using @wojtekmaj/enzyme-adapter-react-17 to work with Enzyme, but I've also replicated the same issue using a CodeSandbox running React 16.8.3 and enzyme-adapter-react-16. Link to the CodeSandbox here

If you look at the CodeSandbox, you can see that the code works. But the Enzyme test doesn't reflect that. Any help appreciated!

library version
enzyme 3.11.0 & 3.9.0
react 17.0.1 & 16.8.3
react-dom 17.0.1 & 16.8.3
react-test-renderer 17.0.1 & 17.0.1
adapter (below)

Adapter

ljharb commented 3 years ago

First, I'd suggest not using simulate - it doesn't actually simulate anything. If you want to invoke the onClick prop, do so - the native "reset" button behavior can't be triggered.

Separately, no form should ever have a reset button, as it's horrifically bad UX - https://www.nngroup.com/articles/reset-and-cancel-buttons/ may be helpful reading.

benwainwright commented 3 years ago

@ljharb Thanks for your reply.

Separately, no form should ever have a reset button, as it's horrifically bad UX - https://www.nngroup.com/articles/reset-and-cancel-buttons/ may be helpful reading.

Fair enough, I'll consider that in my design. But it doesn't help me understand why enzyme won't allow me to test for this. I've made some changes to the above CodeSandbox which show that a similar problem exists for the 'submit' behaviour. (link)

If you look at formsubmit.spec.js, you'll see that when I try to click a submit button (via simulate or invoke), the mock that is passed into the onSubmit handler doesn't record a call, and so the test fails. It seems like in the test, the form event handlers just don't do anything, even though they do on the actual page.

ljharb commented 3 years ago

Because enzyme doesn’t build a real DOM - it’s not really a button, it’s a placeholder for one so you can test it.

You don’t need to test the browser itself; that’s not your code.

If you want to test an onSubmit, invoke it directly and explicitly. If you want a fully automated browser test, you’d need to use webdriver, since it’s impossible to truly simulate user activity via JavaScript.