繁体   English   中英

Create React App 在 mocking 异步 function 时更改 jest.fn() 的行为

[英]Create React App changes behaviour of jest.fn() when mocking async function

从使用npx create-react-app jest-fn-behaviour的干净 CRA 项目运行时,我对jest.fn()的以下行为感到困惑。

例子:

describe("jest.fn behaviour", () => {
    
    const getFunc = async () => {
        return new Promise((res) => {
            setTimeout(() => {
                res("some-response");
            }, 500)
        });;
    }

    const getFuncOuterMock = jest.fn(getFunc);


    test("works fine", async () => {

        const getFuncInnerMock = jest.fn(getFunc);
        const result = await getFuncInnerMock();
        expect(result).toBe("some-response"); // passes
    })


    test("does not work", async () => {

        const result = await getFuncOuterMock();
        expect(result).toBe("some-response"); // fails - Received: undefined
    })

});

上述测试将在干净的 JavaScript 项目中按预期工作,但在 CRA 项目中则不然。

有人可以解释为什么第二次测试失败了吗? 在我看来,当 mocking 异步 function jest.fn()在非异步 function 中调用时,将无法按预期工作(上述describe )。 它仅在异步 function (上面的test )中调用时才有效。 但为什么 CRA 会以这种方式改变行为呢?

原因是,正如我在另一个答案中提到的,CRA 的默认 Jest 设置包括以下行

    resetMocks: true,

根据Jest docs ,这意味着(强调我的):

每次测试前自动重置模拟 state。 相当于在每次测试之前调用jest.resetAllMocks() 这将导致任何模拟删除其虚假实现但不会恢复其初始实现。

正如我在评论中指出的那样,您的模拟是在测试发现时创建的,当 Jest 定位所有规范并调用describe (但不是it / test )回调时,而不是在执行时,当它调用规范回调时。 因此它的模拟实现是没有意义的,因为它在任何测试运行之前就被清除了。

相反,您有三个选择:

  1. 如您所见,在测试本身中创建模拟是有效的。 在测试中重新配置现有的模拟也可以,例如getFuncOuterMock.mockImplementation(getFunc) (或只是getFuncOuterMock.mockResolvedValue("some-response") )。

  2. 您可以将模拟创建和/或配置移动到beforeEach回调中; 这些是在所有模拟被重置执行的:

     describe("jest.fn behaviour", () => { let getFuncOuterMock; // or `const getFuncOuterMock = jest.fn();` beforeEach(() => { getFuncOuterMock = jest.fn(getFunc); // or `getFuncOuterMock.mockImplementation(getFunc);` }); ... });
  3. resetMocks是 CRA 支持的用于覆盖 Jest 配置的键之一,因此您可以添加:

     "jest": { "resetMocks": false },

    进入您的package.json

    但是,请注意,这可能会导致您expect(someMock).toHaveBeenCalledWith(some, args)的误报测试,并且由于与不同测试中的模拟交互而通过。 如果您要禁用自动重置,您应该更改实现以在beforeEach中创建模拟(即let getFuncOuterMock;选项 2 中的示例)以避免 state 在测试之间泄漏。

请注意,这与同步与异步无关,也与模拟生命周期无关; 您会在 CRA 项目(或带有resetMocks: true Jest 配置的 vanilla JS 项目)中看到与以下示例相同的行为:

describe("the problem", () => {
  const mock = jest.fn(() => "foo");

  it("got reset before I was executed", () => {
    expect(mock()).toEqual("foo");
  });
});
  ● the problem › got reset before I was executed

    expect(received).toEqual(expected) // deep equality

    Expected: "foo"
    Received: undefined

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM