【问题标题】:JavaScript (ES6) and fetch(): How can I throw an error so that catch triggers? (Testing it with Jest)JavaScript (ES6) 和 fetch():如何抛出错误以触发 catch? (用 Jest 测试它)
【发布时间】:2018-12-21 13:11:17
【问题描述】:

直到现在我都认为自己在 JavaScript 方面表现不错。我想为我的 HTTP 请求编写一个辅助函数。我用 Jest 测试了它。问题是catch() 部分没有被触发。让我先给你测试一下:

it("recognizes when a response's status is not okay", () => {
  fetch.mockResponseOnce(JSON.stringify({ ok: false }));

  expect.assertions(1);

  return getRequestWithoutHeader(fullTestUrl).catch(err => {
    expect(err.ok).toEqual(false);
  });
});

也许测试写错了导致失败。不管怎样,这里是我写的辅助函数。我尝试了不同的实现,但都没有通过测试:

// Implementation one: with throw
export const getRequestWithoutHeader = fullUrlRoute =>
  fetch(fullUrlRoute).then(response =>
    response.json().then(json => {
      if (!response.ok) {
        throw Error(json);
      }
      return json;
    }, error => error)
  );

// Implementation two: with throw new
export const getRequestWithoutHeader = fullUrlRoute =>
  fetch(fullUrlRoute).then(response =>
    response.json().then(json => {
      if (!response.ok) {
        throw new Error(json);
      }
      return json;
    }, error => error)
  );

// Implementation three: With Promise.reject
export const getRequestWithoutHeader = fullUrlRoute =>
  fetch(fullUrlRoute).then(response =>
    response.json().then(json => {
      if (!response.ok) {
        return Promise.reject(json);
      }
      return json;
    }, error => error)
  );

// Implementation four: with new Promise
export const getRequestWithoutHeader = fullUrlRoute =>
  new Promise((resolve, reject) => {
    fetch(fullUrlRoute).then(response =>
      response.json().then(
        json => {
          if (!response.ok) {
            reject(json);
          }
          resolve(json);
        },
        error => reject(error)
      )
    );
  });

这些都不起作用。其中一些将在测试中使用then 返回,但我希望能够抛出承诺。我想触发捕获。

我该如何编写这个辅助函数?

【问题讨论】:

  • 您应该在response 上调用.json() 之前检查ok。 (另外,最好不要嵌套这样的 Promise ——这就是 Promise-as-callback 反模式)
  • @CertainPerformance 您能否提供一个代码示例?我现在尝试这样做:codepen.io/anon/pen/Zjbbpb 仍然失败。
  • 你不想要嵌套的.then(json => json);(如果你想用它做点什么,把它放在一个外部的.then中)。你也不想catchgetRequestWithoutHeader 里面的错误,否则它会返回一个resolved Promise(不会被你的测试捕获)
  • @CertainPerformance 嗯,我仍然无法让它工作。我现在是这样实现的:codepen.io/anon/pen/Zjbbpb 对不起,我学得太难了。非常感谢您的耐心和帮助!
  • 是的,现在看起来不错!不幸的是,我没有使用 Jest 的经验,所以如果该代码不起作用,我不知道修复它的下一步是什么

标签: javascript ecmascript-6 fetch jestjs es6-promise


【解决方案1】:

你可以这样试试

  fetch(fullUrlRoute)
  .then(response =>{
      if (response.ok) {
        return response.json();
      }
      else throw response
  })
  .then(json=> {
      console.log(json);
    })
  .catch(error =>{
      console.log(error)
   });

希望对你有所帮助

【讨论】:

  • 这基本上是我的实现二,只是它不起作用,因为按照您的嵌套方式,response 在签入!response.ok 时未定义。
  • 尝试在 .then(response =>{console.log(response)}) 获取之后打印 console.log(response)
  • 如果你没有得到任何回应,那么你做错了。访问developer.mozilla.org/en-US/docs/Web/API/Fetch_API/Using_Fetch
【解决方案2】:

这就是我最终不得不做的事情:

我使用jest-fetch-mock 来模拟请求。

为了正确拒绝承诺,我必须覆盖 mockResponseOnce 函数的 init 参数。

这是测试的结果:

  it("recognizes when a response's status is not okay", () => {
    fetch.mockResponseOnce(JSON.stringify({ someResponse: "someResponse" }), { status: 403 });
    expect.assertions(1);

    return getRequestWithHeader(fullTestUrl, article).catch(err => {
      expect(err.someResponse).toEqual("someResponse");
    });
  });

通过显式设置状态,它会自动在响应中设置ok: false,从而触发函数。

我还应用了CertainPerfomance's 提示,并像这样重构了函数:

export const getRequestWithoutHeader = fullUrlRoute =>
  fetch(fullUrlRoute)
    .then(response => {
      if (!response.ok) {
        return Promise.reject(response);
      }
      return response.json();
    })

【讨论】:

    猜你喜欢
    • 2017-10-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-07
    • 2020-10-22
    • 1970-01-01
    • 2019-07-12
    • 1970-01-01
    相关资源
    最近更新 更多