js异步测试高频报错需理解机制:1. “uncaught (in promise)”因promise未捕获异常;2. “timeout”因done未调用或逻辑中断;3. “expected…tothrow”因断言未await;4. “cannot read property”因promise链返回值错误或未return。

记住 JS 异步代码测试的常见报错,关键不是死记硬背错误字符串,而是理解错误背后的执行机制和触发条件。下面几个高频报错,按“现象—原因—验证方式”结构整理,帮你形成条件反射式的判断能力。
Uncaught (in promise) TypeError / ReferenceError
这是测试中出现频率最高的异步错误提示,说明 Promise 内部抛出了未被处理的异常,且没有被任何 .catch() 或 try/catch 捕获。
- 典型场景:在 Jest 测试里用了
await fn(),但fn内部抛错,又没写try/catch;或用了.then()链却漏了第二个参数或.catch() - 注意:Jest 默认会将未捕获的 Promise rejection 视为测试失败,并打印这个警告,即使你写了
expect(...).rejects.toThrow(),也要确保该 Promise 真正被 await 或返回给测试函数 - 快速验证:在测试代码末尾加一句
await Promise.resolve(),看警告是否消失——如果消失了,说明前面某个 Promise 被“放养”了
Timeout - Async callback was not invoked within the 5000 ms timeout
Jest 默认 5 秒超时,报这个错,代表你声明了异步测试(比如用了 done 回调),但没调用它,或异步逻辑根本没走到那里。
- 常见于老式写法:
test('xxx', (done) => { setTimeout(() => { expect(...); done(); }, 100); });,但实际逻辑出错、提前 return 或抛错,导致done()永远不执行 - 更安全的做法是统一用
async/await,避免手动管理done - 如果必须用
done,建议在setTimeout外层包try/catch,并在 catch 里调用done.fail(e)
Expected the result of calling `toThrow` to be a function
这是 Jest 断言写错了的典型提示,说明你把一个已经执行完的 Promise(比如 fn())直接传给了 expect().toThrow(),而不是传函数引用。
- 错误写法:
expect(myAsyncFn()).rejects.toThrow('xxx')—— 这里myAsyncFn()立即执行并返回 Promise,但expect().rejects要求你传的是 Promise 实例本身 - 正确写法:
await expect(myAsyncFn()).rejects.toThrow('xxx')(推荐),或return expect(myAsyncFn()).rejects.toThrow('xxx') - 小技巧:只要看到
toThrow、toThrowError出现在异步断言里,先检查前面有没有await或return
TypeError: Cannot read property 'xxx' of undefined(发生在 .then() 里)
表面是访问了 undefined 的属性,根源往往是 Promise 链中前一步 resolve 的值不是预期类型,或者忘了 return 导致链中断。
- 典型陷阱:
promise.then(res => { console.log(res); }) // 忘了 return res→ 下一个.then收到的是undefined - 测试中尤其容易忽略:mock 返回值写错(比如 mock 返回
{ data: xxx },但代码里直接解构const { items } = res) - 调试建议:在每个
.then开头加console.log('res:', res),或用await+console.log分段验证











