【问题标题】:npm test doesn't catch errors thrown inside async functionnpm test 不会捕获异步函数中抛出的错误
【发布时间】:2017-06-27 10:31:47
【问题描述】:

我目前正在为我的项目编写一些测试脚本。代码用 ES7 编写,编译使用babel


先介绍一下背景:

假设您运行npm test,测试文件如下所示:

function foo (bar) {
  if (!bar) throw new Error('foooo')
  console.log(bar)
}
foo() // No argument given

现在,当您运行此脚本时,npm 将向您显示如下错误:

$ npm ERR! Test failed.  See above for more details.

这是想要的输出,出了点问题,你还不想发布这个软件,因为那里有错误。

那么我的问题是什么?


好吧,我有一个这样的测试脚本设置:

async function init () {
  const status = await someRequestPromise()
  if (status.error) throw status.error
  console.log(status.result) // Log the result of this async request...
}
init()

为了首先运行我的测试,我使用 babel 编译 ES7,如下所示:

$ babel src -d dist

然后运行npm test


结果

需要明确的是,npm 并没有触发错误...

我也尝试了以下代码,但这并没有改变任何东西......

async function init () {
  const status = await someRequestPromise()
  if (status.error) throw status.error
  console.log(status.result) // Log the result of this async request...
} 

try {
  init()
} catch (e) {
  console.log(e)
}

我想知道如何触发 npm 来捕获错误并报告测试失败的事实。另外我想知道如何捕获错误,因为节点现在将它们标记为未处理,即使使用 try catch 块也是如此。

PS。在init()函数前面添加await语句会导致语法错误,请不要这样做。

【问题讨论】:

标签: javascript node.js npm async-await babeljs


【解决方案1】:

由于async/await 返回承诺,您必须通过.catch 处理拒绝(正如控制台输出所示):

const handle = init()
handle
  .then((result) => handleSuccess(result))
  .catch(({message}) => console.log(message))

try/catch(至少,根据我的经验)用于同步代码。

编辑:

要使脚本“崩溃”,您只需添加process.exit(1)

const handle = init()
handle
  .then((result) => handleSuccess(result))
  .catch(({message}) => {
     console.log(message)
     process.exit(1)
   })

【讨论】:

  • 我会调查的。虽然try/catch 阻止了与 async/await 组合的最佳实践
  • 是的,如果您在异步函数内部而不是外部处理错误——就像它的前身ES6生成器一样。那有意义吗?另外,您在哪里找到有关try/catch 的信息?
  • 信息是基于我自己的记忆哈哈。有一天在某处读到它...(我会快速测试.catch() 方法)
  • 好吧,是的,虽然这是处理任何错误的理想方式,但它仍然不是让 npm 真正捕捉到程序失败的事实的有效方式。您正在处理错误,因此它是预期的......脚本不会崩溃。
  • 只需在catch 部分添加process.exit(1)
【解决方案2】:

晚了几年,但我相信一种正确的方法(没有顶级等待)是将 try catch 移到“init”函数中

async function init () {
  // Try / catch with async / await is basically syntactic sugar for resolve() / reject() 
  try {
    // This async call MUST use await or the promise will not resolve here, 
    // and thus the try / catch wrapping the async call will not trigger
    const status = await someRequestPromise() 
    
    if (status.error) {
      // Throw to reject the promise returned from init()
      throw status.error
    }

    // Log the success of this async request
    console.log(status.result) 
  // Catch your error to do logging.
  } catch (e) {
    // Log the failure of this async request
    console.log(e) 

    // Rethrow to return the promise as rejected (with result as the error object)
    // If you do not rethrow, the promise from init() will return as resolved
    throw e 
  }
  // Return the promise from init() as fulfilled (with result as void)
} 

// Use a thenable to initiate the promise chain at the top level
init().then();

cmets 可能不是 100% 准确,但它正在努力传达这个想法。

基本上,try catch 可用于解决或拒绝承诺,但前提是承诺在 try/catch 中的某处等待

【讨论】:

    猜你喜欢
    • 2017-10-23
    • 1970-01-01
    • 1970-01-01
    • 2020-09-28
    • 1970-01-01
    • 1970-01-01
    • 2015-04-16
    • 1970-01-01
    • 2018-08-09
    相关资源
    最近更新 更多