Similar question here - Cannot check expect(elm).not.toBeVisible() for semantic-ui react component - however the answer suggests that this should be working for CSS-in-JS, which is what I'm using.
I'm using Material-UI's <Hidden>
component to only display some text on sm
screen sizes and up. Here's the code (that works perfectly in production):
<Hidden implementation="css" xsDown>
<LogoText variant="h5" component="p" />
</Hidden>
I'm using jest-dom
with react-testing-library
and am trying to test the responsiveness of my navigation bar, which contains this hidden text.
I have the following test:
const initTest = width => {
Object.defineProperty(window, "innerWidth", {
writable: true,
configurable: true,
value: width
});
window.matchMedia = jest.fn().mockImplementation(
query => {
return {
matches: width >= theme.breakpoints.values.sm ? true : false,
media: query,
onchange: null,
addListener: jest.fn(),
removeListener: jest.fn()
};
}
);
const height = Math.round((width * 9) / 16);
return { width, height };
};
describe("Unit: <Navbar> On xs screens", () => {
it("renders as snapshot at minimum size", async () => {
const { width, height } = initTest(320);
const { asFragment, rerender } = render(
<Container backgroundColor={"#ffffff"}>
<Navbar />
</Container>
);
rerender(
<Container backgroundColor={"#ffffff"}>
<Navbar />
</Container>
);
expect(asFragment()).toMatchSnapshot();
const screenshot = await generateImage({
viewport: { width, height }
});
expect(screenshot).toMatchImageSnapshot();
});
it("renders as snapshot at maximum size", async () => {
const { width, height } = initTest(theme.breakpoints.values.sm - 1);
const { asFragment, rerender } = render(
<Container backgroundColor={"#ffffff"}>
<Navbar />
</Container>
);
rerender(
<Container backgroundColor={"#ffffff"}>
<Navbar />
</Container>
);
expect(asFragment()).toMatchSnapshot();
const screenshot = await generateImage({
viewport: { width, height }
});
expect(screenshot).toMatchImageSnapshot();
});
it("hides logo text", async () => {
initTest(theme.breakpoints.values.sm - 1);
const { rerender, getByText } = render(
<Container backgroundColor={"#ffffff"}>
<Navbar />
</Container>
);
rerender(
<Container backgroundColor={"#ffffff"}>
<Navbar />
</Container>
);
await wait(() => expect(getByText("LOGO TEXT")).not.toBeVisible());
});
});
The first 2 tests take a screenshot and when I look at the screenshot, I can see that the logo text is not visible:
- renders as snapshot at minimum size: https://i.stack.imgur.com/uwc2q.png
- renders as snapshot at maximum size: https://i.stack.imgur.com/dz0RY.png
And when I view the DOM in the browser at xs
size, I see that the parent component is indeed hidden: https://i.stack.imgur.com/b7kbU.png
Yet when I run the test it fails and says that the element is visible:
● Unit: <Navbar> On xs screens › hides logo text
expect(element).not.toBeVisible()
Received element is visible:
<p class="MuiTypography-root MuiTypography-h5 makeStyles-typography-237" />
If I add in a console.log(innerWidth)
before the expect()
then it returns the correct width, so the issue isn't that jsdom is rendering at the wrong screen width.
Also, if I change the implementation of the <Hidden>
component from CSS to JS, it works fine (as the element is completely taken out of the document using JS instead of just being hidden using media queries).
How do I fix this to get it to work?