如何在React单元测试中模拟屏幕尺寸测试MUI响应式组件
问题根因
测试运行在JSDOM环境中,该环境默认没有实现window.matchMedia API,Material UI的useMediaQuery钩子无法获取到正确的屏幕匹配结果,默认返回false,因此始终渲染非中等屏幕的按钮,导致找不到mediumScreenButton元素。
解决步骤
- 实现可自定义宽度的
matchMediamock方法,覆盖MUI依赖的所有API属性 - 在对应屏幕尺寸的测试用例中,传入对应断点区间的宽度值,挂载mock后再渲染组件
- 测试结束后重置mock,避免影响其他测试用例
具体实现代码
1. 编写matchMedia mock工具方法
MUI默认主题的md断点对应宽度范围是960px ~ 1279.95px,如果你自定义过主题断点,请替换为自己项目的断点数值:
const createMatchMedia = (screenWidth) => { return (query) => ({ matches: screenWidth >= 960 && screenWidth < 1280, // 匹配md断点区间 media: query, onchange: null, addListener: jest.fn(), // 兼容旧版媒体查询API removeListener: jest.fn(), addEventListener: jest.fn(), removeEventListener: jest.fn(), dispatchEvent: jest.fn(), }) }
2. 修改测试用例
在中等屏幕测试用例渲染组件前,挂载中等宽度(比如1024px,属于md区间)的matchMedia mock:
import React from 'react'; import { render, fireEvent, screen, cleanup } from '@testing-library/react'; import Demo from './Demo' // 可放到单独的测试工具文件复用 const createMatchMedia = (screenWidth) => { return (query) => ({ matches: screenWidth >= 960 && screenWidth < 1280, media: query, onchange: null, addListener: jest.fn(), removeListener: jest.fn(), addEventListener: jest.fn(), removeEventListener: jest.fn(), dispatchEvent: jest.fn(), }) } beforeEach(() => { window.scrollTo = jest.fn(); window.HTMLDivElement.prototype.scrollIntoView = jest.fn(); }); describe('屏幕尺寸按钮渲染测试', () => { afterEach(() => { cleanup(); jest.clearAllMocks(); // 重置所有mock避免用例间互相影响 }); it('中等屏幕下渲染对应按钮', () => { // 模拟中等屏幕宽度1024px window.matchMedia = createMatchMedia(1024); const { container } = render(<Demo />) const mediumScreenButton = screen.getByTestId('mediumScreenButton'); fireEvent.click(mediumScreenButton); expect(container).toMatchSnapshot(); }); // 可补充其他屏幕的测试用例 it('非中等屏幕下渲染对应按钮', () => { // 模拟小屏幕宽度375px window.matchMedia = createMatchMedia(375); render(<Demo />) const otherScreenButton = screen.getByTestId('otherScreenButton'); expect(otherScreenButton).toBeInTheDocument(); }) });
注意事项
- 如果项目自定义了MUI主题的breakpoints配置,必须修改
createMatchMedia中的宽度判断逻辑,和项目断点保持一致,否则匹配结果会出错 - 如果多个测试文件都需要测试响应式逻辑,可以把
createMatchMedia方法抽到全局测试配置文件(比如src/setupTests.ts)中,避免重复编写 - 测试用例中不需要真的修改
window.innerWidth,只要mock matchMedia的返回值即可,MUI的useMediaQuery只依赖matchMedia的匹配结果,不直接读取窗口宽度
内容的提问来源于stack exchange,提问作者Gowtham Manthena
相关产品推荐
相关产品推荐

