【问题标题】:How to test a method with setTimeout and jquery using jest如何使用 jest 使用 setTimeout 和 jquery 测试方法
【发布时间】:2019-02-13 19:35:36
【问题描述】:

我正在努力寻找如何用 jest 测试这个导出函数的解决方案。

export const scrollToError = () => {
  setTimeout(() => {
    const hasErrorElement = jQuery('.has-error');
    if (!hasErrorElement.length) return;
    jQuery('html,body').animate({
      scrollTop: hasErrorElement.offset().top - 50,
    }, 'slow');
  }, 400);
};

我将它导入我的测试文件并尝试启动它:

import { scrollToError } from './utils';

describe('Utils', () => {
  it('should scroll to error', () => {
    const result = scrollToError();
    expect(result).toBe(true); //added this just to force an error and got result as undefined 
  });
});

谁能给我一些关于如何使用这些依赖项测试代码的提示?

【问题讨论】:

    标签: javascript jquery unit-testing jestjs


    【解决方案1】:

    scrollToError() 是异步函数,您不能调用它并期望结果立即出现。在测试之前,您需要等待该毫秒数(在您的情况下为 400)。

    在 Jest 中测试的异步代码略有不同:Testing Asynchronous Code。您也可以take control over the timers 或将其与manual mocks 结合起来并覆盖jQuery 本身。

    【讨论】:

    • 但是 jquery 怎么样.. 我试图找出一种方法来模拟它..
    【解决方案2】:

    你是如何使用 jQuery 的?

    我的意思是,你是使用 npm 还是 yarn 获得它的?要模拟 node_modules,您可以点击此链接:https://jestjs.io/docs/en/manual-mocks#mocking-node-modules

    否则,您将不得不创建手动模拟。你可以在这里看到如何做到这一点:https://jestjs.io/docs/en/manual-mocks

    更新:

    最简单的方法是覆盖它,即在 beforeXXX 方法设置测试时。

    你可以简单地输入类似window.JQuery = jest.fn();

    这是有史以来最简单的模拟,但您必须创建像 animate 这样的方法和其他与 jquery 相关的方法。

    再考虑一下,看看你的函数,如果你模拟 jQuery,还有什么要测试的?

    如果您模拟,您将测试您的 fn 是否正在执行您在此处定义的步骤。比如检查是否使用.has-error 类调用了 jQuery fn,或者animate 是否收到了正确的参数。

    这种测试对你一点帮助都没有,它只是检查它是否逐行遵循你的算法。这里的问题是,您可以进行一些重构,例如更改 .has-error 类名称或通过其他改进方法更改 animate 方法。

    你真正需要改变的是,如果它在做最后应该做的事情。显示 div 或应显示的任何内容。如果您对此进行测试,无论您以何种方式重构代码,测试都会检查最终解决方案是否仍然有效以及重要的事项。

    我说清楚了吗?英语不是我的母语,所以可能有点混乱

    【讨论】:

    • 这里的困难是为它创建一个手动模拟...我不是从 node_modules 使用它...
    【解决方案3】:

    我终于设法找到了一个合适的解决方案。 我为它写了三个测试用例:

    jest.useFakeTimers();
    describe('utils', () => {
      afterEach(() => {
        document.body.innerHTML = '';
      });
      it('ScrollToError - should run the settimeout for 400 ms', () => {
        scrollToError();
        expect(setTimeout).toHaveBeenCalledTimes(1);
        expect(setTimeout).toHaveBeenCalledWith(expect.any(Function), 400);
      });
      it('ScrollToError - should scroll to error', () => {
        document.body.innerHTML = formStep1ErrorMock;
        window.setTimeout = fn => fn();
        const result = scrollToError();
        expect(result).toBe(true);
      });
      it('ScrollToError - should do nothing as has no errors', () => {
        document.body.innerHTML = formStep1Mock;
        window.setTimeout = fn => fn();
        const result = scrollToError();
        expect(result).toBe(true);
      });
    });
    

    所以基本上,首先我检查是否在适当的秒数内调用了 setTimeout(这并不重要)。

    然后我通过这样做window.setTimeout = fn => fn(); 来模拟 setTimeout,这样它就可以在不等待延迟的情况下运行。我还用我需要的适当细节来模拟 html。

    最后,我只介绍另一个场景。

    PS:我在 scrollToError 方法中添加了 return true 语句,以便更简单地获得预期结果。

    通过这种方式,我实现了 100% 的覆盖率。

    【讨论】:

      猜你喜欢
      • 2018-03-24
      • 2021-09-20
      • 2021-12-26
      • 2022-01-18
      • 1970-01-01
      • 1970-01-01
      • 2020-12-07
      • 1970-01-01
      • 2019-04-22
      相关资源
      最近更新 更多