I created a menu component based of the material-ui's example for a simple menu to change the language for my app. The menu works just fine in the browser, but for one of my tests, more precise the last assertion, does not work and I do not know why.
The test should:
- render the component
- test that the menu is not rendered
- click the menu's activation button
- test that the rendered menu matches the snapshot and is visible
- click the button in the menu to close the menu (here I tried different things, left them out-commented)
- test that the menu is not rendered anymore, thus disappears
Before this state of the code I had keepMounted
in the menu's props, like the above linked example, and instead of testing that the menu is not rendered I tested that it is not.toBeVisible()
. But this did not work either.
From the error message I assume, that the button inside the menu does disappear, but the menu itself does not, because the button's HTML is missing. But I do not understand the reason for this.
I hope someone can shed some light into this issue. Thanks in advance :)
The below component's code works in my app and the console output is from the below test.
Console output:
FAIL src/components/__tests__/LanguageMenu.test.tsx
<LanguageMenu />
× renders menu correctly when opened and closed (275 ms)
● <LanguageMenu /> › renders menu correctly when opened and closed
expect(received).toBeNull()
Received: <div aria-hidden="true" class="MuiPopover-root" data-testid="lang-menu" id="test-menu" role="presentation" style="position: fixed; z-index: 1300; right: 0px; bottom: 0px; top: 0px; left: 0px;"><div data-test="sentinelStart" tabindex="0" /><div class="MuiPaper-root MuiMenu-paper MuiPopover-paper MuiPaper-elevation8 MuiPaper-rounded" style="opacity: 0; transform: scale(0.75, 0.5625); transition: opacity 0ms cubic-bezier(0.4, 0, 0.2, 1) 0ms,transform 0ms cubic-bezier(0.4, 0, 0.2, 1) 0ms; top: 16px; left: 16px; transform-origin: -16px -16px;" tabindex="-1"><ul class="MuiList-root MuiMenu-list MuiList-padding"
role="menu" tabindex="-1"><li aria-disabled="false" class="MuiButtonBase-root MuiListItem-root MuiMenuItem-root MuiMenuItem-gutters MuiListItem-gutters MuiListItem-button" role="menuitem" tabindex="0">Menu Button<span class="MuiTouchRipple-root"><span class="MuiTouchRipple-ripple MuiTouchRipple-rippleVisible" style="width: 2.8284271247461903px; height: 2.8284271247461903px; top: -1.4142135623730951px; left: -1.4142135623730951px;"><span class="MuiTouchRipple-child MuiTouchRipple-childLeaving" /></span></span></li></ul></div><div data-test="sentinelEnd" tabindex="0" /></div>
20 | userEvent.click(screen.getByText("Menu Button"));
21 |
> 22 | expect(screen.queryByTestId("lang-menu")).toBeNull();
| ^
23 | });
24 | });
25 |
at Object.<anonymous> (src/components/__tests__/LanguageMenu.test.tsx:22:47)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 total
Snapshots: 1 passed, 1 total
Time: 6.587 s
Ran all test suites related to changed files.
Simplified version of the menu to recreate issue:
import { Button, Menu, MenuItem, Typography } from "@material-ui/core";
import React, { MouseEvent, ReactElement, useState } from "react";
const LanguageMenu = (): ReactElement => {
const [anchorEl, setAnchorEl] = useState<null | HTMLElement>(null);
const handleClick = (event: MouseEvent<HTMLButtonElement>): void => {
setAnchorEl(event.currentTarget);
};
const handleClose = (): void => {
setAnchorEl(null);
};
return (
<>
<Button aria-controls="test-menu" aria-haspopup="true" onClick={handleClick}>
<Typography>Open Menu</Typography>
</Button>
<Menu
data-testid="lang-menu"
id="test-menu"
anchorEl={anchorEl}
open={Boolean(anchorEl)}
onClick={handleClose}
onClose={handleClose}
>
<MenuItem key="item1" onClick={handleClose}>
Menu Button
</MenuItem>
</Menu>
</>
);
};
export default LanguageMenu;
Erroneous test:
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import React from "react";
import LanguageMenu from "../LanguageMenu";
describe("<LanguageMenu />", () => {
it("renders menu correctly when opened and closed", () => {
render(<LanguageMenu />);
expect(screen.queryByTestId("lang-menu")).toBeNull();
userEvent.click(screen.getByRole("button"));
expect(screen.getByTestId("lang-menu")).toMatchSnapshot();
expect(screen.getByTestId("lang-menu")).toBeVisible();
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore
// userEvent.click(screen.getByRole("presentation").firstChild); // click backdrop
// userEvent.click(screen.getByTestId("lang-menu")); // click menu itself
userEvent.click(screen.getByText("Menu Button")); // click button in menu
expect(screen.queryByTestId("lang-menu")).toBeNull();
});
});