Jest mocking axios's request method giving error - jestjs

I am trying to mock the axios's request method. But it throwing error
it('should execute axios request method once', async () => {
jest.mock('axios');
axios.request.mockImplementation(() =>
Promise.resolve({
data: {}
})
);
const requestObj = {
method: 'GET',
url: 'http://mock.url',
headers: {}
};
await request(requestObj);
expect(axios.request).toHaveBeenCalledTimes(1);
});
request.js
export default async (request, httpService = axios) => {
const { method, data, headers } = request;
let { url } = request;
const token = getLocalstorage('token');
if (token) {
headers.token = token;
}
if (method === 'GET') {
if (data) {
url += `?${serialize(data)}`;
}
}
return httpService
.request({
method,
url,
headers: Object.assign({}, headers),
...(method !== 'GET' && { data })
})
.then(successResponse, error => {
throwHttpError(error);
});
};
error

Here is the solution based on:
"jest": "^24.8.0",
"ts-jest": "^24.0.2",
"typescript": "^3.5.3"
"axios": "^0.19.0",
request.ts:
import axios from 'axios';
const serialize = data => data;
const getLocalstorage = key => key;
const successResponse = () => console.log('successResponse');
const throwHttpError = error => new Error(error);
export default async (request, httpService = axios) => {
const { method, data, headers } = request;
let { url } = request;
const token = getLocalstorage('token');
if (token) {
headers.token = token;
}
if (method === 'GET') {
if (data) {
url += `?${serialize(data)}`;
}
}
return httpService
.request({
method,
url,
headers: Object.assign({}, headers),
...(method !== 'GET' && { data })
})
.then(successResponse, error => {
throwHttpError(error);
});
};
Unit test, request.spec.ts
import request from './request';
import axios from 'axios';
jest.mock('axios');
describe('request', () => {
it('should execute axios request method once', async () => {
(axios.request as jest.Mock<any, any>).mockResolvedValueOnce({ data: 'mocked data' });
const requestObj = {
method: 'GET',
url: 'http://mock.url',
headers: {}
};
await request(requestObj);
expect(axios.request).toHaveBeenCalledTimes(1);
});
});
Unit test result:
PASS src/stackoverflow/57353897/request.spec.ts
request
✓ should execute axios request method once (13ms)
console.log src/stackoverflow/57353897/request.ts:4
successResponse
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 2.637s, estimated 3s

Related

how to set headers in axios patch request in react js

Can someone tell me what mistake I am making or tell me how to set the header in axios patch request. when I am running the API through postman, everything is working fine but when I connect it with the front end, an error comes up saying that the JWT is not provided on the backend
here is the frond end code :
import React, { useEffect } from 'react';
import { useParams } from 'react-router';
import axios from 'axios';
const Loader = () => {
const parmas = useParams();
const { id } = parmas;
console.log(id);
useEffect(() => {
const fetchBags = async () => {
try {
const res = await axios.patch('http://localhost:4001/public/verify', {
headers: {
'Content-Type': 'application/json',
Token: id,
},
});
console.log(res);
console.log('CBM', { res });
} catch (error) {
console.log(error);
}
};
fetchBags();
}, []);
return <div>this is loader</div>;
};
export default Loader;
below is my backend code:
export const verifyUser = async (data) => {
const token1 = data.header("Token");
try {
const verified = jwt.verify(token1, getTokenSecret());
console.log(verified)
await userModel.verifyUser(verified);
return {
message: "success",
};
} catch (error) {
console.log(`Auth Service > verifyUser > ${error.toString()}`);
throw error;
}
};
this error is comming:
Error
From docs
axios.patch(url[, data[, config]])
As you can see you pass config in 3rd argument not 2nd.
const res = await axios.patch(
'http://localhost:4001/public/verify',
{}, // data (2nd argument)
{
headers: {
'Content-Type': 'application/json',
Token: id,
},
} // config (3rd argument)
)

Jest error: Type error: res.status is not a function

I'm using a middleware to verify token with this code:
import { Request, Response, NextFunction } from "express";
import jwt from "jsonwebtoken";
class VerifyToken {
public verify(req: Request, res: Response, next: NextFunction) {
try {
const authHeader = req.headers["authorization"];
const token = authHeader?.split(" ")[1];
const signature = process.env.JWT_SIGNATURE;
jwt.verify(token, signature);
next();
} catch (error) {
return res.status(401).json("Acess denied");
}
}
}
export default new VerifyToken().verify;
I'm using Jest to test this middleware, here's the code:
import dotenv from "dotenv";
import { NextFunction, Request, Response } from "express";
import verifyToken from "../../src/middlewares/verifyToken";
describe("Verify token", () => {
let mockRequest: Partial<Request>;
let mockResponse: Partial<Response>;
let nextFunction: NextFunction = jest.fn();
beforeAll(() => {
dotenv.config({ path: ".env" });
});
beforeEach(() => {
mockRequest = {};
mockResponse = {
json: jest.fn(),
};
});
it("should verify token with a invalid token", () => {
const token = process.env.TEST_FALSE_TOKEN;
mockRequest = {
headers: {
authorization: `bearer ${token}`,
},
};
verifyToken(mockRequest as Request, mockResponse as Response, nextFunction);
expect(mockResponse.status).toBe(401);
});
it("should verify token with a valid token", () => {
const token = process.env.TEST_TOKEN;
mockRequest = {
headers: {
authorization: `bearer ${token}`,
},
};
verifyToken(mockRequest as Request, mockResponse as Response, nextFunction);
expect(nextFunction).toBeCalledTimes(1);
});
});
When I run a test using Jest, it shows the following error:
TypeError: res.status is not a function
I've already tried to use ErrorRequestHandler with the request but I get the same error.
How can I fix this? Thanks for the help.
Your mocked response doesn't have a status function on it..
mockResponse = {
json: jest.fn(),
status: jest.fn().mockReturnThis(),
};

Why is react not posting res.json() to console?

I have tried so many thing but my react app is not recieving jsonData variable or res as a return from the node app. The app is working and printing to console on the node side but I can't get it to print onto the react side.
const submitForm = async (event) => {
event.preventDefault(); // Prevent default submission
const data2 = document.getElementById("miles").value;
const data =
"passenger_vehicle-vehicle_type_" +
carType +
"-fuel_source_" +
vehicleType +
"-engine_size_na-vehicle_age_na-vehicle_weight_na";
axios
.post(`http://localhost:8000/api/vehicle/`, { data, data2 })
.then((res) => {
const returnText = res.json();
console.log(returnText);
return res.json();
})
.then((jsonData) => {
console.log(jsonData);
return;
})
.catch((error) => {
console.log("got errr while posting data", error);
});
};
I edited out the api and api key.
var fetch = require('node-fetch');
exports.vehicle = (req, res) =>{
let status;
const { data, data2 } = res.body;
const values = {
"emission_factor": data,
"parameters": {
"distance": parseInt(data2),
"distance_unit": "mi",
},
};
fetch('https://AAAAAAAAAAAAAAAA', {
method: 'POST',
headers: {
'Authorization': 'Bearer MYAPIKEY',
'Content-Type': 'application/json'
},
body: JSON.stringify(values)
})
.then((res) => {
status = res.status;
return res.json()
})
.then((jsonData) => {
console.log(jsonData);
console.log(status);
return jsonData
})
.catch((err) => {
// handle error
console.error(err);
});
res.send(req.body);
}
Working code thanks for the help:
const submitForm = async (event) => {
event.preventDefault(); // Prevent default submission
const data2 = document.getElementById("miles").value;
const data =
"passenger_vehicle-vehicle_type_" +
carType +
"-fuel_source_" +
vehicleType +
"-engine_size_na-vehicle_age_na-vehicle_weight_na";
axios
.post(`http://localhost:8000/api/vehicle/`, { data, data2 })
.then((res) => {
console.log(res.data);
return;
})
.catch((error) => {
console.log("got err while posting data", error);
});
};
Node solution in comments.
The functions inside your then() statements need to return data e.g. then((res) => {return res.json()})
You have two problems here...
Client-side, you seem to be mixing up an Axios response with a fetch() Response. You want res.data, not res.json(). Since you've tagged this with reactjs, here is where you would set the data to a state value, eg
axios.post(...).then(res => {
setSomeState(res.data)
})
Server-side, you aren't waiting for your fetch request to complete. I'd recommend using an async function
exports.vehicle = async (req, res) => {
try {
const { data, data2 } = req.body
const values = {
"emission_factor": data,
"parameters": {
"distance": parseInt(data2),
"distance_unit": "mi",
},
}
// don't mix up the Express "res" with the fetch "response"
const response = await fetch('https://AAAAAAAAAAAAAAAA', {
method: 'POST',
headers: {
'Authorization': 'Bearer MYAPIKEY',
'Content-Type': 'application/json'
},
body: JSON.stringify(values)
})
if (!response.ok) {
throw new Error(`${response.status}: ${await response.text()}`)
}
res.json(await response.json()) // respond with the data
} catch (err) {
console.error(err)
res.status(500).send(err)
}
}

i'm getting isssue while calling API in Useeffect in reactJs

I'm calling two methods in useeffect but when api1 get called it get executed till await axios.put and then api2 get called without getting the response from api1. And after getting a reponse from api2 it goes to api1 reponse and gets a reponse as undefined
useEffect(() => {
api1();
api2();
}, [])
const api1 = async () => {
try {
var requestModel = JSON.stringify({ UserId: userid, MenuName: menuname });
var requestBody = security.encrypt(requestModel);
axios.myHashData = security.computedHmac256(requestBody);
var config = { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } }
await axios.put(axios.controllername + 'methodname', requestBody, config, { withCredentials: true })
.then(response => {
if (response.status === 200) {
//setapidata(response.data);
}
});
} catch (error) {
console.error(error.message)
}
}
const api2= async () => {
try {
var requestModel = JSON.stringify({ UserID: userid });
var requestBody = security.encrypt(requestModel);
axios.myHashData = security.computedHmac256(requestBody);
var config = { headers: { 'Content-Type': 'application/json', 'Access-Control-Allow-Origin': '*' } }
await axios.post(axios.controllername + 'methodname', requestBody, config, { withCredentials: true })
.then(response => {
if (response.status === 200) {
setapidata(response.data);
GetApis();
}
});
} catch (error) {
console.error(error.message)
}
}
If you want to wait for the api1 to execute before api2 is called you need to change the code for useEffect as below
useEffect(async() => {
await api1();
await api2();
}, [])
or
useEffect(() => {
api1().then(() => api2());
}, [])
To handle errors properly use try-catch block inside the useEffect if using await or use catch block if using .then
Also, another suggestion, if you are using a function inside useEffect make sure either the function is defined inside the same useEffect block or it is memorized either via useCallback or useMemo

mockResolvedValue returns undefined

I want to test the function below using the tests below. However, I fail in mocking the userService.login function, which always returns undefined instead of desired value. I have tried these approaches https://jestjs.io/docs/mock-functions#mock-return-values (please see the tests), but nothing seems to work.
FUNCTION
static async login(req: Request, res: Response, next: NextFunction): Promise<void> {
const userDTO = req.body;
try {
const accessToken = await userService.login(userDTO);
// accessToken is undefined here :(
res.setHeader('authorisation', `Bearer ${accessToken}`);
res.send('Logged in');
} catch (e) {
// eslint-disable-next-line callback-return
next(e);
}
}
TESTS:
import UserService from '#services/users.service';
import UserController from '#routers/controller/users.controller';
import { NextFunction, Request, Response } from 'express';
import UserRepository from '#data-access/user.repository';
jest.mock('#services/users.service');
let userService: UserService;
const fakeToken = 's$sdfDgf45d';
beforeAll(() => {
userService = new UserService(UserRepository);
// userService.login = jest.fn().mockResolvedValue('s$sdfDgf45d').mockRejectedValue('error');
});
describe('UserController: ', () => {
const mockReq = {
body: {
login: 'Artyom',
password: 'qwerty123'
}
};
const mockRes = {
setHeader: jest.fn(),
send: jest.fn()
};
const nextFunction = jest.fn();
test('the class constructor should have been called', () => {
expect(UserService).toHaveBeenCalled();
});
test('should send auth token in case of success scenario', async () => {
// #ts-ignore
userService.login.mockResolvedValue('s$sdfDgf45d').mockRejectedValue('error');
// jest.spyOn(userService, 'login').mockResolvedValue('s$sdfDgf45d' as any).mockRejectedValue('error');
await UserController.login(mockReq as Request, mockRes as any as Response, nextFunction as NextFunction);
// that's the test that fails
expect(mockRes.setHeader.mock.calls[0]).toEqual(['authorisation', `Bearer ${fakeToken}`]);
expect(mockRes.send.mock.calls[0][0]).toEqual('Logged in');
});
test('should throw an error', async () => {
return expect((userService.login as jest.Mock)()).rejects.toMatch('error');
});
});
ERROR:
Array [
"authorisation",
- "Bearer s$sdfDgf45d",
+ "Bearer undefined",
CODE:
https://github.com/lion9/node-express

Resources