How to thrown error in catch block using sinon stub - node.js

I am using mocha and sinon for test the node services, In controller I have getToken npm module for getting the token with name and value as parameters and in spec file I trying to send empty name as parameter using withargs but the response getting success excepted result is token creating fail please help on this issue.
controller.ts
import {getToken} from './tokenUtil';
export async function userInfo(req:Request,res:Response){
try{
let token = await getToken(name,value);
}
catch(error){
res.send({status:'Failue',message:error});
return
}
res.send({status:'success',message:'token creation success'})
}
tokenUtil.ts
export async function getToken(name,value){
// token code here
}
token.spce.ts
import * as sinon from 'sinon';
import * as proxyquire from 'proxyquire';
describe('get token',()=>{
let req:any;
let res:any;
beforeEach(()=>{
res={
send:sinon.stub();
}
it('getting error when given empty name',async()=>{
let tokenStub = sinon.stub().withArgs('',tokenValue).returns(undefined);
let tokenctl=proxyquire('./controller',{
'./tokenUtil':tokenStub
})
await tokenctl.userInfo(req,res);
sinon.assert.calledWithExactly(res.send,{status:'Failue',message:'token creating fail'})
})
})
})

You are testing the controller.ts module, so the test file name should be controller.spec.ts or controller.test.ts.
Since the ./tokenUtil use named exports, so the tokenStub should be an object.
You should use sinon.stub().rejects() to create a promise stub with rejected value.
E.g.
controller.ts:
import { getToken } from './tokenUtil';
import { Request, Response } from 'express';
export async function userInfo(req: Request, res: Response) {
const { name, value } = req.body;
try {
let token = await getToken(name, value);
res.send({ status: 'success', message: 'token creation success' });
} catch (error) {
res.send({ status: 'Failue', message: error });
}
}
tokenUtil.ts:
export async function getToken(name, value) {
// token code here
}
controller.test.ts:
import sinon from 'sinon';
import proxyquire from 'proxyquire';
describe('get token', () => {
let req: any;
let res: any;
beforeEach(() => {
res = {
send: sinon.stub(),
};
});
it('should create token success', async () => {
req = { body: { value: '123', name: 'teresa teng' } };
let tokenStub = {
getToken: sinon.stub().withArgs(req.body.name, req.body.value).resolves(),
};
let tokenctl = proxyquire('./controller', {
'./tokenUtil': tokenStub,
});
await tokenctl.userInfo(req, res);
sinon.assert.calledWithExactly(res.send, { status: 'success', message: 'token creation success' });
});
it('should handle error when given empty name', async () => {
const tokenValue = '123';
req = { body: { value: tokenValue, name: '' } };
const error = new Error('token creating fail');
let tokenStub = {
getToken: sinon.stub().withArgs('', tokenValue).rejects(error),
};
let tokenctl = proxyquire('./controller', {
'./tokenUtil': tokenStub,
});
await tokenctl.userInfo(req, res);
sinon.assert.calledWithExactly(res.send, { status: 'Failue', message: error });
});
});
Test result:
get token
✓ should create token success (101ms)
✓ should handle error when given empty name
2 passing (112ms)

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)
)

How to mock a Promise in Jest inside a class (not imported from a library)

I am using the AWS SDK to send emails. I have the following implementation:
import { Injectable } from '#nestjs/common';
import * as AWS from 'aws-sdk';
import { SendEmailDTO } from 'src/Messages/application/DTO/Inputs';
#Injectable()
export class MailSenderSESSDKAdapter implements MailSenderPort {
constructor() {}
async send(params: SendEmailDTO): Promise<void> {
const sendPromise = new AWS.SES(config).sendEmail(params).promise();
sendPromise
.then(function (data) {
console.log('### MailSenderSESSDKAdapter sendPromise data', data);
})
.catch(function (err) {
console.error('### err', err);
});
}
}
This line:
const sendPromise = new AWS.SES(config).sendEmail(params).promise();
returns a promise and when resolved, if successful, you get back the MessageId of the sent email.
I am trying to test it, I tried following approaches:
import { MailSenderSESSDKAdapter } from '../mailSenderSESSDK.adapter';
jest.mock('../mailSenderSESSDK.adapter', () => {
return jest.fn().mockImplementation(() => {
return { sendPromise: jest.fn() };
});
});
describe('mailSenderSESSDK adapter', () => {
let adapter: MailSenderSESSDKAdapter;
let sendPromise: any;
const mockDataResponse = {
ResponseMetadata: {
RequestId: 'ABC123',
},
MessageId: 'abc-123',
};
beforeEach(async () => {
adapter = new MailSenderSESSDKAdapter();
sendPromise = jest.fn().mockResolvedValue(Promise);
});
it.only('sends an email via SES', async () => {
const sendEmailDTO = {
subject: 'foo subject',
body: 'foo body',
from: 'from#mail.com',
to: 'to#mail.com',
};
await adapter.send(sendEmailDTO);
await expect(sendPromise).resolves.toBe(mockDataResponse);
});
});
But I don't know how to mock a method within a class method. I know how to mock the send method, but not the sendPromise promise inside the send method.
Only idea that I have would be to create a method that wraps the creation of the promise, and then mock this method, but seems overkill.
Anyone knows how to do it or best practices?

How to return custom status code in nestjs?

I have my system that has custom errors like this:
import { ExtendableError } from './extandable.error'
export const customError = {
EMAIL_EXIST: () => new ExtendableError({
message: 'USER WITH SUCH EMAIL ALREADY EXIST',
code: 403
}),
INVALID_EMAIL: () => new ExtendableError({
message: 'INVALID EMAIL',
code: 400
}),
INVALID_PASSWORD: () => new ExtendableError({
message: 'INVALID EMAIL OR PASSWORD',
code: 403
}),
EMAIL_DOES_NOT_EXIST: () => new ExtendableError({
message: 'EMAIL DOES NOT EXIST',
code: 404
}),
TOKEN_DOES_NOT_EXIST: () => new ExtendableError({
message: 'TOKEN DOES NOT EXIST',
code: 404
}),
DIFFERENT_PASSWORDS: () => new ExtendableError({
message: 'PASSWORDS ARE NOT SAME',
code: 400
}),
CURRENT_PASSWORD_ERR0R: () => new ExtendableError({
message: 'CURRENT PASSWORD IS INCORRECT',
code: 400
}),
SAME_PASSWORDS_ERROR: () => new ExtendableError({
message: 'CANNOT CHANGE SET NEW PASSWORD AS OLD PASSWORD',
code: 403
})
}
Here I can write my own error responses
When I request something, and for example emails exists, it throws an error that such email while registration already exists.
It states here:
async createAccount (doc: RegisterDto, verificationLink: string) {
if (!isValidEmail(doc.email)) {
return customError.INVALID_EMAIL()
}
const user = await this.existByEmail(doc.email)
if (!user) {
return customError.EMAIL_EXIST()
}// HERE I RETURNING AN ERROR TO CONTROLLER
doc.password = await bcrypt.hash(doc.password, SALT_ROUNDS)
const created = await this.repository.create(this.registerMapper.toDomain(doc))
await this.emailService.sendVerificationEmail(created, verificationLink)
return created
}
Here is my function in controller:
#Post('/api/register')
async register(#Body() registerDTO: RegisterDto, #Request() request, #Response() response) {
const verificationLink = `${request.protocol}://${request.header.host}/api/verify-account/`
return await this.service.createAccount(registerDTO, verificationLink)
}
In postman, it shows me the body and the response, but the actual result of the status code has 201 code
How can I fix it?
try this (ref: https://docs.nestjs.com/controllers#library-specific-approach)
import { Controller, Get, Res, HttpStatus } from '#nestjs/common';
import { Response } from 'express';
#Controller('route01')
export class MyController {
#Get('testResponse')
async testFuntion(#Res() response: Response) {
if('some condition') {
return response.status(HttpStatus.OK).send(data);
} else {
return response.status(HttpStatus.BAD_REQUEST).send(data);
}
}
}
if you need to custom function to create your own response you can use
service to create too but need to pass response to function too like this
import { HttpStatus } from '#nestjs/common';
import { Response } from 'express';
service1(response: Response, data: any) {
return response.status(HttpStatus.OK).send(data);
}
#Controller('newcc')
testFuntion(#Res() response: Response) {
const myCustomResp = this.service1(response, 'some data')
}
Instead of return customError.INVALID_EMAIL() you should throw an error.
From npm docs:
let ExtendableError = require('extendable-error');
class MyCustomError extends ExtendableError {};
throw new MyCustomError('A custom error ocurred!');

cannot mock a fetch call with `fetch-mock-jest 1.5.1` lib

I'm trying to mock a fetch call using thisfetch-mock-jest but it the code still trys to go to the remote address and eventually fail with error message FetchError: request to https://some.domain.io/app-config.yaml failed, reason: getaddrinfo ENOTFOUND some.domain.io].
Here the the test code
import { AppConfig } from '#backstage/config';
import { loadConfig } from './loader';
import mockFs from 'mock-fs';
import fetchMock from 'fetch-mock-jest';
describe('loadConfig', () => {
beforeEach(() => {
fetchMock.mock({
matcher: '*',
response: `app:
title: Example App
sessionKey: 'abc123'
`
});
});
afterEach(() => {
fetchMock.mockReset();
});
it('load config from remote path', async () => {
const configUrl = 'https://some.domain.io/app-config.yaml';
await expect(
loadConfig({
configRoot: '/root',
configTargets: [{ url: configUrl }],
env: 'production',
remote: {
reloadIntervalSeconds: 30,
},
})
).resolves.toEqual([
{
context: configUrl,
data: {
app: {
title: 'Example App',
sessionKey: 'abc123',
},
},
},
]);
expect(fetchMock).toHaveBeenCalledTimes(1);
});
function defer<T>() {
let resolve: (value: T) => void;
const promise = new Promise<T>(_resolve => {
resolve = _resolve;
});
return { promise, resolve: resolve! };
}
});
loadConfig has the fetch code that I'm trying to mock.
export async function loadConfig(
options: LoadConfigOptions,
): Promise<AppConfig[]> {
const loadRemoteConfigFiles = async () => {
const configs: AppConfig[] = [];
const readConfigFromUrl = async (remoteConfigProp: RemoteConfigProp) => {
const response = await fetch(remoteConfigProp.url);
if (!response.ok) {
throw new Error(
`Could not read config file at ${remoteConfigProp.url}`,
);
}
remoteConfigProp.oldETag = remoteConfigProp.newETag ?? undefined;
remoteConfigProp.newETag =
response.headers.get(HTTP_RESPONSE_HEADER_ETAG) ?? undefined;
remoteConfigProp.content = await response.text();
return remoteConfigProp;
};
.......
return configs;
}
let remoteConfigs: AppConfig[] = [];
if (remote) {
try {
remoteConfigs = await loadRemoteConfigFiles();
} catch (error) {
throw new Error(`Failed to read remote configuration file, ${error}`);
}
}
........ do some stuff with config then return
return remoteConfigs;
}
The config is a yaml file, that eventually gets parsed and converted into config object.
Any idea why is it failing to mock the fetch call?
replaced
import fetchMock from 'fetch-mock-jest';
with
const fetchMock = require('fetch-mock').sandbox();
const nodeFetch = require('node-fetch');
nodeFetch.default = fetchMock;
and fetchMock.mockReset(); with fetchMock.restore();

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