If you ever tried to test a real form submission with Jest and JSDOM, you have probably seen this error:
title: Error: Not implemented: HTMLFormElement.prototype.submit
The pattern I use in this cases is wrapping the form in the tests with a
FormMock
component:
const onSubmit = jest.fn();
render(<MyComponentWithAForm />, {
wrapper: () => <FormMock onSubmit={onSubmit} />,
});
userEvent.click(scree.getByRole('button'));
expect(onSubmit).toHaveBeenCalledWith({
method: 'post',
action: '/foo-bar',
data: {
foo: 'bar',
},
target: '_blank',
});
And here's the implementation of the FormMock
component:
import React, { FC, FormEventHandler } from 'react';
interface Data {
method: string;
action: string;
target: string;
data: Record<string, unknown>;
}
interface Props {
onSubmit?(data: Data): void;
}
export const FormMock: FC<Props> = ({ onSubmit, children }) => {
const handleFormSubmit: FormEventHandler = (e) => {
if (e.target instanceof HTMLFormElement) {
// Make sure prevented events don't fire the "onSubmit" method
if (!e.defaultPrevented) {
onSubmit?.({
method: e.target.method,
action: e.target.action,
target: e.target.target,
data: Object.fromEntries(new FormData(e.target)),
});
}
e.preventDefault();
}
};
return <div onSubmit={handleFormSubmit}>{children}</div>;
};