You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

React Testing Library与Jest DOM响应式测试失效,求正确测试方法

React Testing Library + Jest DOM 测试响应式组件的问题与解决方案

问题描述

我正在尝试使用React Testing Library和Jest DOM测试组件的响应式行为,待测试代码的媒体查询在浏览器中可正常工作。当前测试设置如下:

beforeAll(() => {
  window.resizeTo(767, 500);
});

it('should have correct styling for mobile', async () => {
  const {findByTestId} = render(
    <StepHeader index={1}>Future Step</StepHeader>,
  );

  console.log(window.innerWidth)
  const stepHeader = await findByTestId('step-header-button-1'); // 元素已设置该测试ID
  expect(stepHeader).toHaveStyle({fontSize: '16px', height: '48px'});
});

控制台日志显示屏幕宽度符合预期,但测试未通过,组件仍采用桌面端样式(如高度为36px而非预期的48px)。请问是否正确调整了屏幕尺寸?使用React Testing Library和Jest DOM测试响应式屏幕的更佳方法是什么?

问题原因与解决方法

1. 为什么window.resizeTo不生效?

直接调用window.resizeTo不会触发媒体查询的重新计算——Jest的jsdom环境不会自动监听窗口尺寸变化并更新样式。媒体查询样式是在组件渲染时根据当前视口尺寸应用的,哪怕beforeAll里的resize操作早于组件渲染,也不会触发样式的重新适配。

2. 正确的测试方法

方法一:设置视口尺寸后触发resize事件

确保在渲染组件前设置好视口尺寸,再手动触发resize事件让媒体查询重新计算:

it('should have correct styling for mobile', async () => {
  // 覆盖window.innerWidth的值
  Object.defineProperty(window, 'innerWidth', { 
    writable: true, 
    configurable: true, 
    value: 767 
  });
  // 触发resize事件,强制更新媒体查询样式
  window.dispatchEvent(new Event('resize'));

  const {findByTestId} = render(
    <StepHeader index={1}>Future Step</StepHeader>,
  );

  const stepHeader = await findByTestId('step-header-button-1');
  expect(stepHeader).toHaveStyle({fontSize: '16px', height: '48px'});
});

方法二:模拟媒体查询匹配结果(适用于CSS-in-JS方案)

如果组件使用styled-components、Emotion等CSS-in-JS库,可以直接模拟matchMedia的返回结果,精准控制媒体查询是否匹配:

beforeAll(() => {
  jest.spyOn(window, 'matchMedia').mockImplementation(query => ({
    matches: query === '(max-width: 767px)', // 指定匹配移动端媒体查询
    media: query,
    onchange: null,
    addListener: jest.fn(),
    removeListener: jest.fn(),
    addEventListener: jest.fn(),
    removeEventListener: jest.fn(),
    dispatchEvent: jest.fn(),
  }));
});

afterAll(() => {
  jest.restoreAllMocks(); // 测试结束后恢复mock
});

it('should have correct styling for mobile', async () => {
  const {findByTestId} = render(
    <StepHeader index={1}>Future Step</StepHeader>,
  );

  const stepHeader = await findByTestId('step-header-button-1');
  expect(stepHeader).toHaveStyle({fontSize: '16px', height: '48px'});
});

方法三:用user-event模拟动态窗口resize

如果需要测试窗口尺寸变化时的样式切换,可以使用@testing-library/user-event模拟resize操作:

import userEvent from '@testing-library/user-event';

it('should update styling when resizing to mobile', async () => {
  const user = userEvent.setup();
  const {findByTestId} = render(
    <StepHeader index={1}>Future Step</StepHeader>,
  );

  // 模拟窗口缩小到移动端尺寸
  await user.resizeWindow(767, 500);

  const stepHeader = await findByTestId('step-header-button-1');
  expect(stepHeader).toHaveStyle({fontSize: '16px', height: '48px'});
});

3. 注意事项

  • 避免在beforeAll中全局设置窗口尺寸,测试用例之间可能互相干扰,建议每个测试单独设置并在结束后恢复。
  • 使用toHaveStyle时,确保样式写法和组件实际生成的一致(比如单位、属性名驼峰格式)。
  • 若使用传统CSS或CSS Modules,需确保Jest配置能正确解析媒体查询(一般默认配置即可支持)。

内容的提问来源于stack exchange,提问作者Yousuf Daramay

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 08:21:57