Skip to content

fireEvent.keyPress is not working (ignored or not being triggered) #405

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

Closed
maufarinelli opened this issue Nov 26, 2019 · 17 comments
Closed

Comments

@maufarinelli
Copy link

  • DOM Testing Library version: "@testing-library/dom": "^6.10.1" and "@testing-library/react": "^9.3.2",`
  • node version: v12.13.1`
  • npm (or yarn) version: yarn 1.19.1`

Relevant code or config:

const { container } = render(<ModelsForm />);
const input = (container as HTMLDivElement).querySelector('input');

fireEvent.change(input, { target: { value: 'test' } });
fireEvent.keyPress(input, { key: 'Enter', code: 13 });

What you did:

I am trying to test a small component which contains an input type="text"

If I fireEvent.change(input, { target: { value: 'test' } }); I can expect its value and it is changed to test as expected

But if I fireEvent.keyPress(input, { key: 'Enter', code: 13 });, my mocked function is never called

What happened:

fireEvent.keyPress(input, { key: 'Enter', code: 13 }); mocked function is never called. Looks like it ignores the event

Reproduction:

https://codesandbox.io/s/react-testing-library-demo-2l41s

Problem description:

fireEvent keyPress is not working

@kentcdodds
Copy link
Member

This one's got me stumped. I don't have time to look at it right now, but if anyone wants to do a little digging that would be appreciated!

@maufarinelli
Copy link
Author

maufarinelli commented Nov 27, 2019

I dig into the code and now I know at least the reason.

keyPress as any other event is created at:
@testing-library/dom/dist/events.js line 632

createEvent[key] = (node, init) => {
    if (!node) {
      throw new Error(`Unable to fire a "${key}" event - please provide a DOM element.`);
    }

    const eventInit = (0, _extends2.default)({}, defaultInit, {}, init);
    const {
      target: {
        value,
        files
      } = {}
    } = eventInit,
          targetProperties = (0, _objectWithoutPropertiesLoose2.default)(eventInit.target, ["value", "files"]);

And they are expecting to have a { target: { value } }

As I fire the event without it in the params
fireEvent.keyPress(input, { key: "Enter", code: 13 });
value is undefined

Now, I think the solution might be just get the target from the HTMLElement. And if we pass the { target: { value } } in the params, we override it. What do you think?
I am just wondering... not sure if it could be the right approach.

@kentcdodds
Copy link
Member

Thanks for investigating. I'm not sure I understand though. Could you clarify your suggestion?

@maufarinelli
Copy link
Author

maufarinelli commented Nov 28, 2019

Sure @kentcdodds . What I meant is that, when we use fireEvent, we pass the HTMLElement to it.
e.g.: fireEvent.keyPress(input, { key: "Enter", code: 13 });
So, that is actually the target of our event. We could get the value from it, when it has.

I will see if I have some time today to try it. I let you know. Maybe I could contribute with your project :)

@kentcdodds
Copy link
Member

I'm still very confused. If you could make either a codesandbox with your suggested workaround or a pull request work your suggested fix that would probably help.

@NateRadebaugh
Copy link

NateRadebaugh commented Dec 20, 2019

I was also confused by how @maufarinelli was wording this, so here's my attempt at rewording what he's suggested. Hope it helps:

I've dug into the code and I have a guess for why this isn't working like had expected:

keyPress is treated like all the other event types, and is created at:
@testing-library/dom/dist/events.js line 632

createEvent[key] = (node, init) => {
    if (!node) {
      throw new Error(`Unable to fire a "${key}" event - please provide a DOM element.`);
    }

    const eventInit = (0, _extends2.default)({}, defaultInit, {}, init);
    const {
      target: {
        value,
        files
      } = {}
    } = eventInit,
          targetProperties = (0, _objectWithoutPropertiesLoose2.default)(eventInit.target, ["value", "files"]);

All the events in the system look like they expect to have a { target: { value } }

However, I am firing the event without a target in my parameters. Here's what I'm using:

fireEvent.keyPress(input, { key: "Enter", code: 13 });

So since I'm not passing in any target, value is undefined in the event.js code.

Now, I think the solution might be for event.js to (instead of requiring target be passed in) have event.js look up the target from the passed in HTMLElement by default (and allowing the caller to override the target by passing the { target: { value } } in the params if needed).

What do you think? I am just wondering... not sure if it could be the right approach.

@kentcdodds
Copy link
Member

Thanks for the help @NateRadebaugh,

I'm not sure that will solve the issue. Did you try that locally to verify it works? If so, feel free to open a pull request on it. Thanks!

@eps1lon
Copy link
Member

eps1lon commented Mar 21, 2020

fireEvent.keyPress(input, { key: 'Enter', code: 13 }); mocked function is never called.

@maufarinelli What mocked function?

Assuming you expect change to be fired then it is expected that a lone keydown event will not trigger a change event. Chrome does not fire a change event if you fire a key event at a textbox. I'm pretty sure this is how any browser behaves.

Also:

  • keep in mind that keydown is the recommended web standard in favor of the deprecate keypress.
  • keydown is dispatched before input so the value changes most often between keydown and input

@hexpunk
Copy link

hexpunk commented May 19, 2021

I'm also experiencing this. Here's an even simpler example: https://codesandbox.io/s/react-testing-library-demo-forked-xn4f8

For posterity since I didn't make an account on codesandbox:

Input.js

import React, { useState } from "react";

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

  return (
    <>
      <label htmlFor="text-input">Text input:</label>
      <input
        id="text-input"
        placeholder="Type in here..."
        value={value}
        onChange={(e) => setValue(e.target.value)}
        onKeyPress={(e) => {
          if (e.key === "Enter") {
            e.preventDefault();
            onSubmit();
          }
        }}
        type="text"
      />
    </>
  );
};

export default Input;

Input.test.js

import React from "react";
import { render, fireEvent } from "@testing-library/react";
import Input from "../Input";

describe("<Input>", () => {
  test("submits on enter key", () => {
    const handleSubmit = jest.fn();
    const { getByLabelText } = render(<Input onSubmit={handleSubmit} />);

    const input = getByLabelText("Text input:");
    console.log(input);

    fireEvent.keyPress(input, { key: "Enter", code: 13 });

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

Fails with:

expect(jest.fn()).toHaveBeenCalled()

Expected number of calls: >= 1
Received number of calls:    0

EDIT: Saved to a repo for posterity, just in case: https://github.com/JayAndCatchFire/dom-testing-library-fireevent-keypress

@Aidenbuis
Copy link

The fix is to set the charCode in the options:
testing-library/react-testing-library#269 (comment)

@arausly
Copy link

arausly commented Jul 31, 2021

I tried replacing fireEvent.keyPress(input, { key: 'Enter', code: 13 }) with suggestion from https://github.com/testing-library/react-testing-library/issues/269#issuecomment-455854112
fireEvent.keyDown(input, { key: "Enter", keyCode: 13 })

@eps1lon
Copy link
Member

eps1lon commented Aug 25, 2021

I'm also experiencing this. Here's an even simpler example: codesandbox.io/s/react-testing-library-demo-forked-xn4f8

Enter triggering a submit event is something the user agent e.g. a browser does. It's not a web standard and it may not even work in an actual browsers. Note that dispatching events always dispatches synthetic, untrusted events. They are treated differently.

There's nothing actionable for us to do. If you want to test this behavior I recommend you use a end-to-end testing setup with e.g. https://playwright.dev/.

@eps1lon eps1lon closed this as completed Aug 25, 2021
jgsneves added a commit to jgsneves/testing-library-docs that referenced this issue Sep 19, 2021
Since we need ```charCode: 13``` to call ```fireEvent.keyDown()``` using 'Enter' key and a lot of users need to test when 'Enter' key got pressed, I'm proposing this change on this library docs to help more people on this.

reference: testing-library/dom-testing-library#405
@ak-spotter
Copy link

I am still facing the same issue, none of the solutions worked.

@MatanBobi
Copy link
Member

@ak-spotter - In order for us to help, please open a new issue and provide a CodeSandbox (https://react.new/), or a link to a repository on GitHub.
Here are some tips for providing a minimal example: https://stackoverflow.com/help/mcve

@ak-spotter
Copy link

ak-spotter commented Sep 11, 2023

@MatanBobi Here's my code-

App.tsx-

function App() {
  return (
    <div className="App">
      <input type="checkbox" data-testid="testing-it" />
    </div>
  );
}
export default App;

App-test.tsx

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

import App from './App';

describe('App', () => {
  it('should work as expected', async () => {
    const { getByTestId } = render(<App />);

    const testCheckBox = getByTestId('testing-it');
    expect(testCheckBox).not.toBeChecked();

    fireEvent.focus(testCheckBox);
    fireEvent.keyPress(testCheckBox, { keyCode: 32, charCode: 32, key: ' ', code: 'Space' });

    expect(testCheckBox).toBeChecked(); // this fails
  });
});

CodeSandbox link- https://codesandbox.io/s/cool-star-6k6ghp

@ak-spotter
Copy link

@MatanBobi thanks for you response. I have opened a new issue- #1258

@zacharytyhacz
Copy link

I tried replacing fireEvent.keyPress(input, { key: 'Enter', code: 13 }) with suggestion from https://github.com/testing-library/react-testing-library/issues/269#issuecomment-455854112 fireEvent.keyDown(input, { key: "Enter", keyCode: 13 })

🙏 🙏 🙏 🙏 🙏 🙏 🙏 🙏 🙏 🙏 🙏 🙏 🙏

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

10 participants