Jest 和 HTTP mocking with nock

Jest and HTTP mocking with nock

我试图在我的 Next.js 应用程序中为端点编写我的第一个 Jest 测试,并且这个测试总是通过,无论我如何尝试 'break' 它。这让我觉得,我做错了。这是我的 api/weather.js 端点:

const url = (city) => `https://api.weatherapi.com/v1/current.json?key=${process.env.WEATHER_API_KEY}&q=${city}`;
export default async function handler(req, res) {
 const { query: { city } } = req
  return fetch(url(city))
    .then((response) => {
      if(response.ok){
        return response.json()
      }
      throw new Error('Response not OK')
    })
    .then((data) => res.status(200).json(data))
    .catch(() => res.status(400).json({message: 'Currently not avaliable'}))
}

所以基本上我的前端向 api/weather 发送了一个看起来有点像

的请求
const fetchCityData = () => {
    const options = {
      method: `POST`,
    };
    fetch(`/api/weather?city=${city}`, options)
    .then((response) => { ......

我有一个测试端点的任务,据我所知应该测试 api/weather.js,因为这取决于外部 API 我需要模拟请求。我在这里仍然有点迷路。另外,我使用查询字符串,我试图将其集成到我的笑话测试中,但不太确定我在做什么

import nock from 'nock';
it('should return weather', () => {
    nock('https://api.weatherapi.com/v1')
    .get(`/current.json?key=123434&q=London`)
    .reply(200, { results: [{ temp_c: '18 degrees' }] })
});

基本上 'real life' 中发生的事情是我在前端的输入中输入一个城市,该城市被发布到 api/weather.js 然后它将 return 天气为了这个城市。我如何测试它?我已经读了 3 天有关 nock 和 jest 的文章,但我真的不明白它背后的概念。此外,如果我将测试中的 .reply 重写为 400 或重写结果,测试仍然会通过。为什么?我做错了什么?

您传递给 nock 的 .reply 的第二个参数将创建一个拦截器,该拦截器将更改请求持续到您为其设置的主机的时间。这意味着通过这样做:

    it('should return weather', () => {
       nock('https://api.weatherapi.com/v1')
       .get(`/current.json?key=123434&q=London`)
       .reply(200, { results: [{ temp_c: '18 degrees' }] })
    });

下一个获取调用将return一个由它组成的对象:

   const { results } = await fetchCityData("London");
   expect(results[0].temp_c).toEqual("19 degrees");

那会过去的。这不会:

    const { results } = await fetchCityData("London");
    expect(results[0].temp_c).toEqual("33 degrees");
   Expected: "33 degrees"
   Received: "19 degrees"

然后由您决定使用您想要从 WeatherAPI 模拟的所有数据来完全模拟适当的请求,例如:

[...]
 {
      location: {
        name: 'London',
        region: 'City of London, Greater London',
        country: 'United Kingdom',
        lat: 51.52,
        lon: -0.11,
        tz_id: 'Europe/London',
        localtime_epoch: 1631181607,
        localtime: '2021-09-09 11:00'
      },
      current: {
[...]

或试验 Nock's recording 选项,这些选项允许您在您希望的地方来回抓取数据。

这是 dominicfraser/NockExamples 上的一个很好的示例,它将涵盖一些可能对您有用的用例并提供一些指导,然后从那里开始!

编辑 1: 下面是一些代码,希望能澄清一些问题:

import nock from "nock";
const fetch = require('node-fetch');

const SERVER_HOST = 'http://localhost:3000';

// from WeatherApi.com
const londonMock = {"location":{"name":"London","region":"City of London, Greater London","country":"United Kingdom",
"lat":51.52,"lon":-0.11,"tz_id":"Europe/London","localtime_epoch":1631195008,
"localtime":"2021-09-09 14:43"},"current":{"last_updated_epoch":
1631194200,"last_updated":"2021-09-09 14:30","temp_c":23,"temp_f":73.4,"is_day":1,
"condition":{"text":"Partly cloudy","icon":"//cdn.weatherapi.com/weather/64x64/day/116.png","code":1003},
"wind_mph":11.9,"wind_kph":19.1,"wind_degree":210,"wind_dir":"SSW","pressure_mb":1008,
"pressure_in":29.77,"precip_mm":0,"precip_in":0,"humidity":69,"cloud":75,"feelslike_c":25,
"feelslike_f":77,"vis_km":10,"vis_miles":6,"uv":5,"gust_mph":9.6,"gust_kph":15.5}};

const fetchCityData = async (city) => {
  const options = {
    method: `GET`,
  };
  const response = await fetch(`${SERVER_HOST}/api/weather?city=${city}`, options);
  const data = await response.json();
  return data;
}

it("checks if London's weather equals to 33 degrees on a mocked response", async () => {
    nock(SERVER_HOST)
      .get(`/api/weather?city=London`)
      .reply(200, londonMock);
    const results = await fetchCityData("London");
    expect(results.current.temp_c).toEqual(33);
});

it("checks if London's weather equals to 23 degrees on a mocked response", async () => {
    nock(SERVER_HOST)
      .get(`/api/weather?city=London`)
      .reply(200, londonMock);
    const results = await fetchCityData("London");
    expect(results.current.temp_c).toEqual(23);
});