jaypee
jaypee

Reputation: 2137

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

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.

Upvotes: 40

Views: 55256

Answers (8)

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

Upvotes: 0

Murilo Medeiros
Murilo Medeiros

Reputation: 261

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

Upvotes: 0

Nisharg Shah
Nisharg Shah

Reputation: 19532

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://stackoverflow.com/a/4471635/8798220

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

Upvotes: 2

Ain
Ain

Reputation: 748

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

Upvotes: -1

Peter Cardenas
Peter Cardenas

Reputation: 806

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

Upvotes: 22

Robert Brisita
Robert Brisita

Reputation: 5844

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

Upvotes: 0

Sveta Buben
Sveta Buben

Reputation: 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);

Upvotes: -1

Kevin Gorski
Kevin Gorski

Reputation: 3771

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

Upvotes: 14

Related Questions