I'm testing a styled button component in a Next.js 13+ App Router project using Jest and React Testing Library, but my tests fail when checking for style changes on hover.
Component (TestButton.tsx
):
import { styled } from "@mui/material/styles";
import type { FC } from "react";
const MyButton = styled("button")({
color: "red",
"&:hover": {
color: "yellow",
},
});
const TestButton: FC = () => {
return <MyButton className="button">Test Button</MyButton>;
};
export default TestButton;
Test (TestButton.spec.tsx
):
import TestButton from "~/components/testButton/TestButton";
import { Renderer } from "./Renderer";
import { act } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
describe("TestButton", () => {
it("should change text color on hover", async () => {
const user = userEvent.setup();
const { getByRole } = await act(() => new Renderer(<TestButton />).withAllProviders().render());
const button = getByRole("button", { name: /Test Button/i });
expect(button).toHaveStyle({
color: "red",
});
await act(async () => {
await user.hover(button);
});
expect(button).toHaveStyle({
color: "yellow", // ❌ This fails
});
await act(async () => {
await user.unhover(button);
});
expect(button).toHaveStyle("color: red");
});
});
Test failure output:
FAIL src/__test__/TestButton.spec.tsx
TestButton
× should change text color on hover (168 ms)
● TestButton › should change text color on hover
expect(element).toHaveStyle()
- Expected
- color: yellow;
+ color: red;
so the problem is that toHaveStyle({ color: "yellow" })
fails after triggering user.hover(button)
. while the hover state works fine in the browser.
How can I properly test hover styles for MUI styled components?
If I manually set the styles using onMouseEnter
and onMouseLeave
, the test passes:
const TestButton: FC = () => {
return (
<MyButton
className="button"
onMouseEnter={(e) => {
e.currentTarget.style.color = "yellow";
}}
onMouseLeave={(e) => {
e.currentTarget.style.color = "red";
}}
>
Test Button
</MyButton>
);
};
I'm testing a styled button component in a Next.js 13+ App Router project using Jest and React Testing Library, but my tests fail when checking for style changes on hover.
Component (TestButton.tsx
):
import { styled } from "@mui/material/styles";
import type { FC } from "react";
const MyButton = styled("button")({
color: "red",
"&:hover": {
color: "yellow",
},
});
const TestButton: FC = () => {
return <MyButton className="button">Test Button</MyButton>;
};
export default TestButton;
Test (TestButton.spec.tsx
):
import TestButton from "~/components/testButton/TestButton";
import { Renderer } from "./Renderer";
import { act } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
describe("TestButton", () => {
it("should change text color on hover", async () => {
const user = userEvent.setup();
const { getByRole } = await act(() => new Renderer(<TestButton />).withAllProviders().render());
const button = getByRole("button", { name: /Test Button/i });
expect(button).toHaveStyle({
color: "red",
});
await act(async () => {
await user.hover(button);
});
expect(button).toHaveStyle({
color: "yellow", // ❌ This fails
});
await act(async () => {
await user.unhover(button);
});
expect(button).toHaveStyle("color: red");
});
});
Test failure output:
FAIL src/__test__/TestButton.spec.tsx
TestButton
× should change text color on hover (168 ms)
● TestButton › should change text color on hover
expect(element).toHaveStyle()
- Expected
- color: yellow;
+ color: red;
so the problem is that toHaveStyle({ color: "yellow" })
fails after triggering user.hover(button)
. while the hover state works fine in the browser.
How can I properly test hover styles for MUI styled components?
If I manually set the styles using onMouseEnter
and onMouseLeave
, the test passes:
const TestButton: FC = () => {
return (
<MyButton
className="button"
onMouseEnter={(e) => {
e.currentTarget.style.color = "yellow";
}}
onMouseLeave={(e) => {
e.currentTarget.style.color = "red";
}}
>
Test Button
</MyButton>
);
};
Share
Improve this question
edited Feb 16 at 18:53
jonrsharpe
122k30 gold badges267 silver badges474 bronze badges
asked Feb 16 at 18:46
Haitam-ElgharrasHaitam-Elgharras
1389 bronze badges
1 Answer
Reset to default 0Your test fails because Jest and React Testing Library (RTL) do not process CSS styles dynamically applied via MUI’s styling system. MUI's styled API uses emotion (CSS-in-JS), which injects styles into the DOM, but JSDOM (the environment Jest runs in) does not support pseudo-classes (:hover) by default.
Since MUI's styled components rely on emotion, you need a proper style injector during tests.
install tooling that do provide this
npm install --save-dev jest-styled-components @emotion/react
Modify your test to import jest-styled-components, which enables pseudo-class testing:
import TestButton from "~/components/testButton/TestButton";
import { Renderer } from "./Renderer";
import { act, render } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
import "jest-styled-components"; // <---
describe("TestButton", () => {
it("should change text color on hover", async () => {
const user = userEvent.setup();
const { getByRole } = render(<TestButton />); // <---Use direct render
const button = getByRole("button", { name: /Test Button/i });
expect(button).toHaveStyleRule("color", "red");
await act(async () => { await user.hover(button); });
expect(button).toHaveStyleRule("color", "yellow", { modifier: ":hover" });
});
});
OR another alternative approach is to check the computed style directly (instead of toHaveStyleRule, retrieve styles via JSDOM):
import TestButton from "~/components/testButton/TestButton";
import { render, screen } from "@testing-library/react";
import userEvent from "@testing-library/user-event";
describe("TestButton", () => {
it("should change text color on hover", async () => {
render(<TestButton />);
const button = screen.getByRole("button", { name: /Test Button/i });
expect(window.getComputedStyle(button).color).toBe("red");
await userEvent.hover(button);
await new Promise((r) => setTimeout(r, 100)); // optionally wait for styles (paranoia)
expect(window.getComputedStyle(button).color).toBe("yellow");
await userEvent.unhover(button);
expect(window.getComputedStyle(button).color).toBe("red");
});
});