I have recently upgraded my React project to ant design v4 and all the tests that use a Select, AutoComplete or Tooltip are broken. Basically when clicking the components, the modal or select options are not present in JSDOM. This used to work fine in v3.
Can somebody show me how to test antd v4 with react testing library ?
Example:
My Component:
import React from "react";
import "./styles.css";
import { Select } from "antd";
const { Option } = Select;
function handleChange(value) {
console.log(`selected ${value}`);
}
export default function App() {
return (
<div className="App" style={{ marginTop: "40px" }}>
<Select
defaultValue="lucy"
style={{ width: 120 }}
onChange={handleChange}
>
<Option value="jack">Jack</Option>
<Option value="lucy">Lucy</Option>
<Option value="disabled" disabled>
Disabled
</Option>
<Option value="Yiminghe">yiminghe</Option>
</Select>
</div>
);
}
My test
import "@testing-library/jest-dom/extend-expect";
import React from "react";
import { render, fireEvent, prettyDOM } from "@testing-library/react";
import App from "./App";
test("App Test", () => {
const { queryAllByText, getByText, container } = render(<App />);
expect(queryAllByText("Lucy").length).toBe(1);
expect(queryAllByText("Jack").length).toBe(0);
fireEvent.click(getByText("Lucy"));
console.log(prettyDOM(container));
// This line fails although I would expect the dropdown to be open and all the options visible
expect(queryAllByText("Jack").length).toBe(1);
});
Here is a link to a codesandbox that reproduces the issue. (As mentioned, that code used to work in v3).
https://codesandbox.io/s/staging-shape-0xkrl?file=/src/App.test.js:0-494
Ant Design of React. Following the Ant Design specification, we developed a React UI library antd that contains a set of high quality components and demos for building rich, interactive user interfaces.
This is not a clean solution, as it modifies the production code for testing. It might miss a failure on a TouchEvent, but this should be an issue to the antd-mobile library – not this test. Thanks for contributing an answer to Stack Overflow!
In antd v3 it used to be possible to open a Select by doing selectHtmlElement.click (). You can test in the chrome dev tools console. In v4 this does not work.
It might miss a failure on a TouchEvent, but this should be an issue to the antd-mobile library – not this test. Thanks for contributing an answer to Stack Overflow!
After losing 2 days on this, here is the problem and solution:
Problem
In antd v3 it used to be possible to open a Select by doing selectHtmlElement.click()
. You can test in the chrome dev tools console. In v4 this does not work.
This means that RTL which uses JSDOM under the hood will have the same behaviour. When you do fireEvent.click(selectElement);
nothing happens !
Solution
This put me on the right track: https://github.com/ant-design/ant-design/issues/22074
The event you need to trigger is not a click()
but a mouseDown()
on the first child of the select.
const elt = getByTestId('your-select-test-id').firstElementChild;
fireEvent.mouseDown(elt); // THIS WILL OPEN THE SELECT !
Now at this point you probably want to select an option from the list but there is an animation going on so the following code (that used to work in v3) will also fail.
expect(getByText('Option from Select')).toBeVisible(); // FAILS !
You have 2 options, use toBeInTheDocument()
or wait for the animation to be over by using waitFor(...)
Option 1: Faster but not totally accurate, I prefer to use this for simple use cases as it makes the tests faster and synchronous
expect(getByText('Option from Select')).toBeInTheDocument(); // WORKS !
Option 2: Slower as you need to wait for the animation to finish but more accurate for complex cases
await waitFor(() => expect(getByText('Option from Select')).toBeVisible()); // WORKS !
Looks like now ("antd": "4.17.3", "@testing-library/user-event": "^13.5.0") userEvent.click
with { skipPointerEventsCheck: true }
works:
const options = [
{ label: "🐱", value: "cat", },
{ label: "🐶", value: "dog", }
];
const onChangeMock = jest.fn();
render(
<Select
options={options}
onChange={onChangeMock}
/>,
);
const select = screen.getByRole("combobox");
userEvent.click(select);
const option = screen.getByText("🐶");
userEvent.click(option, undefined, { skipPointerEventsCheck: true });
expect(onChangeMock).toHaveBeenCalledWith("dog", {
label: "🐶",
value: "dog",
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With