1

最近只是使用 Mock Service Worker 来测试我的 HTTP 请求,我正在寻找测试我的失败路径。

我的第一个测试通过(很高兴),但我收到的失败错误是“JSON 输入意外结束”

它确实以我想要的方式运行,但从测试的角度来看,我有点困惑。

我怎样才能让我的失败路径通过测试?

我的测试文件

import "whatwg-fetch";
import { rest } from "msw";
import { setupServer } from "msw/node";

import { collect } from "./collect";

const server = setupServer(
  rest.get(
    "http://api.openweathermap.org/data/2.5/weather",
    (req, res, ctx) => {
      return res(
        ctx.status(200),
        ctx.json({ base: "stations", clouds: { all: 6 }, cod: 200 })
      );
    }
  )
);

beforeAll(() => server.listen());
afterAll(() => server.close());
afterEach(() => server.resetHandlers());

it("collects data", async () => {
  const res = await collect();
  expect(res).toEqual({ base: "stations", clouds: { all: 6 }, cod: 200 });
});

it("handles failure", async () => {
  server.use(
    rest.get(
      "http://api.openweathermap.org/data/2.5/weather",
      (req, res, ctx) => {
        return res(ctx.status(401));
      }
    )
  );
  await expect(collect()).rejects.toThrow("401");
});

我的 fetch 异步功能

require('dotenv').config()

export const collect = async () => {
    const key = process.env.REACT_APP_API_KE
    // try{
      const res = await fetch(`http://api.openweathermap.org/data/2.5/weather?q=london&appid=${key}`)
      if(res.status !== 200){
        const error = await res.json()
        throw { message: error.message, status: error.cod }
      }
        const data = await res.json()
        return data 
}
4

2 回答 2

0

修复模拟服务器

问题是collect即使发生错误,该函数也需要 JSON 响应,但您的模拟服务器不会返回该响应。因此,当您res.json()collect函数中执行此操作时,会出现错误。

更新您的响应解析器以返回json响应。

return res(ctx.json({message: "error"}), ctx.status(401));

修复测试

toThrow这里不是正确的匹配器,因为async函数总是返回承诺,在你的情况下,collect函数返回一个被抛出的数据拒绝的承诺。
因此,您可以改用toEqual匹配器。

您还需要更新测试错误的方式。您可以选择以下任何选项:

使用rejects匹配器:

it("handles failure", () => {
  server.use(
    rest.get(
      "http://api.openweathermap.org/data/2.5/weather",
      (req, res, ctx) => {
        return res(ctx.json({message: "error"}), ctx.status(401));
      }
    )
  );
  return expect(collect()).rejects.toEqual({ message: "error", status: 401 });
});

使用async/await语法:

it("handles failure", async () => {
  server.use(
    rest.get(
      "http://api.openweathermap.org/data/2.5/weather",
      (req, res, ctx) => {
        return res(ctx.status(401));
      }
    )
  );
  try {
    await collect();
  } catch (err) {
    expect(err).toEqual({ message: "error", status: 401 });
  }
});

使用.catch

但是在这种方法中,您需要明确检查您的catch断言是否已被调用,否则已实现的承诺不会使您的测试失败。

it("handles failure", async () => {
  server.use(
    rest.get(
      "http://api.openweathermap.org/data/2.5/weather",
      (req, res, ctx) => {
        return res(ctx.status(401));
      }
    )
  );
  expect.assertions(1);
  return collect().catch((err) =>
    expect(err).toEqual({ message: "error", status: 401 })
  );
});

修复collect功能

在你的collect函数中status应该是res.status而不是data.code

res.json()您还可以通过将调用移出条件来稍微清理以下代码。

require("dotenv").config();

export const collect = async () => {
  const key = process.env.REACT_APP_API_KEY;
  const res = await fetch(
    `http://api.openweathermap.org/data/2.5/weather?q=london&appid=${key}`
  );
  const data = await res.json();
  if (res.status !== 200) {
    throw { message: data.message, status: res.status };
  }
  return data;
};

而且你不应该在反应环境变量中存储秘密,这会暴露。文档 在此处输入图像描述

于 2022-01-13T16:20:35.510 回答
0

在一些帮助下,我更新了我的收集功能,所以它是以下我现在将响应的值作为状态发送

require("dotenv").config();

export const collect = async () => {
  const key = process.env.REACT_APP_API_KEY;
  const res = await fetch(
    `http://api.openweathermap.org/data/2.5/weather?q=london&appid=${key}`
  );
  const data = await res.json();
  if (res.status !== 200) {
    throw { message: data.message, status: res.status };
  }
  return data;
};

我的测试现在看起来像这样,我必须使用 toEqual 匹配器而不是 toThrow 并让它返回而不是 await / async

it("handles failure", () => {
  server.use(
    rest.get(
      "http://api.openweathermap.org/data/2.5/weather",
      (req, res, ctx) => {
        return res(ctx.json({message: "error"}), ctx.status(401));
      }
    )
  );
  return expect(collect()).rejects.toEqual({ message: "error", status: 401 });
});
于 2022-01-14T16:25:59.650 回答