Pressing enter to submit form in react-testing-library does not work
Asked Answered
D

8

38

Description:

I am trying to test that a form submits when the user presses the "Enter" key. I have a passing test for when pressing the Submit button, but I also want to be sure the form submits with the keyboard (convenience and a11y).

Code:

test("should submit when pressing enter", () => {
  const handleSubmit = jest.fn();
  const { getByLabelText } = render(<App handleSubmit={handleSubmit} />);
  const input = getByLabelText("Name:");

  fireEvent.change(input, { target: { value: "abc" } });
  fireEvent.keyPress(input, { key: "Enter", code: 13, charCode: 13 });

  expect(handleSubmit).toHaveBeenCalled();
});

Here is a CodeSandbox with the minimal amount of code needed.

Dimphia answered 16/12, 2019 at 19:2 Comment(0)
T
20

The following worked for me:

import userEvent from "@testing-library/user-event";
import { render } from "@testing-library/react";

test("should submit when pressing enter", () => {
  const handleSubmit = jest.fn();
  const { getByLabelText } = render(<App handleSubmit={handleSubmit} />);
  const input = getByLabelText("Name:");

  userEvent.type(input, "abc{enter}");

  expect(handleSubmit).toHaveBeenCalled();
});
Tamarah answered 16/4, 2021 at 8:28 Comment(5)
I don't have onsubmit prop on my component. I have onkeydown function . When i press enter key on input onkeydown function calls and from there i am submitting the form. So how can i spyon for onkeydown method. I want to check my function calling or not. Please helpNadda
You can check if the view updates according to what happens after the submit function is executed. For example, if you type enter, the form submits and a div with "Form Submitted" pops up, you can check if an element with that text exists. However, if you really need to check if that function executes, then you can jest.spyOn any utility functions that submit function calls.Tamarah
I tried jest.spyon(component.prototype, 'method'); but i am getting an error like can't spyon premitive value. In my component onkeydown is a function and i am submitting form from there. I want to check onkeydown calling or not using spyon.Nadda
oh sorry I should have clarified. I meant that if your component method calls any utility functions that are imported like lodash, fetch, or your own utility function, you can jest.spyOn that. hope this helpsTamarah
this is the only correct way that does not cause act errorVillalba
O
14

It's a little less clear what the source of the interaction is intended to be, but submit can be called on the input and it appears to fix the test in the sandbox:

fireEvent.submit(input);
Overdress answered 13/1, 2020 at 20:41 Comment(1)
Author states "I am trying to test that a form submits when the user presses the "Enter" key.". Your answer will not simulate that behavior.Cloister
R
2

I followed the above answer but it's not worked for me because I am using keydown listener to check my input.

Please remember, use only e.key not e.keyCode/e.which its deperecated. https://mcmap.net/q/54415/-keycode-vs-which

import React, { useState } from "react";
import userEvent from "@testing-library/user-event";
import { render } from "@testing-library/react";

const Input = () => {
  const [value, setValue] = useState("");

  const handleEnter = (e) => {
    if (e.key === "Enter") {
      const value = e.target.value;
      // API CALLING / LOGIC
    }
  };

  return (
    <input
      placeholder="Search..."
      value={value}
      onChange={(e) => setValue(e.target.value)}
      onKeyDown={handleEnter}
    />
  );
};

it("should submit when pressing enter", async () => {
  const text = "hello";

  render(<Input />);

  const input = screen.getByPlaceholderText("Search...");
  await userEvent.type(input, `${text}[Enter]`);

  expect(input).toHaveValue(text);
  // check about enter logic.
});
Ronnie answered 19/7, 2022 at 18:16 Comment(1)
In the answer you cite, "enter" is lower-case and enclosed in curly braces. Here, you've capitalized it (which probably doesn't matter) and put it in square brackets (which probably does matter).Paleolith
C
0

You can submit by button but the event target will be the button and not the form. To resolve this:

  • submit the form
  • useRef on the form
  • ByTestId on the form

Submitting the form is only accessible if it has an accessible name. In this sense, using role="my-form" (ByRole) or aria-label="form's purpose" (ByLabelText or ByRole("form")).

import "@testing-library/jest-dom/extend-expect";
import { getByRole, fireEvent } from '@testing-library/dom';

test("test form", () => {
  const div = document.createElement("div");

  div.innerHTML = `
  <form role="my-form">
    <label for="first_name">
      First Name:
      <input id="first_name" type="text" />
    </label>
    <button type="submit">Submit</button>
  </form>
  `;

  const handleSubmit = jest.fn();
  div.querySelector('form').onsubmit = handleSubmit;

  fireEvent.submit(getByRole(div, "my-form"));
  expect(handleSubmit).toHaveBeenCalledTimes(1);
});
Cagle answered 13/8, 2020 at 0:28 Comment(1)
Just FYI that my-form is not a valid ARIA role. Please make sure to use valid ARIA roles. In this case simply role="form". More info developer.mozilla.org/en-US/docs/Web/Accessibility/ARIA/RolesMoberg
I
0

I found a way to force it without any changes or new libraries as follow

const btnDeepPropsKey = Object.keys(
  wrapper.getByTestId('input-search')
)?.find(item => item?.includes('__reactProps'))

await waitFor(async () =>
  (wrapper.getByTestId('input-search') as any)?.[
    btnDeepPropsKey
  ]?.onKeyPress({ key: 'Enter' })
)

If you can't reach that prop you can log it as well

console.log(wrapper.getByTestId("input-search"))

Note that some states may have been lost if you try to access any other onKeyPress of those props that was shown in log above

Indemonstrable answered 4/7, 2023 at 12:51 Comment(0)
U
0

This is a similar solution, in my case I needed the form to call a method when they hit enter, I'm using angular 9.1.

it('should call loginFromKey when enter key is pressed', () => {
  fixture.detectChanges();

  const loginFromKeySpy = jest.spyOn(component, 'loginFromKey');

  const formElement: HTMLElement = queryNativeElement('form');
  expect(formElement).toBeTruthy();

  formElement.dispatchEvent(new KeyboardEvent('keydown', { key: 'Enter' }));

  expect(loginFromKeySpy).toBeCalled();
});
Unpen answered 18/10, 2023 at 15:44 Comment(0)
S
-1

To simulate keyboard show/hide I first focus on input and then simulate typing. This way you can fire onSubmitEditing event to simulate submit button pressed on a Keyboard.

import { fireEvent } from '@testing-library/react-native'

const input = getByTestId('input');
fireEvent.focus(input);
fireEvent.changeText(input, 'hello world')
fireEvent.submitEditing(input);
Stancil answered 6/5, 2020 at 14:35 Comment(0)
P
-1

You are not passing the correct options to fireEvent.keyDown event. Try to pass keyCode: 13 along with key: "enter"

The following piece of code works for me

it('Check if added todo show in list with label', () => {
  render(<TodoApp/>)
  const input = screen.getByTestId('add-todo')

  fireEvent.change(input, {target: {value: 'Task with label @health'}});
  fireEvent.keyDown(input, {key: 'enter', keyCode: 13})

  const todoList = screen.getByTestId('todo-list')
  expect(todoList).toHaveTextContent('health')
});
Porthole answered 10/6, 2022 at 20:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.