typescript 滚动事件的Jest测试似乎没有调用回调

v09wglhw  于 2023-02-10  发布在  TypeScript
关注(0)|答案(1)|浏览(101)

这是我的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 />;
};

这是我的考验

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

我的测试写得不对吗?什么是合适的测试方法?

w1jd8yoj

w1jd8yoj1#

Jestjs底层使用JSDOM来模拟一个类似浏览器的环境。但是JSDOM还没有实现一个布局系统。请参见web平台的未实现部分issues#2843issues#135
因此,您必须模拟window.innerHeightdocument.documentElement.scrollTopdocument.documentElement.offsetHeight属性。
例如
ScrollWatcher.tsx

import React from 'react';
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 />;
};

ScrollWatcher.test.tsx

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

function scroll(scrollTop, offsetHeight) {
  const event = document.createEvent('Event');
  event.initEvent('scroll', true, true);

  Object.defineProperty(document.documentElement, 'scrollTop', {
    writable: true,
    configurable: true,
    value: scrollTop,
  });
  Object.defineProperty(document.documentElement, 'offsetHeight', {
    writable: true,
    configurable: true,
    value: offsetHeight,
  });
  window.dispatchEvent(event);
}

describe('ScrollWatcher', () => {
  it('should call the onReachBottom function when the user scrolls to the bottom of the page', () => {
    const onReachBottom = jest.fn();
    Object.defineProperty(window, 'innerHeight', {
      writable: true,
      configurable: true,
      value: 50,
    });
    render(<ScrollWatcher onReachBottom={onReachBottom} />);
    scroll(0, 100);
    expect(onReachBottom).not.toHaveBeenCalled();
    scroll(50, 100);
    expect(onReachBottom).toHaveBeenCalled();
  });
});

试验结果:

PASS  stackoverflow/75392262/ScrollWatcher.test.tsx (12.661 s)
  ScrollWatcher
    ✓ should call the onReachBottom function when the user scrolls to the bottom of the page (21 ms)

-------------------|---------|----------|---------|---------|-------------------
File               | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
-------------------|---------|----------|---------|---------|-------------------
All files          |     100 |      100 |     100 |     100 |                   
 ScrollWatcher.tsx |     100 |      100 |     100 |     100 |                   
-------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        13.661 s

相关问题