如何用Jest和React Testing Library测试窗口缩放时的CSS响应式样式
解决Jest/React Testing Library中响应式CSS媒体查询测试问题
你遇到的问题很典型:直接修改window.innerWidth并不会让浏览器自动重新计算媒体查询对应的CSS样式,因为Jest的JS DOM环境不会主动监听窗口尺寸变化并更新已渲染元素的样式。下面来一步步解决这个问题:
为什么你的测试不通过?
- 直接替换window对象无效:你用
window = { ...window, innerWidth: 500 }的方式替换了全局window对象,但此时组件已经渲染完成,DOM不会重新读取新的window尺寸来应用媒体查询。 - 媒体查询需要触发样式重计算:即使修改了窗口尺寸,也需要触发resize事件或者重新渲染组件,才能让浏览器重新计算并应用对应的CSS规则。
正确的测试方案
我们需要先正确修改window.innerWidth(注意Jest中这个属性默认是只读的),然后触发样式重计算,再验证样式是否正确。这里有两种可靠的实现方式:
方式一:使用Object.defineProperty修改尺寸并触发resize事件
import { render } from '@testing-library/react'; import Footer from './Footer'; it("should toggle border display based on viewport width", () => { // 测试大屏幕尺寸(大于590px) Object.defineProperty(window, 'innerWidth', { writable: true, configurable: true, value: 1024 }); const { container } = render(<Footer />); let border = container.querySelector('.border'); let computedStyle = window.getComputedStyle(border); // 验证大屏幕下border可见 expect(computedStyle.display).not.toBe('none'); // 修改为小屏幕尺寸(小于590px) Object.defineProperty(window, 'innerWidth', { writable: true, configurable: true, value: 500 }); // 触发resize事件,让JS DOM重新计算媒体查询样式 window.dispatchEvent(new Event('resize')); // 重新获取元素和计算样式(因为resize可能触发组件更新) border = container.querySelector('.border'); computedStyle = window.getComputedStyle(border); // 验证小屏幕下border被隐藏 expect(computedStyle.display).toBe('none'); });
方式二:使用Jest Spy模拟尺寸并重新渲染组件
如果你更倾向于用Jest的mock能力,可以用jest.spyOn来模拟window.innerWidth,并通过重新渲染组件来应用新样式:
import { render } from '@testing-library/react'; import Footer from './Footer'; it("should hide border on small viewports", () => { // 保存原始窗口尺寸,测试后恢复 const originalInnerWidth = window.innerWidth; // 模拟大屏幕尺寸 const widthSpy = jest.spyOn(window, 'innerWidth', 'get').mockReturnValue(1024); const { container, rerender } = render(<Footer />); let border = container.querySelector('.border'); expect(window.getComputedStyle(border).display).not.toBe('none'); // 切换到小屏幕尺寸 widthSpy.mockReturnValue(500); // 重新渲染组件,让它根据新的窗口尺寸应用样式 rerender(<Footer />); // 验证样式变化 border = container.querySelector('.border'); expect(window.getComputedStyle(border).display).toBe('none'); // 恢复原始窗口尺寸,避免影响其他测试 widthSpy.mockRestore(); });
关键注意事项
- 不要直接赋值window.innerWidth:Jest环境中
window.innerWidth是只读属性,直接赋值不会生效,必须用Object.defineProperty或者jest.spyOn来修改。 - 触发样式重计算:修改尺寸后,要么触发
resize事件,要么重新渲染组件,才能让媒体查询的CSS规则生效。 - 测试后恢复环境:记得在测试结束后恢复原始的
window.innerWidth,避免影响其他测试用例的执行。
内容的提问来源于stack exchange,提问作者uinstinct
相关产品推荐
相关产品推荐

