jsdom icon indicating copy to clipboard operation
jsdom copied to clipboard

form submitted despite required input

Open eps1lon opened this issue 6 years ago • 10 comments

Basic info:

  • Node.js version: 10.16.0
  • jsdom version: 16.2.1

Minimal reproduction case

https://runkit.com/eps1lon/5e6969234944ab001d7f7d5e

const { JSDOM } = require('jsdom');

const {window} = new JSDOM(`
<form>
    <input name="test" type="radio" value="1" required />
    <input name="test" type="radio" value="2" required />
    <button type="submit">Submit</button>
</form>
`);
const document = window.document;

const form = document.querySelector("form");
form.addEventListener("submit", event => {
  // without preventDefault it crashes
  event.preventDefault();
  console.log("submit");
});

const submit = document.querySelector("button");
submit.addEventListener("click", () => console.log("click"));
submit.dispatchEvent(new window.MouseEvent("click"));

Logs:

click
submit

Same issue for required textbox: https://runkit.com/eps1lon/5eff0e98c6645d001a3fabc5

How does similar code behave in browsers?

In Chrome 80 https://codesandbox.io/s/browser-submit-required-9w3z2

logs:

click

Same repro for a textbox: https://codesandbox.io/s/browser-submit-required-textfield-xv2fw

Context

Reported in https://github.com/testing-library/react-testing-library/issues/607 and https://github.com/testing-library/react-testing-library/issues/729

eps1lon avatar Mar 11 '20 22:03 eps1lon

Nice find. A fix would be most welcome.

// without preventDefault it crashes

Are you sure? It should just output a console message saying that form submission is not implemented. If it crashes, that's a separate bug worth filing.

domenic avatar Mar 14 '20 17:03 domenic

Are you sure? It should just output a console message saying that form submission is not implemented.

Forgot to link the runkit. In that one (https://runkit.com/eps1lon/5e6969234944ab001d7f7d5e) it's crashing without preventDefault.

eps1lon avatar Mar 14 '20 21:03 eps1lon

I don't see a crash there, just a console logging of an error object.

domenic avatar Mar 14 '20 21:03 domenic

I don't see a crash there, just a console logging of an error object.

Yeah I didn't investigate further. I don't know how I would distinguish this in runkit anyway. I'd have to try locally I think.

eps1lon avatar Mar 14 '20 22:03 eps1lon

Same issue with a textbox https://runkit.com/eps1lon/5eff0e98c6645d001a3fabc5

eps1lon avatar Jul 03 '20 11:07 eps1lon

I also hit this issue that the form is submitted although it’s actually invalid. (Actually doing something as described in https://github.com/testing-library/react-testing-library/issues/729)

Has anyone come up with a workaround? I would appreciate any hint.

bwaldvogel avatar Nov 26 '20 21:11 bwaldvogel

Has any progress been made on this? I'm experiencing the issue with an invalid url in a type="url" input element. I enter an invalid url however the form still submits.

jthannah avatar Jul 26 '21 03:07 jthannah

Ping! Just spent half a day struggling before we realized this was an RTL issue, not ours. I'd love to hear if there has been any work done on this issue. Thankfully we can cover ourselves with a Cypress test pretty easily, but that's not ideal.

griffico avatar Jan 06 '22 19:01 griffico

https://mobile.twitter.com/slicknet/status/782274190451671040

domenic avatar Jan 06 '22 20:01 domenic

It's possibly related, we are experiencing a similar issue. It's an email type input field and the test fails when we want to assert that the invalid error shows up. The Formik validator function doesn't run, only if I remove the type=email attribute from the input field. Everything works correctly if I test it in the browser manually.

Sorry, I can't provide an example at the moment.

I've updated JSDOM to 20.0.0 but unfortunately this did not solve the issue.

tiborsaas-tw avatar Jun 23 '22 16:06 tiborsaas-tw

I'm using Jest and React, and the workaround I did is to fire the invalid events ourselves.

Example:

import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { act } from 'react-dom/test-utils';

describe('Invalid event on form submit', () => {
  test('that the form triggers an invalid event if input elements are invalid', async () => {
    // Problem:
    //   <form> is submitted even if inputs are invalid hence the
    //   act below triggers the needed invalid events for this test
    // GitHub issue: jsdom/jsdom#2898
    const handleInvalid = jest.fn();
    const user = userEvent.setup();
    render(
      <form onSubmit={(e) => e.preventDefault()}>
        <label htmlFor="input">Input:</label>
        {/* Notice that the input here is required*/}
        <input id="input" type="text" onInvalid={handleInvalid} required />
        <button>Submit</button>
      </form>
    );

    // submitting the form will STILL submit and
    // won't call that it's invalid (since the input
    // is empty and it is required)
    await user.click(screen.getByRole('button'));

    expect(() => {
      expect(handleInvalid).toHaveBeenCalledTimes(1);
    }).toThrow(/expected number of calls/i);

    // the workaround is to fire the invalid event
    // ourselves, it is OPTIONAL to click the submit button
    // but be aware that it'll fire submit events
    // (Note: In an actual browser, if a form is invalid,
    //   because one of its input elements is invalid,
    //   it won't fire submit events)
    await user.click(screen.getByRole('button'));
    act(() => {
      screen.getByLabelText(/input/i).dispatchEvent(
        new InputEvent('invalid', {
          bubbles: true,
          cancelable: true,
        })
      );
    });

    expect(handleInvalid).toHaveBeenCalledTimes(1);
  });
});

Zekumoru avatar Feb 11 '23 21:02 Zekumoru

Any news for this issue that's been opened for 3 years? I'm trying to test right now a form with fields that do not have the correct data (they do not match the pattern specified) and the form is triggering the onSubmit anyway. If I query the form and check for its validity (just to confirm everything is as expected), it is invalid:

expect(screen.getByTestId('supplier-register-form')).toBeValid();
-------
Received element is not currently valid:
      <form data-testid="supplier-register-form" />

So if the form is not valid, the onSubmit should not be executed, but it is executing and it's making the test fail.

Any workaround or fix available for this?

albertnev avatar May 10 '23 06:05 albertnev

hey! any updates on that?

AndrewEastwood avatar Nov 18 '23 19:11 AndrewEastwood

https://twitter.com/slicknet/status/782274190451671040

domenic avatar Nov 18 '23 23:11 domenic