React Testing Library无法检测MUI样式组件的:hover样式
测试MUI样式组件hover样式的正确方法
问题场景
在Next.js 13+ App Router项目中,使用Jest和React Testing Library测试MUI styled 生成的按钮组件时,hover状态的样式断言失败,但该效果在浏览器中正常工作。手动通过onMouseEnter/onMouseLeave绑定内联样式时,测试可以通过。
组件代码(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;
测试代码(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", // ❌ 测试失败 }); await act(async () => { await user.unhover(button); }); expect(button).toHaveStyle("color: red"); }); });
测试失败输出
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;
问题原因
Jest依赖的jsdom环境对CSS伪类(如:hover)的样式计算支持有限,toHaveStyle断言仅检查元素的内联样式或jsdom计算出的当前样式,无法正确识别MUI styled 生成的伪类样式规则。而手动绑定onMouseEnter/onMouseLeave时,样式是直接设置到元素的内联style属性,因此能被toHaveStyle捕获。
解决方案
推荐使用@emotion/jest提供的toHaveStyleRule匹配器,它可以直接解析MUI(基于Emotion)生成的样式规则,包括伪类状态下的样式。
步骤1:安装依赖
npm install --save-dev @emotion/jest
步骤2:配置Jest(可选)
若要全局启用该匹配器,在jest.config.js中添加:
module.exports = { setupFilesAfterEnv: ["@emotion/jest"], };
或者在单个测试文件顶部导入:
import '@emotion/jest';
步骤3:修改测试代码
将原来的toHaveStyle断言替换为toHaveStyleRule,并通过modifier指定伪类:
import TestButton from "~/components/testButton/TestButton"; import { Renderer } from "./Renderer"; import { act } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import '@emotion/jest'; // 若未全局配置则添加此行 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).toHaveStyleRule('color', 'red'); // 触发hover并检查伪类样式 await user.hover(button); expect(button).toHaveStyleRule('color', 'yellow', { modifier: ':hover' }); // 离开hover并恢复检查 await user.unhover(button); expect(button).toHaveStyleRule('color', 'red'); }); });
原理说明
toHaveStyleRule会直接从Emotion生成的样式表中查找目标元素对应的样式规则,包括伪类、媒体查询等特殊规则,无需依赖jsdom对这些状态的计算支持,因此能准确验证MUI styled组件的样式逻辑。
内容的提问来源于stack exchange,提问作者Haitam-Elgharras
相关产品推荐
相关产品推荐

