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

fireEvent.keyPress not fire in test #269

Closed
zhaozhiming opened this issue Jan 18, 2019 · 28 comments
Closed

fireEvent.keyPress not fire in test #269

zhaozhiming opened this issue Jan 18, 2019 · 28 comments
Labels
help wanted Extra attention is needed needs investigation question Further information is requested

Comments

@zhaozhiming
Copy link

zhaozhiming commented Jan 18, 2019

  • react-testing-library version: 5.4.4
  • react version: 16.5.2
  • node version: 10.0.0
  • npm (or yarn) version: yarn 1.9.2

Relevant code or config:

  test("input key press correctly", () => { // failed
    const doSomething = jest.fn();
    const doOtherThing = jest.fn();
    const { container } = render(
      <App doSomething={doSomething} doOtherThing={doOtherThing} />
    );
    const input = getByTestId(container, "input");
    fireEvent.keyPress(input, { key: "Enter", code: 13 });
    expect(doSomething.mock.calls.length).toBe(1);
  });

What you did:

run test

What happened:

test failed

Reproduction:

https://codesandbox.io/s/jrv9v845v

Problem description:

When use fireEvent.keyPress, the input keyPress event not fired.
I found the doc about this part of the content, but I don't know what different between the keyPress event and change event.
image

Suggested solution:

I have no idea.

@kentcdodds kentcdodds added help wanted Extra attention is needed question Further information is requested needs investigation labels Jan 18, 2019
@baruchvlz
Copy link

baruchvlz commented Jan 19, 2019

I decided to dig into this a little bit. Adding input.addEventListener('keypress', console.log); shows that the event is indeed dispatched but for some reason React isn't calling the function.

This is as far as I got, I'm no React guru so I wouldn't know where to go from here.

@puemos
Copy link

puemos commented Jan 20, 2019

Ok so i found out what is the issue:

TL;DR

https://codesandbox.io/s/n4p6z5o270

when you fire an keypress event you have to set the charCode

const input = getByTestId(container, "input");
fireEvent.keyPress(input, { key: "Enter", code: 13, charCode: 13 });
expect(doSomething.mock.calls.length).toBe(1);

Why? here:

switch (topLevelType) {
    case DOMTopLevelEventTypes.TOP_KEY_PRESS:
        // Firefox creates a keypress event for function keys too. This removes
        // the unwanted keypress events. Enter is however both printable and
        // non-printable. One would expect Tab to be as well (but it isn't).
        if (getEventCharCode(nativeEvent) === 0) {
            return null;
        }
}

https://github.com/facebook/react/blob/b87aabdfe1b7461e7331abb3601d9e6bb27544bc/packages/react-dom/src/events/SimpleEventPlugin.js#L226

/**
 * `charCode` represents the actual "character code" and is safe to use with
 * `String.fromCharCode`. As such, only keys that correspond to printable
 * characters produce a valid `charCode`, the only exception to this is Enter.
 * The Tab-key is considered non-printable and does not have a `charCode`,
 * presumably because it does not produce a tab-character in browsers.
 *
 * @param {object} nativeEvent Native browser event.
 * @return {number} Normalized `charCode` property.
 */
function getEventCharCode(nativeEvent) {
  var charCode = void 0;
  var keyCode = nativeEvent.keyCode;

  if ('charCode' in nativeEvent) {
    charCode = nativeEvent.charCode;

    // FF does not set `charCode` for the Enter-key, check against `keyCode`.
    if (charCode === 0 && keyCode === 13) {
      charCode = 13;
    }
  } else {
    // IE8 does not implement `charCode`, but `keyCode` has the correct value.
    charCode = keyCode;
  }

  // IE and Edge (on Windows) and Chrome / Safari (on Windows and Linux)
  // report Enter as charCode 10 when ctrl is pressed.
  if (charCode === 10) {
    charCode = 13;
  }

  // Some non-printable keys are reported in `charCode`/`keyCode`, discard them.
  // Must not discard the (non-)printable Enter-key.
  if (charCode >= 32 || charCode === 13) {
    return charCode;
  }

  return 0;
}

https://github.com/facebook/react/blob/b87aabdfe1b7461e7331abb3601d9e6bb27544bc/packages/react-dom/src/events/getEventCharCode.js

@kentcdodds
Copy link
Member

Awesome! Would anyone be willing to add a note about this in the docs?

@puemos
Copy link

puemos commented Jan 20, 2019

I'm on it 😎

@puemos
Copy link

puemos commented Jan 20, 2019

@kentcdodds maybe we should set the defaults for the KeyboardEvent to include charCode: 0 as the browser does.

*Try to create an new KeyboardEvent()

@baruchvlz
Copy link

baruchvlz commented Jan 20, 2019

Maybe have a fallback in the library where if the user has code and not charCode then set charCode to the value of code.

if (init.code && init.charCode === undefined) {
  init.charCode = init.code;
}

I feel this is too much coding for failure, but I still wanted to suggest it.

@kentcdodds
Copy link
Member

Ah, good ideas.

I think let's start with the suggestion from @puemos. Not sure how I feel about @baruchvlz's idea. I worry it could lead to confusion and potentially hide problems 🤔

puemos added a commit to puemos/dom-testing-library that referenced this issue Jan 20, 2019
@baruchvlz
Copy link

@kentcdodds Yea, I agree that it could lead to confusion. It also feels like it's trying to solve one specific scenario which doesn't go at-par with the library. In any case, I still wanted to suggest it 😃

kentcdodds pushed a commit to testing-library/dom-testing-library that referenced this issue Jan 20, 2019
* add: charCode to Keyboard Events defaults

as we discussed here testing-library/react-testing-library#269 (comment)

* add: puemos as contributor
@kentcdodds
Copy link
Member

This fix by @puemos will be released momentarily! Thanks!

@alexkrolick
Copy link
Collaborator

I think their might be differences in how browsers fire keypress events - I don't see handleKeyPress being called at all when I type in the codesandbox on mobile Chrome. onKeyDown/onKeyUp do get called.

@Jacknes
Copy link

Jacknes commented Jul 8, 2019

For me, using fireEvent.keyDown all I needed to add was the keyCode

fireEvent.keyDown(searchField, { key: 'enter', keyCode: 13 })

ryota-murakami added a commit to laststance/react-typescript-todomvc-2022 that referenced this issue Aug 17, 2019
ryota-murakami added a commit to laststance/react-typescript-todomvc-2022 that referenced this issue Aug 17, 2019
@ryota-murakami
Copy link
Contributor

I had still same issue at 'keyPress' event on the personal open-source project.�🤔

  • version: @testing-library/react@8.0.4

Relevant code

test('should work edit mode toggle', () => {
  const { getByTestId, container } = render(
    <Provider store={initialStore}>
      <App />
    </Provider>
  )

  // by default, edit input form is not visible
  expect(getByTestId('todo-edit-input')).not.toBeVisible()

  // double click todo text label, then enable todo text edit code
  fireEvent.doubleClick(getByTestId('todo-body-text'))
  expect(getByTestId('todo-item')).toHaveClass('editing')
  // @TODO in jsdom, dynamic .editing css class doesn't apply. So tipically show/hide UI test are difficult.
  // @ref https://spectrum.chat/testing-library/general/testing-an-accordion~b004a9b1-b104-4eb1-a73b-43c60b1a3630?m=MTU1NDQ4NDIzMTQ5Ng==
  //expect(getByTestId('todo-edit-input')).toBeVisible()
  fireEvent.change(getByTestId('todo-edit-input'), {
    target: { value: 'cut tomato plus' }
  })
+  //@TODO why fireEvent.keyPress() didn't work?
+  fireEvent.keyPress(getByTestId('todo-edit-input'), {
+  key: 'Enter',
+  code: 13,
  })

expect(getByTestId('todo-body-text')).toHaveTextContent('cut tomato plus')
+ success press enter key then finish edit mode
+ expect(container.querySelector('[class*="editing"]')).toBe(null)

But added keyCode: 13 option, it works well.

Bellow, I left reproduce log.

  • picture(commit)

Screen Shot 2019-08-17 at 11 31 33

to: @kentcdodds @puemos

@sstauross
Copy link

ng fireEvent.keyDown all I needed to add was the keyCode

Had same issue with enter and using keyCode instead of code worked:

    fireEvent.keyDown(domElement, {
      key: 'Enter',
      keyCode: 13,
    });

@wunnle
Copy link

wunnle commented Oct 9, 2019

I'm still having the same problem, couldn't manage to fire 'Enter' to submit the form.

I tried different suggestions from here, with keyCode instead of code and/or adding charCode, none of them worked for me.

@thiemnv-teko
Copy link

thiemnv-teko commented Dec 11, 2019

Same issue with my code:

    const inputText = 'z'.repeat(254);
    let outputText = '';

    const comp = queryByTestId('name');

    fireEvent.change(comp , { target: { value: inputText } });
    fireEvent.keyPress(comp , { key: 'A', keyCode: 65 });
    fireEvent.keyPress(comp , { key: 'A', keyCode: 65 });
    outputText = ref.current.getData().name; // forwardRef, useImperativeHandle here

    expect(outputText.length).toEqual(255);

outputText length still 254

@ThomasBurleson
Copy link

This still seems to be a bug (even in version 9.4.0). Should this be re-opened?

@kentcdodds
Copy link
Member

Please open a new issue with a reproduction and a suggested solution.

@SimonFinney
Copy link

Is this still an issue that folks are having? I've attempted the solutions above and have been unable to resolve.

@eps1lon
Copy link
Member

eps1lon commented Feb 12, 2020

I'm still having the same problem, couldn't manage to fire 'Enter' to submit the form.

@wunnle As far as I know this is a limitation of JSDOM. That a form is submitted when pressing Enter while an input is focused is not standard (as in there is no specification for that) behavior.

Most browsers implement it anyway.

Someone would need to do a bit of research and find out if this is expected (as in the browser also ignores dispatched Enter) or if this is indeed only a JSDOM limitation.

Otherwise it might make sense to propose this feature to user-event.

@brietsparks
Copy link

In all the confusion I'm seeing variance in:

  • .keyDown, .keyPress
  • key: 'enter', 'Enter'
  • keyCode and code: 13 and Enter

So I ran:

fireEvent.keyDown(input, { key: 'Enter', keyCode: 13 });
fireEvent.keyDown(input, { key: 'enter', keyCode: 13 });
fireEvent.keyDown(input, { key: 'Enter', code: 13 });
fireEvent.keyDown(input, { key: 'enter', code: 13 });

fireEvent.keyDown(input, { key: 'Enter', keyCode: 'Enter' });
fireEvent.keyDown(input, { key: 'enter', keyCode: 'Enter' });
fireEvent.keyDown(input, { key: 'Enter', code: 'Enter' });
fireEvent.keyDown(input, { key: 'enter', code: 'Enter' });

fireEvent.keyDown(input, { key: 'Enter', keyCode: 'enter' });
fireEvent.keyDown(input, { key: 'enter', keyCode: 'enter' });
fireEvent.keyDown(input, { key: 'Enter', code: 'enter' });
fireEvent.keyDown(input, { key: 'enter', code: 'enter' });

fireEvent.keyPress(input, { key: 'Enter', keyCode: 13 });
fireEvent.keyPress(input, { key: 'enter', keyCode: 13 });
fireEvent.keyPress(input, { key: 'Enter', code: 13 });
fireEvent.keyPress(input, { key: 'enter', code: 13 });

fireEvent.keyPress(input, { key: 'Enter', keyCode: 'Enter' });
fireEvent.keyPress(input, { key: 'enter', keyCode: 'Enter' });
fireEvent.keyPress(input, { key: 'Enter', code: 'Enter' });
fireEvent.keyPress(input, { key: 'enter', code: 'Enter' });

fireEvent.keyPress(input, { key: 'Enter', keyCode: 'enter' });
fireEvent.keyPress(input, { key: 'enter', keyCode: 'enter' });
fireEvent.keyPress(input, { key: 'Enter', code: 'enter' });
fireEvent.keyPress(input, { key: 'enter', code: 'enter' });

And found that my winning combo of the day was fireEvent.keyPress(input, { key: 'Enter', keyCode: 13 });

Don't know if it covers all permutations but you get the idea

@rohmanhm
Copy link

It seems this issue is related to #680

SpiritBreaker226 added a commit to SpiritBreaker226/nfl-rushing that referenced this issue Jun 8, 2020
Fix Player Search test for keyPress as there is an undocumented key
`charCode` that is required for fireEvent to run.

---
Ref:

testing-library/react-testing-library#269
SpiritBreaker226 added a commit to SpiritBreaker226/nfl-rushing that referenced this issue Jun 8, 2020
Fix Player Search test for keyPress as there is an undocumented key
`charCode` that is required for fireEvent to run.

---
Ref:

testing-library/react-testing-library#269
@lannyheidbreder-mc
Copy link

And found that my winning combo of the day was fireEvent.keyPress(input, { key: 'Enter', keyCode: 13 });

Naturally, the winning combo uses a deprecated event with a big red warning on MDN 😅

@ryota-murakami
Copy link
Contributor

Over a year I was facing and commented issue still arrive. This is interesting.
Here is looks like domevent-debugging-library lol

@wafuwafu13
Copy link

I solved by

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

input.focus();
userEvent.keyboard('{enter}');

@davidcoelho02
Copy link

This is still not working... the event itself is fired, but the state doesn't change.
I've tried it with fireEvent.keyDown and fireEvent.keyPress.

@davidcoelho02
Copy link

It worked with @wafuwafu13 solution 💪

qijixin2 pushed a commit to qijixin2/dom-testing-library that referenced this issue Aug 26, 2022
* add: charCode to Keyboard Events defaults

as we discussed here testing-library/react-testing-library#269 (comment)

* add: puemos as contributor
codegenius1017 added a commit to codegenius1017/create-react-app-example that referenced this issue Aug 28, 2022
codegenius1017 added a commit to codegenius1017/create-react-app-example that referenced this issue Aug 28, 2022
Wxh16144 added a commit to Wxh16144-forks/collapse that referenced this issue Jan 9, 2023
zombieJ pushed a commit to react-component/collapse that referenced this issue Jan 10, 2023
* feat: Upgrade build deps

* chore: update

* test: replace enzyme with testing

* chore: remove script

* style: format code

use prettier

* test: update case

ref: testing-library/react-testing-library#269 (comment)

* style: update README.md

* chore: update docs

* chore: rname

* style: foramt
@yduartep
Copy link

yduartep commented Mar 3, 2023

I solved by

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

input.focus();
userEvent.keyboard('{enter}');

This is also working for me

@elmijo
Copy link

elmijo commented Jun 1, 2023

Hi guys, I think the issue happens because the focus is not on the input, so if you do this:

input.focus()
fireEvent.keyPress(input, { key: 'Enter', keyCode: 13 });

The keyboard event will be fired. At latest it worked for me 😄

  • @testing-library/react: 14.0.0
  • Node.js 16.18.1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
help wanted Extra attention is needed needs investigation question Further information is requested
Projects
None yet
Development

No branches or pull requests