I use the simple-git package. I have the following function:
import simpleGit from 'simple-git';
/**
* The function returns the ticket Id, is presents, in the branch name
* #returns ticket Id
*/
export const getTicketIdFromBranchName = async (ticketRegex: RegExp) => {
const git = simpleGit();
try {
const localBranches = await git.branchLocal();
const currentBranch = localBranches.current;
const currentBranchTicketMatches = currentBranch.match(ticketRegex);
if (currentBranchTicketMatches) {
return currentBranchTicketMatches[0];
}
return null;
} catch {
return null;
}
};
I try to create a unit-test for this function:
import { getTicketIdFromBranchName } from '#/utils/git-info';
const TICKET_ID_REGEX = /((?<!([A-Z]{1,10})-?)[A-Z]+-\d+)/.source;
describe('[utils/git-info]', () => {
it('getTicketIdFromBranchName | Function should proper ticket Id when there is one', async () => {
const ticketId = 'CLO-1234';
jest.mock('simple-git', () => {
const mGit = {
branchLocal: jest.fn(() => Promise.resolve({ current: `${ticketId} DUMMY TEST` })),
};
return jest.fn(() => mGit);
});
const result = await getTicketIdFromBranchName(new RegExp(TICKET_ID_REGEX));
expect(result === ticketId).toEqual(true);
});
});
But the unit-test fails. I says I expected to get true but it got false in the final line.
I guess I use jest.mock in the wrong way.
The official documentation has a key description of the use of jest.mock.
Note: In order to mock properly, Jest needs jest.mock('moduleName') to be in the same scope as the require/import statement.
You call the jest.mock('moduleName') inside test case function scope, but import the git-info module in module scope. That's why mock doesn't work.
Use require('moduleName') or await import('moduleName') in test case function. The order of the require/import and jest.mock() statements does not matter.
git-info.js:
import simpleGit from 'simple-git';
/**
* The function returns the ticket Id, is presents, in the branch name
* #returns ticket Id
*/
export const getTicketIdFromBranchName = async (ticketRegex) => {
const git = simpleGit();
try {
const localBranches = await git.branchLocal();
const currentBranch = localBranches.current;
const currentBranchTicketMatches = currentBranch.match(ticketRegex);
if (currentBranchTicketMatches) {
return currentBranchTicketMatches[0];
}
return null;
} catch {
return null;
}
};
git-info.test.js:
const TICKET_ID_REGEX = /((?<!([A-Z]{1,10})-?)[A-Z]+-\d+)/.source;
describe('[utils/git-info]', () => {
it('getTicketIdFromBranchName | Function should proper ticket Id when there is one', async () => {
const { getTicketIdFromBranchName } = await import('./git-info');
const ticketId = 'CLO-1234';
jest.mock(
'simple-git',
() => {
const mGit = {
branchLocal: jest.fn(() => Promise.resolve({ current: `${ticketId} DUMMY TEST` })),
};
return jest.fn(() => mGit);
},
{ virtual: true }
);
const result = await getTicketIdFromBranchName(new RegExp(TICKET_ID_REGEX));
expect(result === ticketId).toEqual(true);
});
});
Test result:
PASS stackoverflow/71808909/git-info.test.js (7.439 s)
[utils/git-info]
✓ getTicketIdFromBranchName | Function should proper ticket Id when there is one (6892 ms)
-------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
-------------|---------|----------|---------|---------|-------------------
All files | 84.62 | 50 | 100 | 81.82 |
git-info.js | 84.62 | 50 | 100 | 81.82 | 19-21
-------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 8.215 s, estimated 9 s
package version: "jest": "^26.6.3"
Related
I have the following code of the NodeJS AWS Lambda function I would like to cover by unit tests with Jest:
index.js
const { getConfig } = require('./modules/config/configManager');
const BridgeDataProvider = require('./modules/storage/bridge/bridgeDataProvider');
const ClientProcessor = require('./modules/domain/clientProcessor');
const configPromise = getConfig();
exports.handler = async () => {
const config = await configPromise;
if (!config.enabled) {
return;
}
const bridgeDataProvider = new BridgeDataProvider(config.bridgeDynamoDbConfig);
const clientProcessor = new ClientProcessor(config);
const clients = await bridgeDataProvider.getActiveClients();
for (const client of clients) {
await clientProcessor.process(client);
}
};
And I'm trying to mock getConfig async function for each test individually, but unfortunately it doesn't work. await getConfig() in index.js always returns undefined Here's the testing code:
index.test.js
const { getConfig } = require('../modules/config/configManager');
const { handler } = require('../index');
const BridgeDataProvider = require('../modules/storage/bridge/bridgeDataProvider');
const ClientProcessor = require('../modules/domain/clientProcessor');
jest.mock('../modules/config/configManager', () => ({
getConfig: jest.fn(),
}));
jest.mock('../modules/storage/bridge/bridgeDataProvider');
jest.mock('../modules/domain/clientProcessor');
const defaultMocks = {
BridgeDataProvider: {
getActiveClients: jest.fn().mockImplementation(() => {
/** #type {Client[]} */
const clients = [
{
id: '1234abc',
clientcode: 'Amazon',
},
{
id: '5678def',
clientcode: 'Facebook',
},
];
return Promise.resolve(clients);
}),
},
};
/**
* #typedef {import('../modules/config/config.types').AppConfig} AppConfig
* #typedef {import('../modules/storage/bridge/models.types').Client} Client
*/
describe('handler', () => {
beforeEach(() => {
jest.resetModules()
.clearAllMocks();
setupDefaultMocks();
});
it('does not handle clients if function is not enabled', async () => {
getConfig.mockResolvedValue({enabled: false, bridgeDynamoDbConfig: {}}); // this is not working, await getConfig() returns undefined in index.js
await handler();
const processMethod = ClientProcessor.mock.instances[0].process;
expect(processMethod).toHaveBeenCalledTimes(0);
});
});
function setupDefaultMocks() {
getConfig.mockResolvedValue({enabled: true, bridgeDynamoDbConfig: {}}); // this is not working, await getConfig() returns undefined in index.js
BridgeDataProvider.mockImplementation(() => defaultMocks.BridgeDataProvider);
}
Test output:
FAIL test/index.test.js
● handler › does not handle clients if function is not enabled
TypeError: Cannot read properties of undefined (reading 'enabled')
10 |
11 | const config = await configPromise;
> 12 | if (!config.enabled) {
| ^
13 | return;
14 | }
15 |
at enabled (index.js:12:17)
at Object.<anonymous> (test/index.test.js:48:9)
If I put default implementation right inside jest.mock('../modules/config/configManager', ...) statement, it will mock resolved value as expected. Why is the mocking in individual test not working and how to make it work?
Thanks to #slideshowp2, he pointed me to the fact that getConfig is called at the module scope, and I need to require handler after doing the mock of getConfig. However, if I try to add two tests with differently mocked getConfig (config.enabled = true and config.enabled = false), second test will get the same enabled = true. I put the example below based on the #slideshowp2's answer. I belive I need to remove the index.js module cache after each test. I would be grateful if someone would show how to do it.
index.test.js
const { getConfig } = require('../modules/config/configManager');
const BridgeDataProvider = require('../modules/storage/bridge/bridgeDataProvider');
const ClientProcessor = require('../modules/domain/clientProcessor');
jest.mock('../modules/config/configManager');
jest.mock('../modules/storage/bridge/bridgeDataProvider');
jest.mock('../modules/domain/clientProcessor');
describe('index', () => {
test('should pass (enabled=true)', async () => {
getConfig.mockResolvedValueOnce({ enabled: true, bridgeDynamoDbConfig: 'fake bridge dynamoDB config' });
const bridgeDataProviderInstance = {
getActiveClients: jest.fn().mockResolvedValueOnce([1, 2])
};
BridgeDataProvider.mockImplementation(() => bridgeDataProviderInstance);
const clientProcessorInstance = {
process: jest.fn()
};
ClientProcessor.mockImplementation(() => clientProcessorInstance);
const {handler} = require('../index');
await handler();
expect(getConfig).toBeCalledTimes(1);
expect(BridgeDataProvider).toBeCalledWith('fake bridge dynamoDB config');
expect(bridgeDataProviderInstance.getActiveClients).toBeCalledTimes(1);
expect(clientProcessorInstance.process.mock.calls).toEqual([[1], [2]]);
});
test('should pass (enabled=false)', async () => {
getConfig.mockResolvedValueOnce({ enabled: false, bridgeDynamoDbConfig: 'fake bridge dynamoDB config' });
const bridgeDataProviderInstance = {
getActiveClients: jest.fn().mockResolvedValueOnce([1, 2])
};
BridgeDataProvider.mockImplementation(() => bridgeDataProviderInstance);
const clientProcessorInstance = {
process: jest.fn()
};
ClientProcessor.mockImplementation(() => clientProcessorInstance);
const {handler} = require('../index');
await handler();
expect(clientProcessorInstance.process).toBeCalledTimes(0);
});
});
Test output
FAIL test/index2.test.js
index
√ should pass (enabled=true) (234 ms)
× should pass (enabled=false) (3 ms)
● index › should pass (enabled=false)
expect(jest.fn()).toBeCalledTimes(expected)
Expected number of calls: 0
Received number of calls: 2
43 | const {handler} = require('../index');
44 | await handler();
> 45 | expect(clientProcessorInstance.process).toBeCalledTimes(0);
| ^
46 | });
47 | });
at Object.toBeCalledTimes (test/index2.test.js:45:49)
Test Suites: 1 failed, 1 total
Tests: 1 failed, 1 passed, 2 total
Snapshots: 0 total
Time: 2.95 s, estimated 4 s
See es6-class-mocks#replacing-the-mock-using-mockimplementation-or-mockimplementationonce:
Note: you call getConfig in the module scope, so make sure you mock its resolved value before the require('./') statement.
Solution:
index.js:
const { getConfig } = require('./modules/config/configManager');
const BridgeDataProvider = require('./modules/storage/bridge/bridgeDataProvider');
const ClientProcessor = require('./modules/domain/clientProcessor');
const configPromise = getConfig();
exports.handler = async () => {
const config = await configPromise;
if (!config.enabled) {
return;
}
const bridgeDataProvider = new BridgeDataProvider(config.bridgeDynamoDbConfig);
const clientProcessor = new ClientProcessor(config);
const clients = await bridgeDataProvider.getActiveClients();
for (const client of clients) {
await clientProcessor.process(client);
}
};
modules/config/configManager.js:
exports.getConfig = async () => {
return { enabled: false }
}
modules/storage/bridge/bridgeDataProvider.js:
class BridgeDataProvider {
async getActiveClients() {
return []
}
}
module.exports = BridgeDataProvider;
modules/domain/clientProcessor.js:
class ClientProcessor {
async process(client) { }
}
module.exports = ClientProcessor;
index.test.js:
const { getConfig } = require('./modules/config/configManager');
const BridgeDataProvider = require('./modules/storage/bridge/bridgeDataProvider');
const ClientProcessor = require('./modules/domain/clientProcessor');
jest.mock('./modules/config/configManager');
jest.mock('./modules/storage/bridge/bridgeDataProvider');
jest.mock('./modules/domain/clientProcessor');
describe('index', () => {
test('should pass', async () => {
getConfig.mockResolvedValueOnce({ enabled: true, bridgeDynamoDbConfig: 'fake bridge dynamoDB config' })
const bridgeDataProviderInstance = {
getActiveClients: jest.fn().mockResolvedValueOnce([1, 2])
}
BridgeDataProvider.mockImplementation(() => bridgeDataProviderInstance);
const clientProcessorInstance = {
process: jest.fn()
}
ClientProcessor.mockImplementation(() => clientProcessorInstance)
const { handler } = require('./');
await handler();
expect(getConfig).toBeCalledTimes(1);
expect(BridgeDataProvider).toBeCalledWith('fake bridge dynamoDB config');
expect(bridgeDataProviderInstance.getActiveClients).toBeCalledTimes(1);
expect(clientProcessorInstance.process.mock.calls).toEqual([[1], [2]])
})
})
Test result:
PASS stackoverflow/74137912/index.test.js (10.599 s)
index
✓ should pass (87 ms)
---------------------------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
---------------------------------|---------|----------|---------|---------|-------------------
All files | 76.19 | 50 | 28.57 | 78.95 |
74137912 | 92.86 | 50 | 100 | 92.31 |
index.js | 92.86 | 50 | 100 | 92.31 | 10
74137912/modules/config | 33.33 | 100 | 0 | 50 |
configManager.js | 33.33 | 100 | 0 | 50 | 2
74137912/modules/domain | 50 | 100 | 0 | 50 |
clientProcessor.js | 50 | 100 | 0 | 50 | 2
74137912/modules/storage/bridge | 50 | 100 | 0 | 50 |
bridgeDataProvider.js | 50 | 100 | 0 | 50 | 3
---------------------------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 11.271 s
Thanks to #slideshowp2, he pointed me to the fact that getConfig is called at the module scope of index.js, and I need to require handler after mocking implementation of getConfig. However, I got the issue of caching the results of getConfig because getConfig is called at the top-level of the module. That makes multiple tests dependent to each other.
Finally I found a way how to do require('../index') in test ignoring the cached state of the module with a help of jest.isolateModules(fn). I added getIsolatedHandler() which returns isolated handler function without any caching state. Here's the final solution:
index.test.js
const { getConfig } = require('../modules/config/configManager');
const BridgeDataProvider = require('../modules/storage/bridge/bridgeDataProvider');
const ClientProcessor = require('../modules/domain/clientProcessor');
jest.mock('../modules/config/configManager');
jest.mock('../modules/storage/bridge/bridgeDataProvider');
jest.mock('../modules/domain/clientProcessor');
describe('index', () => {
test('should pass (enabled=true)', async () => {
getConfig.mockResolvedValueOnce({ enabled: true, bridgeDynamoDbConfig: 'fake bridge dynamoDB config' });
const bridgeDataProviderInstance = {
getActiveClients: jest.fn().mockResolvedValueOnce([1, 2])
};
BridgeDataProvider.mockImplementation(() => bridgeDataProviderInstance);
const clientProcessorInstance = {
process: jest.fn()
};
ClientProcessor.mockImplementation(() => clientProcessorInstance);
const handler = getIsolatedHandler();
await handler();
expect(getConfig).toBeCalledTimes(1);
expect(BridgeDataProvider).toBeCalledWith('fake bridge dynamoDB config');
expect(bridgeDataProviderInstance.getActiveClients).toBeCalledTimes(1);
expect(clientProcessorInstance.process.mock.calls).toEqual([[1], [2]]);
});
test('should pass (enabled=false)', async () => {
getConfig.mockResolvedValueOnce({ enabled: false, bridgeDynamoDbConfig: 'fake bridge dynamoDB config' });
const bridgeDataProviderInstance = {
getActiveClients: jest.fn().mockResolvedValueOnce([1, 2])
};
BridgeDataProvider.mockImplementation(() => bridgeDataProviderInstance);
const clientProcessorInstance = {
process: jest.fn()
};
ClientProcessor.mockImplementation(() => clientProcessorInstance);
const handler = getIsolatedHandler();
await handler();
expect(clientProcessorInstance.process).toBeCalledTimes(0);
});
});
function getIsolatedHandler() {
let handler;
jest.isolateModules(() => {
const index = require('../index');
handler = index.handler;
});
return handler;
}
Test output:
PASS test/index.test.js
index
√ should pass (enabled=true) (263 ms)
√ should pass (enabled=false) (254 ms)
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 3.289 s
I am new to Sinon, but I have looked around for a while trying to find an answer for this question..
I have a function I need to test, it returns a promise to call another function will callback..
Below is the function that I need to write test case for:
const bookService = require(./bookService);
const getBook = () => {
const bookName = "book";
const bookID = '111';
return new Promise((resolve, reject) => {
bookService.InfoRequest(bookName, bookID, 'GET', res => {
if(res.error){
reject(res);
}else{
const list = res['allPages'] || [];
if(list = []){
resolve({
pageNumber: 0,
note: "book is no longer exist"
});
}else{
resolve(res['allPages']);
}
}
})
})
}
The bookService.InfoRequest method is not returning anything it returns the callback(res);
I have tried stub the bookService.InfoRequest method, but since it is not returning anything I am not sure how can I modified the callback parameter to test all 3 branchs..
I am using Ava, so I tried something like this:
test('getBook Error Block', t=> {
const stub = sinon.stub(bookService, InfoRequest);
stub.callsFake(() => {
return { error: true };
});
return obj.getBook().then(res => {
t.deepEqual(res, []);
}).catch(error => {
console.log(error.error);
t.deepEqual(error.error, true);
})
})
This is the test cases for the first Branch, the reject(res) branch. There are 2 more very similar only with different callFake.
But the problem is I am not able to print the error out and test shows it passed, but if I change true to false, it also pass...
The stubbed implementation by .callFake() is not correct. The bookService.InfoRequest() method accepts a callback parameter, the res is passed to this callback. So you need to provide a stubbed implementation with this callback function and pass your fake error.
E.g.
bookService.js:
function InfoRequest(bookName, bookId, method, cb) {}
module.exports = { InfoRequest };
obj.js:
const bookService = require('./bookService');
const getBook = () => {
const bookName = 'book';
const bookID = '111';
return new Promise((resolve, reject) => {
bookService.InfoRequest(bookName, bookID, 'GET', (res) => {
if (res.error) {
reject(res);
} else {
const list = res['allPages'] || [];
if ((list = [])) {
resolve({
pageNumber: 0,
note: 'book is no longer exist',
});
} else {
resolve(res['allPages']);
}
}
});
});
};
module.exports = { getBook };
obj.test.js:
const obj = require('./obj');
const bookService = require('./bookService');
const sinon = require('sinon');
const test = require('ava');
test('getBook Error Block', (t) => {
const res = { error: new Error('network') };
const stub = sinon.stub(bookService, 'InfoRequest').callsFake((bookName, bookId, method, callback) => {
callback(res);
});
return obj.getBook().catch((res) => {
t.deepEqual(res.error, res.error);
sinon.assert.calledWith(stub, 'book', '111', 'GET', sinon.match.func);
});
});
test result:
> nyc ava --timeout=3000 "/Users/dulin/workspace/github.com/mrdulin/expressjs-research/src/stackoverflow/66702460/obj.test.js"
1 test passed
----------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------------|---------|----------|---------|---------|-------------------
All files | 71.43 | 16.67 | 75 | 71.43 |
bookService.js | 100 | 100 | 0 | 100 |
obj.js | 69.23 | 16.67 | 100 | 69.23 | 11-18
----------------|---------|----------|---------|---------|-------------------
How to mock the call of service.request in the code bellow?
import url from 'url'
import jayson from 'jayson/promise'
export async function dispatch(webHook, method, payload) {
const service = jayson.Client.https({ ...url.parse(webHook) })
return service.request(method, { ...payload })
}
In my unit-test I want to do something like this
jest.mock("") // what should go here?
it(() => {
const method = 'test'
expect(request).toHaveBeenCalledWith(method...) ?
})
UPDATE
I updated with my findings my code, but still no luck
import { Client } from 'jayson/promise'
import { dispatch } from '../src/remote'
jest.mock('jayson')
describe('remote', () => {
let spy: jest.SpyInstance<any>
beforeEach(() => {
spy = jest.spyOn(Client.https.prototype, 'request')
})
afterEach(() => {
spy.mockClear()
})
it('should invoke request method', () => {
const url = 'http://example.com:8000'
const method = ''
const payload = {}
dispatch(url, method, payload)
expect(spy).toHaveBeenCalledWith({})
})
})
You can use jest.mock to mock jayson/promise module. Don't need to use jest.spyOn.
E.g.
index.ts:
import url from 'url';
import jayson from 'jayson/promise';
export async function dispatch(webHook, method, payload) {
const service = jayson.Client.https({ ...url.parse(webHook) });
return service.request(method, { ...payload });
}
index.test.ts:
import { dispatch } from './';
import jayson, { HttpsClient } from 'jayson/promise';
import { mocked } from 'ts-jest';
jest.mock('jayson/promise');
const httpsClientMock = mocked(jayson.Client.https);
describe('65924278', () => {
afterAll(() => {
jest.resetAllMocks();
});
it('should pass', async () => {
const url = 'http://example.com:8000';
const method = '';
const payload = {};
const serviceMock = ({
request: jest.fn(),
} as unknown) as HttpsClient;
httpsClientMock.mockReturnValueOnce(serviceMock);
await dispatch(url, method, payload);
expect(jayson.Client.https).toBeCalledTimes(1);
expect(serviceMock.request).toBeCalledWith('', {});
});
});
unit test result:
PASS examples/65924278/index.test.ts (10.748 s)
65924278
√ should pass (13 ms)
----------|---------|----------|---------|---------|-------------------
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: 13.15 s
So just trying to understand how I mock a class function within a function itself. How do I mock the data returned from the exchange.someFunction() method so I can test the actual getPositions() function itself?
const library = require('library');
const exchange = new library.exchange_name();
async function getPositions() {
let positions = [];
const results = await exchange.someFunction();
// Do some stuff
return results;
}
I was trying to do the following but have no idea if I'm doing anything correct at all
const exchange = require('../../exchange');
jest.mock('library')
it('get balances', async () => {
library.someFunction.mockResolvedValue({
data: [{some data here}]
)}
}
Error thrown:
TypeError: Cannot read property 'mockResolvedValue' of undefined
Here is the unit test solution:
index.js:
const library = require('./library');
const exchange = new library.exchange_name();
async function getPositions() {
let positions = [];
const results = await exchange.someFunction();
return results;
}
module.exports = getPositions;
library.js:
function exchange_name() {
async function someFunction() {
return 'real data';
}
return {
someFunction,
};
}
module.exports = { exchange_name };
index.test.js:
const getPositions = require('./');
const mockLibrary = require('./library');
jest.mock('./library', () => {
const mockExchange = { someFunction: jest.fn() };
return { exchange_name: jest.fn(() => mockExchange) };
});
describe('61649788', () => {
it('get balances', async () => {
const mockExchange = new mockLibrary.exchange_name();
mockExchange.someFunction.mockResolvedValueOnce({ data: ['mocked data'] });
const actual = await getPositions();
expect(actual).toEqual({ data: ['mocked data'] });
expect(mockExchange.someFunction).toBeCalled();
});
});
unit test results with 100% coverage:
PASS stackoverflow/61649788/index.test.js (8.775s)
61649788
✓ get balances (7ms)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
index.js | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 10.099s
I am trying to mock AWS.SNS and I am getting error. I referred posts on StackOverflow and could come up with below. Still, I am getting an error. I have omitted the irrelevant portion. Can someone please help me?
Below is my index.ts
import { SNS } from "aws-sdk";
export const thishandler = async (event: thisSNSEvent): Promise<any> => {
// I have omitted other code that works and not related to issue I am facing.
// I am receiving correct value of 'snsMessagetoBeSent' I verified that.
const response = await sendThisToSNS(snsMessagetoBeSent);
} // thishandler ends here
async function sendThisToSNS(thisMessage: snsAWSMessage) {
const sns = new SNS();
const TOPIC_ARN = process.env.THIS_TOPIC_ARN;
var params = {
Message: JSON.stringify(thisMessage), /* required */
TopicArn: TOPIC_ARN
};
return await sns.publish(params).promise();
}
My test case is below
jest.mock('aws-sdk', () => {
const mockedSNS = {
publish: jest.fn().mockReturnThis(),
promise: jest.fn()
};
return {
SNS: jest.fn(() => mockedSNS),
};
});
import aws, { SNS } from 'aws-sdk';
const snsPublishPromise = new aws.SNS().publish().promise;
import { thishandler } from "../src/index";
describe("async testing", () => {
beforeEach(() => {
jest.restoreAllMocks();
jest.resetAllMocks();
});
it("async test", async () => {
const ENRICHER_SNS_TOPIC_ARN = process.env.ENRICHER_SNS_TOPIC_ARN;
process.env.ENRICHER_SNS_TOPIC_ARN = "OUR-SNS-TOPIC";
const mockedResponseData ={
"Success": "OK"
};
(snsPublishPromise as any).mockResolvedValueOnce(mockedResponseData);
const result = await thishandler(thisSNSEvent);
});
I get error as TypeError: sns.publish is not a function
Here is the unit test solution:
index.ts:
import { SNS } from 'aws-sdk';
export const thishandler = async (event): Promise<any> => {
const snsMessagetoBeSent = {};
const response = await sendThisToSNS(snsMessagetoBeSent);
return response;
};
async function sendThisToSNS(thisMessage) {
const sns = new SNS();
const TOPIC_ARN = process.env.THIS_TOPIC_ARN;
const params = {
Message: JSON.stringify(thisMessage),
TopicArn: TOPIC_ARN,
};
return await sns.publish(params).promise();
}
index.test.ts:
import { thishandler } from './';
import { SNS } from 'aws-sdk';
jest.mock('aws-sdk', () => {
const mSNS = {
publish: jest.fn().mockReturnThis(),
promise: jest.fn(),
};
return { SNS: jest.fn(() => mSNS) };
});
describe('59810802', () => {
let sns;
beforeEach(() => {
sns = new SNS();
});
afterEach(() => {
jest.clearAllMocks();
});
it('should pass', async () => {
const THIS_TOPIC_ARN = process.env.THIS_TOPIC_ARN;
process.env.THIS_TOPIC_ARN = 'OUR-SNS-TOPIC';
const mockedResponseData = {
Success: 'OK',
};
sns.publish().promise.mockResolvedValueOnce(mockedResponseData);
const mEvent = {};
const actual = await thishandler(mEvent);
expect(actual).toEqual(mockedResponseData);
expect(sns.publish).toBeCalledWith({ Message: JSON.stringify({}), TopicArn: 'OUR-SNS-TOPIC' });
expect(sns.publish().promise).toBeCalledTimes(1);
process.env.THIS_TOPIC_ARN = THIS_TOPIC_ARN;
});
});
Unit test results with 100% coverage:
PASS src/stackoverflow/59810802/index.test.ts (13.435s)
59810802
✓ should pass (9ms)
----------|----------|----------|----------|----------|-------------------|
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: 15.446s
Source code: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/59810802