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

Jest滚动事件测试未触发回调问题排查与正确测试方法咨询

问题:ScrollWatcher组件Jest测试无法触发底部回调

我开发了ScrollWatcher.tsx组件,代码如下:

import { useEffect } from 'react';

interface Props {
  onReachBottom: () => void;
}

export const ScrollWatcher = ({ onReachBottom }: Props) => {
  useEffect(() => {
    const handleScroll = () => {
      if (
        window.innerHeight + document.documentElement.scrollTop ===
        document.documentElement.offsetHeight
      ) {
        onReachBottom();
      }
    };

    window.addEventListener('scroll', handleScroll);

    return () => {
      window.removeEventListener('scroll', handleScroll);
    };
  }, [onReachBottom]);

  return <div />;
};

该组件监听window滚动事件,滚动到页面底部时触发传入的onReachBottom回调,实际页面中功能正常,但编写的Jest测试用例无法触发该回调。

测试代码如下:

import '@testing-library/jest-dom';
import { fireEvent, render } from '@testing-library/react';
import { ScrollWatcher } from './ScrollWatcher';

describe('ScrollWatcher', () => {
  it('should call the onReachBottom function when the user scrolls to the bottom of the page', () => {
    const onReachBottom = jest.fn();
    const { container } = render(<ScrollWatcher onReachBottom={onReachBottom} />);
    const scrollableContainer = container.parentElement;

    fireEvent.scroll(scrollableContainer, { target: { scrollingElement: { scrollTop: 100 } } });

    expect(onReachBottom).not.toHaveBeenCalled();

    fireEvent.scroll(scrollableContainer, {
      target: { scrollingElement: { scrollTop: scrollableContainer.scrollHeight } },
    });

    expect(onReachBottom).toHaveBeenCalled();
  });
});

测试报错信息:

expect(jest.fn()).toHaveBeenCalled()

Expected number of calls: >= 1
Received number of calls:    0

请问我的测试用例是否编写错误?正确的测试方式是什么?


解答

测试用例的错误点

  1. 事件目标不匹配:你的组件监听的是window的滚动事件,但测试中却给container.parentElement触发滚动,两者不是同一个目标,组件的handleScroll不会被执行。
  2. 未模拟判断条件所需的DOM属性:组件判断滚动到底部的逻辑依赖window.innerHeight、document.documentElement.scrollTop和document.documentElement.offsetHeight,测试中没有设置这些属性的正确值,即使触发滚动,判断条件也不成立。

正确的测试代码

直接模拟window的滚动事件,并修改对应DOM属性让判断条件成立:

import '@testing-library/jest-dom';
import { fireEvent, render } from '@testing-library/react';
import { ScrollWatcher } from './ScrollWatcher';

describe('ScrollWatcher', () => {
  it('triggers onReachBottom when scrolled to page bottom', () => {
    const onReachBottom = jest.fn();
    
    // 模拟页面高度和窗口高度
    Object.defineProperty(document.documentElement, 'offsetHeight', { value: 1000 });
    Object.defineProperty(window, 'innerHeight', { value: 500 });
    
    render(<ScrollWatcher onReachBottom={onReachBottom} />);

    // 滚动未到底部时,回调不触发
    Object.defineProperty(document.documentElement, 'scrollTop', { value: 300 });
    fireEvent.scroll(window);
    expect(onReachBottom).not.toHaveBeenCalled();

    // 滚动到底部时(window.innerHeight + scrollTop = offsetHeight),回调触发
    Object.defineProperty(document.documentElement, 'scrollTop', { value: 500 });
    fireEvent.scroll(window);
    expect(onReachBottom).toHaveBeenCalled();
  });
});

关键说明

  • 使用Object.defineProperty修改只读DOM属性:document.documentElement和window的部分属性是只读的,需要用这个方法在测试中模拟它们的值。
  • 保持事件目标一致:组件监听window滚动,测试中就要触发window的滚动事件。
  • 严格匹配判断条件:确保window.innerHeight + document.documentElement.scrollTop等于document.documentElement.offsetHeight,这样组件的判断逻辑才会生效。

内容的提问来源于stack exchange,提问作者Stupid.Fat.Cat

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 04:05:54