Javascript Create React应用程序在模拟异步函数时更改jest.fn()的行为
当从使用Javascript Create React应用程序在模拟异步函数时更改jest.fn()的行为,javascript,reactjs,async-await,jestjs,Javascript,Reactjs,Async Await,Jestjs,当从使用npx create react app jest fn behavior创建的干净CRA项目运行时,我对jest.fn()的以下行为感到困惑 例如: describe("jest.fn behaviour", () => { const getFunc = async () => { return new Promise((res) => { setTimeout(() => {
npx create react app jest fn behavior
创建的干净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项目中不会
有人能解释一下为什么第二次测试失败吗?在我看来,模拟异步函数时,在非异步函数中调用时,jest.fn()
将无法按预期工作(例如上面的description
)。它只有在异步函数中调用时才起作用(test
)。但是为什么CRA会以这种方式改变行为?原因是,正如我在中提到的,CRA的默认Jest设置包括:
resetMocks:true,
这意味着(我的重点):
在每次测试之前自动重置模拟状态。相当于
在每次测试之前调用jest.resetAllMocks()
这将导致
删除了假实现的所有模拟,但没有
恢复其初始实现
正如我在评论中指出的,当Jest定位所有规范并调用descripe
(但不是it
/test
)回调时,您的模拟是在测试发现时创建的,而不是在执行时调用规范回调时创建的。因此,它的模拟实现是毫无意义的,因为它在任何测试运行之前就被清除了
相反,您有三种选择:
getFuncOuterMock.mockImplementation(getFunc)
(或者只是getFuncOuterMock.mockResolvedValue(“一些响应”)
)
中;在重置所有模拟后执行这些操作:
description(“jest.fn行为”),()=>{
让我们到最外面去;
//或'const getFuncOuterMock=jest.fn()`
在每个之前(()=>{
getFuncOuterMock=jest.fn(getFunc);
//或者“getFuncOuterMock.mockImplementation(getFunc)”`
});
...
});
resetMocks
是覆盖Jest配置的CRA之一,因此您可以添加:
"jest": {
"resetMocks": false
},
进入您的包.json
但是,请注意,这可能会导致假阳性测试,您期望(someMock).tobeencalledwith(some,args)
,并且由于在不同测试中与mock交互而通过。如果要禁用自动重置,还应更改实现以在每个之前在中创建模拟(即选项2中的let getFuncOuterMock;
示例),以避免测试之间的状态泄漏
resetMocks:true
Jest配置的vanilla JS项目)中,您会看到以下示例的相同行为:
“它在我的机器上运行得很好。”hoangdv很有趣。如果您在承诺中添加了
setTimeout()
(我已经更新了问题),只是为了确保这不是一个竞争条件问题,会怎么样?getTodosOuterMock
可能在该描述块中的测试之间共享状态,并且是在测试发现而不是测试执行时创建的;也许当你试图减少这一点时,这方面就消失了?@jonrsharpe我承认这可能不是一个现实的例子。但是,如果我单独运行这些测试(依次对每个测试进行注释),我会得到相同的结果。我只是挠头想弄明白为什么async-await
不适用于getTodosOuterMock
函数,正如我所期望的那样,它仍然适用于我。请注意,在单元测试中,您可能并不希望有500毫秒的延迟,如果您正在测试实际使用setTimeout的东西,请查看Jest的“伪计时器”。
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