-更新-
已确定问题。
在实际的代码库中,将断言传递给导入的回调,一旦回调以失败的测试执行,则会引发承诺拒绝。
因此,这与测试的实际编写方式很接近:
describe( "file system", () => {
it( "should check if the file exists", async () => {
call( async () => {
const received = await fileExists();
const expected = true;
expect( received ).toBe( expected );
});
});
});
并以更简单的方式显示复杂的回调以产生相同的问题:
export function call( callback) {
callback();
}
-更新-
以下代码有效。
我从大型代码库中提取了一小部分代码,以提高可视性。如果我只运行下面的代码,它将按预期工作。我认为实际的代码库中存在问题。
@Flask关于处理未处理的诺言拒绝的建议为该问题增加了很大的价值。
请考虑以下测试:
import fileExists, { call } from "./exists";
describe( "file system", () => {
it( "should check if the file exists", async () => {
const received = await fileExists();
const expected = true;
expect( received ).toBe( expected );
});
});
适用于以下来源:
import fs, { constants } from "fs";
import { promisify } from "util";
export default async function fileExists() {
const path = ".nonexistent";
const access = promisify( fs.access );
try {
await access( path, constants.F_OK );
} catch {
return false;
}
return true;
}
当fileExists
拒绝返回false
时,将按预期接收到。但这无助于追踪失败测试的根源。UnhandledPromiseRejectionWarning
对于同步测试,Jest显示测试的路径(即file system › should check if the file exists
),这有助于跟踪失败的测试的来源。
实现异步测试的最佳方法是什么?
答案 0 :(得分:3)
UnhandledPromiseRejectionWarning
在这里不是预期的。它不等于失败的测试,因为它不会阻止断言通过时测试通过。这意味着代码编写方式错误,并且包含未链接的承诺。
只有在测试中省略await
时,它才会发生:
fileExists(); // no await
或者fileExists
函数包含未处理的宽松承诺:
fileExists() {
whatever() // no return
.then(() => {
whatever() // no return
}) // no catch to suppress errors
}
在setupFiles
中拥有一个好习惯:
process.on('unhandledRejection', console.error);
与UnhandledPromiseRejectionWarning
相比,它提供了更多有用的输出,并允许基于错误堆栈来调试问题。