Jest unit test on('error') of createWriteStream - node.js

I am using Nestjs and have written the function below which recieves a file from a post request and saves it in a folder in my project.
My issue is I'm not sure how to test the on('error') branch.
function to unit test.
saveFile({ createReadStream, filename }: FileUpload): Promise<boolean> {
return new Promise(async (resolve, reject) => {
createReadStream().pipe(
createWriteStream(join(process.cwd(), `apps/mull-api/uploads/${filename}`))
.on('finish', () => resolve(true))
.on('error', () => {
console.log(createReadStream);
reject(false);
})
);
});
}
How I am testing the on('finish') branch
it('should save file', async () => {
const returnedFile = await service.saveFile(mockFile);
expect(returnedFile).toBe(true);
});
This is what my mockFile looks like. I tried providing a mockFile with empty name and it errors out.
export const mockFile: FileUpload = {
filename: 'zoro',
mimetype: 'image/jpeg',
encoding: '7bit',
createReadStream(): ReadStream {
return fs.createReadStream(join(process.cwd(), `apps/mull-api/uploads/mock-upload/zoro`));
},
};

We can mock createWriteStream, .on('finish') and .on('error') methods using mockImplementation(). And trigger these two events in the mock implementation function by ourself.
The 'finish' event handler in the mock implementation function is () => resolve(true); The 'error' event handler in the mock implementation function is () => reject(false);
See Mock Implementations, and below example:
const myMockFn = jest.fn(cb => cb(null, true));
myMockFn((err, val) => console.log(val));
// > true
index.ts:
import { createWriteStream, ReadStream } from 'fs';
import { join } from 'path';
export interface FileUpload {
filename: string;
mimetype: string;
encoding: string;
createReadStream(): ReadStream;
}
export class FileService {
public saveFile({ createReadStream, filename }: FileUpload): Promise<boolean> {
return new Promise(async (resolve, reject) => {
createReadStream().pipe(
createWriteStream(join(process.cwd(), `apps/mull-api/uploads/${filename}`))
.on('finish', () => resolve(true))
.on('error', () => {
reject(false);
}),
);
});
}
}
index.test.ts:
import { FileService, FileUpload } from './';
import { createWriteStream, WriteStream } from 'fs';
import { mocked } from 'ts-jest/utils';
jest.mock('fs');
describe('64485251', () => {
afterAll(() => {
jest.resetAllMocks();
jest.clearAllMocks();
});
it('should save file', async () => {
const mockReadStream = { pipe: jest.fn() };
const mockFile: FileUpload = {
filename: 'zoro',
mimetype: 'image/jpeg',
encoding: '7bit',
createReadStream: jest.fn().mockReturnValueOnce(mockReadStream),
};
const mockWriteStream = {
on: jest.fn().mockImplementation(function(this, event, handler) {
if (event === 'finish') {
handler();
}
return this;
}),
};
mocked(createWriteStream).mockReturnValueOnce((mockWriteStream as unknown) as WriteStream);
const service = new FileService();
const actual = await service.saveFile(mockFile);
expect(mockFile.createReadStream).toBeCalledTimes(1);
expect(mockReadStream.pipe).toBeCalledTimes(1);
expect(createWriteStream).toBeCalledWith(expect.stringContaining('apps/mull-api/uploads/zoro'));
expect(mockWriteStream.on).toBeCalledWith('finish', expect.any(Function));
expect(mockWriteStream.on).toBeCalledWith('error', expect.any(Function));
expect(actual).toBeTruthy();
});
it('should handle error if save file failed', async () => {
const mockReadStream = { pipe: jest.fn() };
const mockFile: FileUpload = {
filename: 'zoro',
mimetype: 'image/jpeg',
encoding: '7bit',
createReadStream: jest.fn().mockReturnValueOnce(mockReadStream),
};
const mockWriteStream = {
on: jest.fn().mockImplementation(function(this, event, handler) {
if (event === 'error') {
handler();
}
return this;
}),
};
mocked(createWriteStream).mockReturnValueOnce((mockWriteStream as unknown) as WriteStream);
const service = new FileService();
await expect(service.saveFile(mockFile)).rejects.toEqual(false);
expect(mockFile.createReadStream).toBeCalledTimes(1);
expect(mockReadStream.pipe).toBeCalledTimes(1);
expect(createWriteStream).toBeCalledWith(expect.stringContaining('apps/mull-api/uploads/zoro'));
expect(mockWriteStream.on).toBeCalledWith('finish', expect.any(Function));
expect(mockWriteStream.on).toBeCalledWith('error', expect.any(Function));
});
});
unit test result:
PASS src/stackoverflow/64485251/index.test.ts (10.201s)
64485251
✓ should save file (6ms)
✓ should handle error if save file failed (3ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 11.344s

Related

async node js jest unit tests

This is my nodejs code and I want to unit tests using jest and mocking the request function.
I am new to nodeJS, attached the mock function and the unit tests as well.
Please can someone add the right jest unit test code for below function.
async function getSomeTask(res) {
request.get({ url: someTaskUrl }, (response, body) => {
if (response.statusCode === 200) {
res.writeHead(200, { 'content-type': 'application/json' });
res.write(body);
res.end();
return;
}
const errorMessage = 'Failed';
res.status(400).json({ error: errorMessage });
});
}
// mock function in __mocks__
function get({url}) {
return this;
}
const handler = require("../../handler");
const request = require("../__mocks__/request");
jest.mock("request");
describe("testHandler", () => {
it("test", async () => {
const response1 = {
statusCode: 200,
body: { Test: "test" },
};
const url = "http://example.com";
jest.fn().mockImplementation({ url }, (response, body) => {
return Promise.resolve(response1);
});
const req = {
body: { requestId: 1111 },
capabilitiesCheckUrl: "http://capabilities-test",
};
const res = {};
const resp = handler.getSomeTask(res);
console.log(resp);
});
});
If possible give me an explanation as well.
You don't need to mock the entire request module by using jest.mock('request') and creating mocks inside __mocks__ directory. You can use jest.spyOn(request, 'get') to only mock request.get method.
handler.js:
const request = require('request');
const someTaskUrl = 'http://localhost:3000/api'
async function getSomeTask(res) {
request.get({ url: someTaskUrl }, (response, body) => {
if (response.statusCode === 200) {
res.writeHead(200, { 'content-type': 'application/json' });
res.write(body);
res.end();
return;
}
const errorMessage = 'Failed';
res.status(400).json({ error: errorMessage });
});
}
module.exports = {
getSomeTask,
};
handler.test.js:
const handler = require('./handler');
const request = require('request');
describe('73754637', () => {
test('should get some task success', () => {
jest.spyOn(request, 'get').mockImplementation((options, callback) => {
const mResponse = { statusCode: 200 };
const mBody = { Test: 'test' };
callback(mResponse, mBody);
});
const mRes = {
writeHead: jest.fn(),
write: jest.fn(),
end: jest.fn(),
};
handler.getSomeTask(mRes);
expect(request.get).toBeCalledWith({ url: 'http://localhost:3000/api' }, expect.any(Function));
expect(mRes.writeHead).toBeCalledWith(200, { 'content-type': 'application/json' });
expect(mRes.write).toBeCalledWith({ Test: 'test' });
expect(mRes.end).toBeCalledTimes(1);
});
});
Test result:
PASS stackoverflow/73754637/handler.test.js (10.283 s)
73754637
✓ should get some task success (5 ms)
------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
------------|---------|----------|---------|---------|-------------------
All files | 81.82 | 50 | 100 | 81.82 |
handler.js | 81.82 | 50 | 100 | 81.82 | 12-13
------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 10.807 s, estimated 11 s

"Missing region in config" after attempting to mock SecretsManager with Jest

I'm currently attempting to mock AWS SecretsManager for my unit testing with Jest, and everytime I'm hit with the ConfigError
My code is somewhat like this
//index.ts
import SM from "aws-sdk/clients/secretsmanager"
const secretManagerClient = new SM()
...
export const randomMethod = async (a: string, b: string) => {
let secret
const personalToken = {
SecretId: process.env.secretId,
}
secretManagerClient
.getSecretValue(personalToken, (err, data) => {
if (err) {
console.error(`[SECRETS MANAGER] Error fetching personal token : ${err}`)
} else if (data && data.SecretString) {
secret = data.SecretString
}
})
}
My mock goes like this :
//index.test.js
const mockGetSecretValue = jest.fn((SecretId) => {
switch (SecretId) {
case process.env.GITHUB_PERSONAL_TOKEN:
return {
SecretString: process.env.GITHUB_PERSONAL_TOKEN_VALUE,
}
default:
throw Error("secret not found")
}
})
jest.mock("aws-sdk/clients/secretsmanager", () => {
return jest.fn(() => {
return {
getSecretValue: jest.fn(({ SecretId }) => {
return mockGetSecretValue(SecretId)
}),
promise: jest.fn(),
}
})
})
However, I get this error thrown at me : ConfigError: Missing region in config, which I understand to some extent, however I don't understand why it occurs here in the mocking part...
Thanks in advance!
EDIT: Thanks to the 1st answer, I've managed to stop having this error. However, the getSecretValue() method is not returning the Secret value I want.
You should NOT use the callback of .getSecretValue() method with .promise() together. Just choose one of them. The error means you didn't mock the secretsmanager class correctly of aws-sdk.
E.g.
index.ts:
import SM from 'aws-sdk/clients/secretsmanager';
const secretManagerClient = new SM();
export const randomMethod = async () => {
const personalToken = {
SecretId: process.env.secretId || '',
};
try {
const data = await secretManagerClient.getSecretValue(personalToken).promise();
return data.SecretString;
} catch (err) {
console.error(`[SECRETS MANAGER] Error fetching personal token : ${err}`);
}
};
index.test.ts:
import { randomMethod } from '.';
import SM from 'aws-sdk/clients/secretsmanager';
import { mocked } from 'ts-jest/utils';
import { PromiseResult } from 'aws-sdk/lib/request';
jest.mock('aws-sdk/clients/secretsmanager', () => {
const mSecretManagerClient = {
getSecretValue: jest.fn().mockReturnThis(),
promise: jest.fn(),
};
return jest.fn(() => mSecretManagerClient);
});
describe('69977310', () => {
test('should get secret value', async () => {
process.env.secretId = 's1';
const mSecretManagerClient = mocked<InstanceType<typeof SM>>(new SM());
const mGetSecretValueRequest = mocked(mSecretManagerClient.getSecretValue());
mGetSecretValueRequest.promise.mockResolvedValue({
SecretString: JSON.stringify({ password: '123456' }),
} as PromiseResult<any, any>);
const actual = await randomMethod();
expect(actual).toEqual(JSON.stringify({ password: '123456' }));
expect(mSecretManagerClient.getSecretValue as jest.Mocked<any>).toBeCalledWith({ SecretId: 's1' });
});
test('should throw error', async () => {
process.env.secretId = 's1';
const logSpy = jest.spyOn(console, 'error').mockImplementation(() => 'suppress error log for testing');
const mSecretManagerClient = mocked<InstanceType<typeof SM>>(new SM());
const mGetSecretValueRequest = mocked(mSecretManagerClient.getSecretValue());
const mError = new Error('network');
mGetSecretValueRequest.promise.mockRejectedValue(mError);
await randomMethod();
expect(logSpy).toBeCalledWith(`[SECRETS MANAGER] Error fetching personal token : ${mError}`);
expect(mSecretManagerClient.getSecretValue as jest.Mocked<any>).toBeCalledWith({ SecretId: 's1' });
});
});
test result:
PASS examples/69977310/index.test.ts (7.722 s)
69977310
✓ should get secret value (4 ms)
✓ should throw error (1 ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 50 | 100 | 100 |
index.ts | 100 | 50 | 100 | 100 | 6
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 8.282 s, estimated 10 s
package versions:
"aws-sdk": "^2.875.0",
"typescript": "^4.1.2",
"jest": "^26.6.3",
I've overlooked the fact that I was using a callback in order to bypass the promise().
The following is the correct code:
const mockGetSecretValue = jest.fn((SecretId, callback) => {
console.log("secretId", SecretId)
switch (SecretId) {
case process.env.GITHUB_PERSONAL_TOKEN:
const data = {
SecretString: process.env.GITHUB_PERSONAL_TOKEN_VALUE,
}
callback(null, data)
break;
default:
const err = new Error("secret not found")
throw err
}
})
jest.mock("aws-sdk/clients/secretsmanager", () => {
return jest.fn(() => {
return {
promise: jest.fn(),
getSecretValue: jest.fn(({ SecretId }, callback) => {
return mockGetSecretValue(SecretId, callback)
}),
}
})
})
Thanks again for your help #slideshowp2!

How to write unit test case for uploadFiles method using jest?

i am trying to write unit test case for uploadFiles() method. This method returns function so i have to check toHaveBeenCalledWith('files', 5). I have updated my test case below, I don't know how to mock return function upload.array. can anyone tell me is that possible?
Method
uploadFiles = (
storage: StorageType,
validationFn: (request: Request, file: Express.Multer.File, cb: FileFilterCallback) => Promise<void>,
) => {
// fileSize - size of an individual file (1024 * 1024 * 1 = 1mb)
const upload = multer({
storage: this[storage](),
limits: { fileSize: 1024 * 1024 * FILE_SIZE },
fileFilter: this.fileUtil.fileValidation(validationFn),
});
return upload.array("files", 5); // maximum files allowed to upload in a single request
};
Test Case
describe('FileService', () => {
// fileValidation Test suite
describe('fileValidation', () => {
let callbackFn: jest.Mock<any, any>;
let validationFn: jest.Mock<any, any>;
beforeEach(() => {
callbackFn = jest.fn();
validationFn = jest.fn();
});
afterEach(() => {
callbackFn.mockClear();
validationFn.mockClear();
});
it('should call the file filter method with image file types when request body has type image', async () => {
// Preparing
const request = {
body: {
entity_no: 'AEZ001',
type: 'image',
category: 'Shipping',
},
};
const file = {
originalname: 'some-name.png',
mimetype: 'image/png',
};
// Executing
const func = fileService.uploadFiles(StorageType.DISK, validationFn);
await func(request as Request, file as any, callbackFn);
});
});
});
You can use jest.mock(moduleName, factory, options) to mock multer module.
E.g.
fileService.ts:
import multer from 'multer';
const FILE_SIZE = 1;
type FileFilterCallback = any;
export enum StorageType {
DISK = 'disk',
}
export class FileService {
fileUtil = {
fileValidation(fn) {
return fn;
},
};
disk() {
return multer.diskStorage({
destination: function (req, file, cb) {
cb(null, '/tmp/my-uploads');
},
filename: function (req, file, cb) {
cb(null, file.fieldname + '-' + Date.now());
},
});
}
uploadFiles = (
storage: StorageType,
validationFn: (request: Request, file: Express.Multer.File, cb: FileFilterCallback) => Promise<void>
) => {
const upload = multer({
storage: this[storage](),
limits: { fileSize: 1024 * 1024 * FILE_SIZE },
fileFilter: this.fileUtil.fileValidation(validationFn),
});
return upload.array('files', 5);
};
}
fileService.test.ts:
import { FileService, StorageType } from './fileService';
import multer from 'multer';
const mMulter = {
array: jest.fn(),
};
jest.mock('multer', () => {
const multer = jest.fn(() => mMulter);
const oMulter = jest.requireActual('multer');
for (let prop in oMulter) {
if (oMulter.hasOwnProperty(prop)) {
multer[prop] = oMulter[prop];
}
}
return multer;
});
describe('65317652', () => {
afterAll(() => {
jest.resetAllMocks();
});
let validationFn: jest.Mock<any, any>;
beforeEach(() => {
validationFn = jest.fn();
});
afterEach(() => {
validationFn.mockClear();
});
it('should pass', () => {
const fileService = new FileService();
fileService.uploadFiles(StorageType.DISK, validationFn);
expect(multer).toBeCalled();
expect(mMulter.array).toHaveBeenCalledWith('files', 5);
});
});
unit test result:
PASS examples/65317652/fileService.test.ts
65317652
✓ should pass (3 ms)
----------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------------|---------|----------|---------|---------|-------------------
All files | 84.62 | 100 | 71.43 | 84.62 |
fileService.ts | 84.62 | 100 | 71.43 | 84.62 | 19-22
----------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 4.693 s

Jest mock typescript dependency

My index.ts file looks like this
import {IS3Client, S3Client} from './client/S3Client';
const s3: IS3Client = new S3Client();
export async function someFunc(event: any, context: any, callback: any) {
const x: string = await s3.getFile('a','b');
}
S3Client.ts looks like this
import * as AWS from 'aws-sdk';
export interface IS3Client {
getFile(bucketName: string, fileName: string): Promise<any>;
}
export class S3Client implements IS3Client {
private s3Client: AWS.S3;
constructor() {
this.s3Client = new AWS.S3();
}
public async getFile(bucketName: string, fileName: string): Promise<any> {
const params = {
Bucket: bucketName,
Key: fileName,
};
return (await this.s3Client.getObject(params).promise()).Body.toString();
}
}
Now I am interested to mock the getFile function to return what I want when I am testing index.ts
My test case looks like this
import {someFunc} from '../src/index';
import { S3Client } from '../src/client/S3Client';
describe("Test Suite", () => {
beforeAll(()=>{
jest.mock('../src/client/S3Client');
const mockedClient: jest.Mocked<S3Client> = new S3Client() as any;
mockedClient.getFile.mockImplementation(() => Promise.resolve('hello'));
});
it("testCase", () => {
const req = {
"key" : ["value"]
};
someFunc(req, null, null);
})
});
I am getting the following error :
TypeError: mockedClient.getFile.mockImplementation is not a function
Somehow this is looking much harder than I thought. Can someone suggest something, Thanks in advance ?
I added another class like this
import { SecretsManager } from 'aws-sdk';
export default class XUtils {
private secretsManager: SecretsManager;
constructor(secretsManager: SecretsManager) {
this.secretsManager = secretsManager;
}
public async getData(urlPrefix: string): Promise<any[]> {
return ['data'];
}
}
And my index.ts looks something like this :
import {IS3Client, S3Client} from './client/S3Client';
import XUtils from './utils/XUtils';
import { SecretsManager } from 'aws-sdk';
const s3: IS3Client = new S3Client();
const secretsManager: SecretsManager = new SecretsManager({ region: process.env.AWS_REGION });
const xUtils: XUtils = new XUtils(secretsManager)
export async function someFunc(event: any, context: any, callback: any) {
const x: string = await s3.getFile('a','b');
const y = await xUtils.getData(x);
}
Following from what you suggested, I modified my test case to something like this :
import {someFunc} from '../src/index';
import { S3Client } from '../src/client/S3Client';
import XUtils from '../utils/XUtils';
jest.mock('../src/client/S3Client', () => {
const mS3Client = { getFile: jest.fn() };
return { S3Client: jest.fn(() => mS3Client) };
});
jest.mock('../utils/XUtils', () => {
const mXUtils = { getData: jest.fn() };
return { XUtils: jest.fn(() => mXUtils) };
});
describe("Test Suite", () => {
beforeAll(()=>{
mockedClient = new S3Client() as any;
mockedClient.getFile.mockImplementation(() => Promise.resolve('url'));
mockedXUtils = new XUtils(null) as any;
mockedXUtils.getData.mockImplementation(() => Promise.resolve(['data']))
});
it("testCase", () => {
const req = {
"key" : ["value"]
};
someFunc(req, null, null);
})
});
I am getting error now as
TypeError: XUtils_1.default is not a constructor
What exactly is this problem ?
You can't use jest.mock in the function scope. It should be used in module scope.
You should use async/await for someFunc method in your test case.
E.g.
index.ts:
import { IS3Client, S3Client } from './s3client';
const s3: IS3Client = new S3Client();
export async function someFunc(event: any, context: any, callback: any) {
const x: string = await s3.getFile('a', 'b');
}
s3client.ts:
import * as AWS from 'aws-sdk';
export interface IS3Client {
getFile(bucketName: string, fileName: string): Promise<any>;
}
export class S3Client implements IS3Client {
private s3Client: AWS.S3;
constructor() {
this.s3Client = new AWS.S3();
}
public async getFile(bucketName: string, fileName: string): Promise<any> {
const params = {
Bucket: bucketName,
Key: fileName,
};
return (await this.s3Client.getObject(params).promise()).Body!.toString();
}
}
index.test.ts:
import { someFunc } from './';
import { S3Client } from './s3client';
jest.mock('./s3client', () => {
const mS3Client = { getFile: jest.fn() };
return { S3Client: jest.fn(() => mS3Client) };
});
describe('Test Suite', () => {
let mockedClient: jest.Mocked<S3Client>;
beforeAll(() => {
mockedClient = new S3Client() as any;
mockedClient.getFile.mockImplementation(() => Promise.resolve('hello'));
});
it('testCase', async () => {
const req = {
key: ['value'],
};
await someFunc(req, null, null);
expect(mockedClient.getFile).toBeCalledWith('a', 'b');
});
});
Unit test results with 100% coverage:
PASS stackoverflow/60445082/index.test.ts (8.548s)
Test Suite
✓ testCase (6ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
index.ts | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 10.04s
source code: https://github.com/mrdulin/react-apollo-graphql-starter-kit/tree/master/stackoverflow/60445082

Jest reset mock of a node module

I'm working on the Google Cloud Functions tests.
The files are these:
index.ts which only exports the functions which are also imported there.
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === 'contactSupportByMail') {
exports.contactSupportByMail = require('./contactSupportByMail');
}
contactSupportByMail.ts the function to test.
And the test:
describe('Cloud Functions', (): void => {
let myFunctions;
let adminInitStub;
beforeAll((): void => {
// [START stubAdminInit]
// If index.js calls admin.initializeApp at the top of the file,
// we need to stub it out before requiring index.js. This is because the
// functions will be executed as a part of the require process.
// Here we stub admin.initializeApp to be a dummy function that doesn't do anything.
adminInitStub = sinon.stub(admin, 'initializeApp');
testEnv.mockConfig({
sendgrid: {
key: 'apiKey',
},
brand: {
support_email: 'supportEmail',
},
});
// [END stubAdminInit]
});
afterAll((): void => {
// Restore admin.initializeApp() to its original method.
adminInitStub.restore();
// Do other cleanup tasks.
process.env.FUNCTION_NAME = '';
myFunctions = undefined;
testEnv.cleanup();
});
describe('contactSupportByMail', (): void => {
// Mocking node_modules library before the require
jest.mock('#sendgrid/mail', (): { [key: string]: any } => ({
setApiKey: (): void => { },
send: (): Promise<any> => Promise.resolve('ok'),
}));
// Setting up cloud function name
process.env.FUNCTION_NAME = 'contactSupportByMail';
// Importing the index file
myFunctions = require('../src/index');
const wrapped = testEnv.wrap(myFunctions.contactSupportByMail);
it('it should export contactSupportByMail', (): void => {
const cFunction = require('../src/contactSupportByMail');
assert.isObject(myFunctions);
assert.include(myFunctions, { contactSupportByMail: cFunction });
});
it('should fully work', async (): Promise<void> => {
const onCallObjects: [any, ContextOptions] = [
{ mailBody: 'mailBody', to: 'toEmail' },
{ auth: { token: { email: 'userEmail' } } },
];
return assert.deepEqual(await wrapped(...onCallObjects), { ok: true });
});
it('not auth', async (): Promise<void> => {
await expect(wrapped(undefined)).rejects.toThrow('The function must be called while authenticated.');
});
it('sendgrid error', async (): Promise<void> => {
// Mocking node_modules library before the require
jest.mock('#sendgrid/mail', (): { [key: string]: any } => ({
setApiKey: (): void => { },
send: (): Promise<any> => Promise.reject('errorsengrid'),
}));
// Importing the index file
const a = require('../src/index');
const wrapped_2 = testEnv.wrap(a.contactSupportByMail);
const onCallObjects: [any, ContextOptions] = [
{ mailBody: 'mailBody', to: 'toEmail' },
{ auth: { token: { email: 'userEmail' } } },
];
await expect(wrapped_2(...onCallObjects)).rejects.toThrow('errorsengrid');
});
});
});
The problem is provoking the sendgrid error. I don't know how to reset the mock of sendgrid's library which is required inside contactSupportByMail. After mocking it for the first time, it always returns the send function as resolved.
Just a note - if using babel-jest, mock calls are hoisted to the top of the transpiled js... doMock allow you to mock in the before functions of a test.
This is one way to mock a module for some tests within a file - and restore it for the others:
describe("some tests", () => {
let subject;
describe("with mocks", () => {
beforeAll(() => {
jest.isolateModules(() => {
jest.doMock("some-lib", () => ({ someFn: jest.fn() }));
subject = require('./module-that-imports-some-lib');
});
});
// ... tests when some-lib is mocked
});
describe("without mocks - restoring mocked modules", () => {
beforeAll(() => {
jest.isolateModules(() => {
jest.unmock("some-lib");
subject = require('./module-that-imports-some-lib');
});
});
// ... tests when some-lib is NOT mocked
});
});
I finally got the solution:
afterEach((): void => {
jest.resetModules();
});

Resources