I am using RTL with Jest to test a Slate editor. I use .type to emulate a user typing into the editor and expect that Slate's onChange will be called. However, this does not happen.
Here's my editor code
import React, { useState } from "react";
import { createEditor } from "slate";
import { Slate, Editable, withReact } from "slate-react";
const initialValue = [
{
type: "paragraph",
children: [{ text: "Foo" }]
}
];
export default function Editor({ onChange }) {
const [editor] = useState(() => withReact(createEditor()));
return (
<Slate onChange={onChange} editor={editor} value={initialValue}>
<Editable data-testid="my_editor" />
</Slate>
);
}
Here's my test code:
import React from "react";
import "@testing-library/jest-dom/extend-expect";
import userEvent from "@testing-library/user-event";
import { render, screen } from "@testing-library/react";
import Editor from "../editor";
test("test", async () => {
const user = userEvent.setup();
const onChange = jest.fn();
render(<Editor onChange={onChange} />);
expect(screen.getByTestId("my_editor")).toHaveTextContent("Foo");
user.type(screen.getByTestId("my_editor"), " some more text");
// I also tried this but did not work...
// user.click(screen.getByTestId("my_editor"));
// user.keyboard("bar");
// also this did not work...
// fireEvent.change(screen.getByTestId("my_editor"), {
// target: { innerHTML: "<p>hello world</p>" }
// });
// or this...
// fireEvent.blur(screen.getByTestId("my_editor"), {
// target: { innerHTML: "<p>hello world</p>" }
// });
expect(onChange).toHaveBeenCalled();
});
If it's easier I have also created a minimal reproduction here.
To reproduce the behavior:
I expected that the onChange will be called. This behavior only happens when tests are ran. In a normal browser onChange is indeed called.
This is a known issue with contenteditable
which is what slate uses.
Essentially the issue lies with js-dom
itself and testing libraries that use js-dom
will all run into this issue.
Look at the discussion and links here Testing react-contenteditable with react testing library
Even the fix that works for testing-library
that uses UserEvents
is able to have the change reflected but doesn't trigger the onChange
events.
On a fork of your code I have added the UserEvent to modify the editor and also added a test that checks for the updated output, which passes. However, the onChange test still fails.
Also, UserEvents v14.x.x is giving some trouble, so I have used v13.5 in my example CodeSandbox
So due to the limitations of the js-dom
, it will be impossible to have a workable test for this. Instead, it is recommended to use other libraries such as puppeteer
.