首页 > 解决方案 > 使用 Jest 测试预期会失败的 Promise

问题描述

我正在尝试使用 Jest 来测试一个返回承诺的函数。

函数 manyUrls 需要传递一个包含 JSON 数据的 URL 数组。获取这些 URL 的内容并以数组的形式返回。我正在测试传递有效 URL 字符串的情况。这会按预期抛出 TypeError,但我无法使用 Promise 为其编写测试(async/await 工作正常)

//index.js
const manyUrls = (urls) => {
  return Promise.all(urls.map(url => fetch(url)))
    .then(responses =>
      Promise.all(responses.map(res => res.json()))
    ).then(texts => {
      return Promise.resolve(texts)
    }).catch(error => {
      return Promise.reject(error)
    })
} 

//index.test.js
const manyUrls = require("./index")
const url = 'https://jsonplaceholder.typicode.com/todos/1'


test('Expect TypeError if a single string is passed', () => {
  // expect.assertions(1);
  // try {
  //   await manyUrls(url);
  // } catch (e) {
  //   expect(e).toBeInstanceOf(TypeError);
  // }


  return manyUrls(url).catch(e =>
    expect(e).toBeInstanceOf(TypeError)
  )
})

我已经注释掉了使用 async/await 成功通过该测试用例的代码位(如果我将 async 添加到回调中),但我正在尝试使用 Promise 来完成这项工作。我遵循了https://jestjs.io/docs/asynchronous上的文档,但似乎无法通过该测试。有谁知道为什么?

提前致谢,

标签: javascriptasynchronoustestingjestjs

解决方案


如果你的函数返回一个 Promise,你的代码就可以正常工作 -但当return manyUrls(url)...参数不是数组时它不会。manyUrlsurls

返回 Promise 并以 Error 拒绝的函数与抛出 Error 的函数之间存在很大差异。通过return在您的测试中使用,您告诉 Jest 您的功能是前者,而实际上您的功能是后者。

manyUrls第一行中,return Promise.all(urls.map(url => fetch(url)))尝试调用urls.maps但在不是数组时抛出错误urls(如在测试用例中)。在抛出错误时,不会返回任何 Promise。

您的 try/catch 实现有效,因为它捕获了manyUrls抛出的错误。如果您希望return实现工作,则manyUrls必须返回一个拒绝的 Promise。

更新manyUrls始终返回 Promise 的最简单方法是添加async关键字 - 就像在const manyUrls = async (urls) => {. 通过将其设为异步函数,任何抛出的错误manyUrls都将自动转换为返回的 Promise 的拒绝值。请参阅:https ://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function#return_value


推荐阅读