form submitted despite required input
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
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.
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.
I don't see a crash there, just a console logging of an error object.
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.
Same issue with a textbox https://runkit.com/eps1lon/5eff0e98c6645d001a3fabc5
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.
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.
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.
https://mobile.twitter.com/slicknet/status/782274190451671040
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.
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);
});
});
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?
hey! any updates on that?
https://twitter.com/slicknet/status/782274190451671040