jsdom: Error: Not implemented: HTMLFormElement.prototype.submit

Error

HTMLInputElement {} HTMLInputElement {}
Error: Not implemented: HTMLFormElement.prototype.submit
    at module.exports (/home/xlmnxp/Documents/Nodejs/DownFrom99/node_modules/jsdom/lib/jsdom/browser/not-implemented.js:9:17)
    at HTMLFormElementImpl.submit (/home/xlmnxp/Documents/Nodejs/DownFrom99/node_modules/jsdom/lib/jsdom/living/nodes/HTMLFormElement-impl.js:68:5)
    at HTMLFormElement.submit (/home/xlmnxp/Documents/Nodejs/DownFrom99/node_modules/jsdom/lib/jsdom/living/generated/HTMLFormElement.js:18:21)
    at /home/xlmnxp/Documents/Nodejs/DownFrom99/app.js:12:10
    at process._tickCallback (internal/process/next_tick.js:109:7) undefined
import { JSDOM } from "jsdom";

JSDOM.fromURL("http://localhost/").then((dom:JSDOM) => {
    let document = dom.window.document;
    let window = dom.window;

    let form = <HTMLFormElement> document.querySelector("form");
    let urlField = <HTMLInputElement> document.querySelector("input[name='formvalue']");
    let submitButton = <HTMLInputElement> document.querySelector("input[type='submit']");

    console.log(submitButton,urlField)
    
    urlField.value = "https://www.youtube.com/watch?v=RWjDLfx8Lww";

    form.submit()
    
})

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 31 (5 by maintainers)

Commits related to this issue

Most upvoted comments

Yes, indeed, form submission is not implemented. This is working as expected.

Ran into this when writing tests using Jest. My workaround:

window.HTMLFormElement.prototype.submit = () => {}

Added this before I mount my component in the test case. At least it keeps my console clean.

Just stumbled upon this when writing my own unit tests and think my solution can help someone in the future.

This happens since by default the form attempts to submit the form and refresh the page.

The error can be avoided by simply mocking the submit handler with event.preventDefault():

it("submits form when button is pressed", () => {
  const handleSubmit = jest.fn().mockImplementation((e) => e.preventDefault()); // gets rid of console error
  render(<Form onSubmit={handleSubmit} />);

  fireEvent.click(screen.getByRole("button")); // if you have multiple buttons on the form, add an aria-label so you can use {name: <aria-label>} here

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

I managed to silence the errors by doing:

describe('submit', () => {
  let emit;

  beforeAll(() => {
    ({ emit } = window._virtualConsole);
  });

  beforeEach(() => {
    window._virtualConsole.emit = jest.fn();
  });

  afterAll(() => {
    window._virtualConsole.emit = emit;
  });

  it('should handle submit ', () => {
    ...
  });
});

My workaround for now is form.dispatchEvent(new Event('submit'));

If you don’t care about the submit you can also disable submitting the form with

<form onsubmit="return false;">

No more error message

This workaround will apply to all the unit tests of your project.

  1. Create a jest.warnings.js file at the root of your project.
// jest.warnings.js
global.originalLogError = global.console.error;

global.console.error = (...args) => {
  /**
   * Avoid jsdom error message after submitting a form
   * https://github.com/jsdom/jsdom/issues/1937
   */
  const errorMessage = "Not implemented: HTMLFormElement.prototype.submit";
  if (args && args[0].includes(errorMessage)) {
    return false;
  }

  global.originalLogError(...args);

  return true;
};
  1. Add this new line on jest.config.js:
// jest.config.js
module.exports = {
  setupFiles: ["./jest.warnings.js"]
};

Possible solution:

// Following code mocks window.console.error
// to ignore the "Not implemented: HTMLFormElement.prototype.submit".
//
// Problem: We use "form.onsubmit" event listener in some tests,
// but HTMLFormElement.prototype.submit is not implemented in JSDOM,
// although the tests are passing and handler fires.
//
// More:
// https://github.com/jsdom/jsdom/issues/1937
// https://github.com/facebook/jest/issues/5223#issuecomment-489422244

let origErrorConsole;

beforeEach(() => {
  origErrorConsole = window.console.error;

  window.console.error = (...args) => {
    const firstArg = args.length > 0 && args[0];

    const shouldBeIgnored =
      firstArg &&
      typeof firstArg === 'string' &&
      firstArg.includes('Not implemented: HTMLFormElement.prototype.submit');

    if (!shouldBeIgnored) {
      origErrorConsole(...args);
    }
  }
})

afterEach(() => {
  window.console.error = origErrorConsole;
})

I managed to silence the errors by doing:

describe('submit', () => {
  let emit;

  beforeAll(() => {
    ({ emit } = window._virtualConsole);
  });

  beforeEach(() => {
    window._virtualConsole.emit = jest.fn();
  });

  afterAll(() => {
    window._virtualConsole.emit = emit;
  });

  it('should handle submit ', () => {
    ...
  });
});

I only needed this part:

beforeEach(() => {
    window._virtualConsole.emit = jest.fn();
  });

I had a component using a form but not using submit on the form and was still seeing this error. I solved it by adding type=“button” to my other buttons within the form.

Is it still possible to implement the handling of the inputs when the form is submitted? event.target[name] are not defined.

I use a FormMock component to wrap my forms in jest. You can read about it here: https://icatalina.me/article/2021-09-24-error:-not-implemented:-htmlformelement.prototype.submit/

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',
});

Possible solution:

// Following code mocks window.console.error
// to ignore the "Not implemented: HTMLFormElement.prototype.submit".
//
// Problem: We use "form.onsubmit" event listener in some tests,
// but HTMLFormElement.prototype.submit is not implemented in JSDOM,
// although the tests are passing and handler fires.
//
// More:
// https://github.com/jsdom/jsdom/issues/1937
// https://github.com/facebook/jest/issues/5223#issuecomment-489422244

let origErrorConsole;

beforeEach(() => {
  origErrorConsole = window.console.error;

  window.console.error = (...args) => {
    const firstArg = args.length > 0 && args[0];

    const shouldBeIgnored =
      firstArg &&
      typeof firstArg === 'string' &&
      firstArg.includes('Not implemented: HTMLFormElement.prototype.submit');

    if (!shouldBeIgnored) {
      origErrorConsole(...args);
    }
  }
})

afterEach(() => {
  window.console.error = origErrorConsole;
})

This solution breaks stacktrace of real error and it’ll be harder to find them.

Before image

After image

Today I was testing a component that programmatically submits a hidden form, and I came across this issue when I tried to verify the submit method was called. My fix is as follows:

const mockSubmit = jest.fn();

jest.spyOn(HTMLFormElement.prototype, "submit").mockImplementation(mockSubmit);

Then I can verify the submit call:

  expect(mockSubmit).toBeCalled();

I was getting this error message in my RTL’s tests. Then I realized I didn’t have put an event.preventDefault() on the submit event handler. After doing it, the message was gone.

If you use a virtual console and listen for "jsdomError"s you should get an exception object with a stack trace.