【问题标题】:Mock Document for Jest Testing用于 Jest 测试的模拟文档
【发布时间】:2019-10-01 09:08:20
【问题描述】:

我在 react 组件中有这样的功能:

    handleOnScroll = () => {
        const {navigationSections, setNavigationSectionActive} = this.props;

        const reversedSections = this.getReversedNavigationSections();

        const OFFSET_TOP = 32;
        const st = window.pageYOffset || document.documentElement.scrollTop; 

        if (st > lastScrollTop) {
            for (let i = 0; i < navigationSections.length; i += 1) {
                if(document.getElementById(navigationSections[i].id).getBoundingClientRect().top <= OFFSET_TOP) {
                    setNavigationSectionActive(navigationSections[i].id);
                }
            }

        } else if (st < lastScrollTop) {
            for (let y = 0; y < reversedSections.length; y += 1) {
                if(document.getElementById(navigationSections[y].id).getBoundingClientRect().top <= OFFSET_TOP) {
                    setNavigationSectionActive(navigationSections[y].id);
                }
            }
        }

        lastScrollTop = st <= 0 ? 0 : st;

    }

还有一些这样的测试:

    it('should handle handleOnScroll', () => {
        instance.handleOnScroll();
        expect(instance.getReversedNavigationSections()).toEqual(props.navigationSections.reverse());
    });

    props.navigationSections.forEach(navSection => {
        it('should call setNavigationSectionActive', () => {
            instance.handleOnScroll();
            expect(props.setNavigationSectionActive).toHaveBeenCalledWith(navSection.id);
        });
    });

如您所见,第一个测试通过但第二个测试('应该调用 setNavigationSectionActive')失败:

我认为原因是因为文档没有被模拟,因此 if 失败。但是,在实际执行时:

document.getElementById(navigationSections[i].id).getBoundingClientRect().top 

具有这些 ID 的 DIV 位于另一部分(不在用于相关测试的包装器组件中)。

我应该模拟文档以模拟 if 语句通过的实际结构还是我完全错了?

到目前为止我的尝试

    it('should handle custom handleOnScroll', () => {
        document.body.innerHTML = '<div><div id="id">my div</div><div id="id-1">my div</div></div>';

        const div = document.getElementById('id');
        div.getBoundingClientRect = () => ({ top: 100 });  // <= mock getBoundingClientRect
        instance.handleOnScroll();
        props.navigationSections.forEach(() => {
            if (global.document.getElementById('id').getBoundingClientRect().top <= global.OFFSET_TOP) {
                expect(props.setNavigationSectionActive).toHaveBeenCalledWith('id');
            }
        });
    });

【问题讨论】:

标签: javascript unit-testing jestjs


【解决方案1】:

Jest 的默认测试环境是jsdom,它提供了类似浏览器的环境。

如果您的测试需要document 中的特定内容,那么您可以使用document.body.innerHTML 之类的内容来设置文档正文。

jsdom 实现了很多浏览器功能,但不是全部。在这种情况下,getBoundingClientRect 被存根始终返回 0,因此如果您希望它返回其他内容,则必须模拟它。

这是一个简单的工作示例,可帮助您入门:

const OFFSET_TOP = 5;

const func = () => 
  document.getElementById('theid').getBoundingClientRect().top <= OFFSET_TOP ?
    'less' :
    'more';

test('func', () => {
  document.body.innerHTML = '<div id="theid">my div</div>';
  expect(func()).toBe('less');  // Success!

  const div = document.getElementById('theid');
  div.getBoundingClientRect = () => ({ top: 10 });  // <= mock getBoundingClientRect
  expect(func()).toBe('more');  // Success!
});

【讨论】:

  • 嗨,谢谢你,这是有道理的。我已经实现了它,但是尽管测试通过了,但覆盖率根本不受影响。我想我需要找到一种方法将您的示例与我的组件/测试用例联系起来。查看更新版本。谢谢
猜你喜欢
  • 2018-03-20
  • 2016-02-11
  • 1970-01-01
  • 2021-08-27
  • 2020-02-13
  • 2021-12-10
  • 2021-08-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多