必须使用 done 时:测试回调风格 API、未返回 Promise 的定时器或事件监听场景;需将 done 作为参数传入,并在异步完成处调用,否则导致超时或断言失效。

在 JavaScript 异步测试中,done 是 Jest、Jasmine 等测试框架提供的回调函数,用于显式告诉测试运行器:异步操作已完成,可以结束当前测试用例。不调用 done 或调用过早,都会导致测试超时或误判。
什么时候必须用 done
当你在测试中直接使用原生异步操作(如 setTimeout、Promise 手动 resolve/reject、XMLHttpRequest、Node.js 的 fs.readFile 等),且没有返回 Promise 时,就需要 done 来同步测试生命周期。
- 测试回调风格的 API(例如 Node.js 的
fs.readFile(path, callback)) - 测试未返回 Promise 的定时器逻辑(如
setTimeout(() => { ... }, 100)) - 测试事件监听 + 手动触发的场景(如
emitter.once('data', () => { ... }))
正确使用 done 的写法
把 done 作为测试函数的参数传入,并在异步操作的“最终完成位置”调用它。若出错,应调用 done.fail(error) 或 done(error)(取决于框架)来标记失败。
以 Jest 为例:
test('should fetch user data after delay', (done) => {
setTimeout(() => {
expect(1 + 1).toBe(2);
done(); // ✅ 正确:在异步逻辑末尾调用
}, 100);
});
<p>test('should handle async error', (done) => {
setTimeout(() => {
try {
throw new Error('Simulated failure');
} catch (err) {
expect(err.message).toBe('Simulated failure');
done(); // ✅ 错误已断言,仍需 done()
}
}, 50);
});
</p>
常见错误和避坑点
-
忘记调用
done()→ 测试超时(Jest 默认 5s),报 “Timeout - Async callback was not invoked…” -
调用
done()太早(比如放在setTimeout外层)→ 断言还没执行就结束,导致断言失效或未覆盖 -
多个
done()调用 → Jest 报 “Done callback called multiple times” -
混用
async/await和done→ 不要同时用,二者选其一。返回 Promise 时优先用async,更简洁安全
done vs return Promise:怎么选
现代测试推荐优先返回 Promise:
test('fetches user with async/await', async () => {
const user = await fetchUser();
expect(user.name).toBe('Alice');
}); // ✅ 自动等待 Promise,无需 done
<p>test('fetches user with Promise chain', () => {
return fetchUser().then(user => {
expect(user.name).toBe('Alice');
});
}); // ✅ 返回 Promise,Jest 自动处理
</p>
只有当无法返回 Promise(如老式回调 API)时,才用 done。它更底层、更灵活,但也更易出错。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











