Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error: Not implemented: HTMLFormElement.prototype.submit #1937

Closed
xlmnxp opened this issue Aug 10, 2017 · 31 comments
Closed

Error: Not implemented: HTMLFormElement.prototype.submit #1937

xlmnxp opened this issue Aug 10, 2017 · 31 comments

Comments

@xlmnxp
Copy link

xlmnxp commented Aug 10, 2017

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()
    
})
@domenic
Copy link
Member

domenic commented Aug 10, 2017

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

@domenic domenic closed this as completed Aug 10, 2017
@StevenDewey
Copy link

@runbb did you find another solution for this? I am trying to do the same thing.

@StevenDewey
Copy link

@domenic do you have any ideas on how to accomplish this functionality? Perhaps another library?

@xlmnxp
Copy link
Author

xlmnxp commented Mar 14, 2018

@stefanbuck no :(

@islazh
Copy link

islazh commented Mar 21, 2018

@domenic is there a reason why this is unimplemented? Would you be open to a pull request to implement this?

@domenic
Copy link
Member

domenic commented Mar 22, 2018

See https://github.com/jsdom/jsdom#unimplemented-parts-of-the-web-platform. This is about navigation, and thus a huge undertaking. You're welcome to try, but please understand you'd need to be implementing basically all of https://html.spec.whatwg.org/multipage/browsing-the-web.html.

@dudyn5ky1
Copy link

@domenic it would be nice to disable this error message.

@domenic
Copy link
Member

domenic commented May 1, 2018

You can do so; see the readme on jsdomErrors.

@YoruNoHikage
Copy link

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

@RiZKiT
Copy link

RiZKiT commented Dec 18, 2018

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

@ssolders
Copy link

ssolders commented Feb 8, 2019

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.

@janjaap
Copy link

janjaap commented Aug 29, 2019

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 ', () => {
    ...
  });
});

@dlrice
Copy link

dlrice commented Nov 5, 2019

There is a nice workaround here https://kula.blog/posts/test_on_submit_in_react_testing_library/

@raquelhortab
Copy link

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.

Hi! I like your workaround but I am not sure where to do that, you thing you could help maybe? I have the following code: (see I added your "fix" as the first statement in main())

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

JSDOM.fromFile("index.html", null).then(dom => {
    main(dom.window);
});

function main(window){

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

  var oldAlert = window.alert;
  window.alert = function() {
    console.log("Alert fired with arguments: " + arguments);
    oldAlert.apply(window, arguments);
  };

  window.document.getElementsByTagName("button")[0].click();

}

but it is still raising the same Error: Not implemented: HTMLFormElement.prototype.submit

@n10v
Copy link

n10v commented Dec 3, 2019

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

@forelabs
Copy link

forelabs commented Mar 2, 2020

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

<form onsubmit="return false;">

No more error message

@pahan35
Copy link

pahan35 commented Jun 10, 2020

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

@domenic
Copy link
Member

domenic commented Jun 10, 2020

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

@pahan35
Copy link

pahan35 commented Jun 17, 2020

@domenic, could you please show us how to use a virtual console from the test file itself?

Let's suggest that the test file is next

import React from 'react'

import {render} from '@testing-library/react'

import ComponentWithSubmit from './ComponentWithSubmit'

test('Component with form', () => {
  const {getByText} = render(<ComponentWithSubmit />)
  expect(getByText('I am inside form')).toBeInTheDocument()
})

P.S: there is jest as a test runner

@domenic
Copy link
Member

domenic commented Jun 17, 2020

Sorry, you'll need to ask Jest for support on how to use Jest. The jsdom is only able to provide support for jsdom itself, not for any package that uses jsdom as a dependency.

@bl-JonathanRys
Copy link

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.

boton added a commit to boton/liferay-portal that referenced this issue Jan 15, 2021
4lejandrito pushed a commit to 4lejandrito/liferay-portal that referenced this issue Jan 19, 2021
brianchandotcom pushed a commit to brianchandotcom/liferay-portal that referenced this issue Jan 19, 2021
@brunogarcia
Copy link

brunogarcia commented Feb 12, 2021

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"]
};

@fantapop
Copy link

It would be great to add form submission specifically to the list of unimplemented features. I read this list before picking this library and did not associate navigation with form submission. Everything is great besides that!

@exaucae
Copy link

exaucae commented Mar 24, 2021

comibining @BoGeM's lifecycle tips and @brunogarcia file separation works just fine.

// jest.warnings.ts

// see https://github.com/jsdom/jsdom/issues/1937
// @ts-ignore
let origErrorConsole: any;

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

  window.console.error = (...args: any []) => {
    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;
});
// jest.config.ts

const jestConfig = {
  preset: 'ts-jest',
  globals: {
    'ts-jest': {
      tsconfig: '<rootDir>/tsconfig.spec.json',
    },
  },
  setupFilesAfterEnv: ['<rootDir>/test/setupTests.ts', '<rootDir>/test/jest.warnings.ts],
// other configs...
};

export default jestConfig;

@manavm1990
Copy link

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();
  });

@TiagoDiass
Copy link

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.

@lbragile
Copy link

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

@eric-burel
Copy link

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

The warning message could definitely tell user that they might want to prevent the default behaviour or mock it somehow.

@icatalina
Copy link

icatalina commented Sep 24, 2021

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

@pahan35
Copy link

pahan35 commented Sep 30, 2021

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

It works for me too. But it is worth mentioning where you take userEvent.

Actually, it's from a separate package.

import userEvent from '@testing-library/user-event'

mvonballmo pushed a commit to mvonballmo/HFU_21H__JAS_20I_app that referenced this issue Jan 14, 2022
We never want to submit the form this way anyway (ot server-side
processing), so we can just turn it off. The form submission was causing
a Jest DOM error in the console (although no test failures).

See the following link for more information:

jsdom/jsdom#1937 (comment)
@KinIcy
Copy link

KinIcy commented Jan 31, 2024

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();

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests