Testing react-contenteditable with react testing library
Asked Answered
D

5

13

How to test this component: https://github.com/lovasoa/react-contenteditable? How to mimic user action in test environment? I've tried following:

// The given element does not have a value setter
fireEvent.change(sourceContent, {
  target: { value: "New content text" }
});

// This doesn't emit onChange Changes text content but onChange is not fired.
fireEvent.change(sourceContent, {
  target: { textContent: "New content text" }
});

// This doesn't emit onChange. Changes inner html but onChange is not fired.
fireEvent.change(sourceContent, {
  target: { innerHTML: "New content text" }
});

All of the above are failed tests. I thought that if I change innerHTML then function provided in onChange will be fired. This is sample project with this problem: https://codesandbox.io/s/ecstatic-bush-m42hw?fontsize=14&hidenavigation=1&theme=dark

Daren answered 2/3, 2020 at 20:7 Comment(0)
H
8

With https://github.com/testing-library/user-event/issues/442 fixed, it's now possible with userEvent:

const element = screen.getByTestId("myEditableElement");
await userEvent.click(element);
await userEvent.keyboard("abc");
expect(element.textContent).toBe("abc");
Hoicks answered 27/5, 2022 at 22:29 Comment(0)
D
7

It looks like for testing input you should use fireEvent.input. So following:

// This doesn't emit onChange. Changes inner html but onChange is not fired.
fireEvent.change(sourceContent, {
  target: { innerHTML: "New content text" }
});

Will be good way to mimic user input.

Daren answered 2/3, 2020 at 20:15 Comment(1)
fireEvent.input? or fireEvent.change?Caviness
L
7

It's not possible to simulate events on contenteditable with testing-react-library, or any testing library that uses js-dom, because of a limitation on js-dom itself.

See the discussion here and here.

The solution would be to use puppeteer or another method that uses a real browser for rendering.

Longer answered 12/3, 2020 at 17:14 Comment(0)
Z
4

As Paul says on Github here: "Unfortunately, at the moment this feature has not been added to JSDOM, but there are people building features in React that require testing ContentEditable, and currently this is not possible with RTL as things currently stand, so far as I can tell."

But one way that works is fire the blur event and input is changed. See below:

fireEvent.blur(NameField, {target: {textContent: 'edited-text'}});
Zahara answered 9/7, 2020 at 17:0 Comment(0)
K
0

First, you need to focus on the element using userEvent.tab() then use userEvent.keyboard() to write on the contenteditable element like this example below:

await step(
    'Should have the value "Hello ahmnouira, how are you?"',
    async () => {
      userEvent.tab(editor)
      // use delay to simulate typings.
      await userEvent.keyboard(`Hello ahmnouira, how are you?`, {
        delay: 100,
      })
      expect(editor.textContent).toBe('Hello ahmnouira, how are you?')
    }
  )
Kletter answered 5/10, 2023 at 19:27 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.