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);
});
我试图在我的 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);
});