'React testing library, how to open a Collapse in Ant Design
I want to write a unit test that opens an antd. Collapse <Panel />
But no matter what combination of fireEvent or userEvent mouse actions I try, I cannot get React testing library to properly "click" on this antD component the same way a real user does.
Example code:
import { Collapse } from 'antd'
const { Panel } = Collapse
const Example = () => (
<Collapse>
<Panel header="test" data-testid="testid">hello_world</Panel>
</Collapse>
)
and in my unit test:
I have tried the following combinations to open the Panel with the header "test"
const panel = screen.getByText('test')
userEvent.click(panel)
const result = screen.getByText('hello_world') // FAILED and never finds hello_world
const panel = screen.getByText('test')
userEvent.click(panel)
const result = await screen.findByText('hello_world') // FAILED and never finds hello_world
const panel = screen.getByText('test')
fireEvent.click(panel)
const result = await screen.findByText('hello_world') // FAILED and never finds hello_world
const panel = screen.getByText('test')
fireEvent.mouseDown(panel)
const result = await screen.findByText('hello_world') // FAILED and never finds hello_world
const panel = screen.getByText('test')
await act(async () => {
fireEvent.mouseDown(panel)
})
const result = await screen.findByText('hello_world') // FAILED and never finds hello_world
const panel = screen.getByText('test')
await act(async () => {
fireEvent.mouseDown(panel)
})
await waait(500) // using waait library, to force time to pass to see if it was that...
const result = await screen.findByText('hello_world') // FAILED and never finds hello_world
const panel = screen.getByTestId('testid')
fireEvent.click(panel) // FAILED, never finds anything with data-testid="testid"
// I guess antd did not bother passing the test-id to the component.
const result = await screen.findByText('hello_world')
This is what the HTML looks like:
<div
class="ant-collapse ant-collapse-icon-position-left css-14dabdk"
>
<div
class="ant-collapse-item"
>
<div
aria-expanded="false"
class="ant-collapse-header"
role="button"
tabindex="0"
>
test
</div>
</div>
I did also try to use querySelector
on container
to target .ant-collapse-header
, ant-collapse-item
or .ant-collapse
with userEvent.click and fireEvent.mouseDown. But those didn't work either.
Why is this thing so difficult to open in a test 🤯.
Does anyone know how to open and antD Collapse component?
Solution 1:[1]
Using user-event
, you can try:
await userEvent.click(screen.getByText(/test/i))
Or click the button, like:
await userEvent.click(screen.getByRole("button"))
Then you can use findByText
like:
expect(await screen.findByText(/hello_world/i)).toBeInTheDocument();
Solution 2:[2]
I've created a simple example to simulate your issue.
What i did to get it working:
- instead of screen, i use
getByText
,queryByText
andfindByText
direct from the return of render, likeconst { getByText, queryByText } = render(<Example />);
* but you can use screen
, not problem at all.
- Your function test should be
async
, like:
it("test", async () => { ... })
or
test("test", async () => { ... })
- To test the success of render 'Hello world', you can use
getByText
withwaitFor
orfindByText
, like below:
Code:
describe("Test PANEL", () => {
it("should PASS WITH QUERYBY - hello_world RENDERED after CLICKED", async () => {
const { getByText, queryByText } = render(<Example />);
const panel = getByText("test");
fireEvent.click(panel);
await waitFor(() => {
const result = queryByText("hello_world");
expect(result).toBeInTheDocument();
});
});
it("should PASS WITH FINDBY - hello_world RENDERED after CLICKED", async () => {
const { getByText, findByText } = render(<Example />);
const panel = getByText("test");
fireEvent.click(panel);
const result = await findByText("hello_world");
expect(result).toBeInTheDocument();
});
});
If you want to check if 'hello_world' is not rendered yet, i recommend you use queryBy
, like this:
describe("Test PANEL", () => {
it("should PASS - hello_world NOT redenred before CLICKED", async () => {
const { getByText, queryByText } = render(<Example />);
const panel = getByText("test");
expect(panel).toBeInTheDocument();
await waitFor(() => {
const result = queryByText("hello_world");
expect(result).not.toBeInTheDocument();
});
});
That´s because queryBy
returns null if it doesnt find any Element, different than findBy
and getBy
-> both throws an error, as you can see in this link.
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | |
Solution 2 |