Jest: Mock class method in a function - javascript

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

Related

How to jest.mock "git-simple" branchLocal function?

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"

how to test cheerio js

this is my code and i don't know how to write test for it:
html.js
const getHtml = async (url) => {
const { data } = await axios.get(url);
return data;
};
const cheerioInit = async (url) => cheerio.load(await getHtml(url));
module.exports = {
cheerioInit,
getHtml
};
i think i should mock this, but don't know how to do that. i wrote this but getting error:
const htmlJs = require("./html");
describe("html", () => {
it("initializes cheerio js", () => {
const mock = jest.spyOn(htmlJs, "cheerioInit");
expect(mock).toHaveBeenCalled();
});
});
this is error:
You can use jest.spyOn(object, methodName) to mock axios.get() method and its resolved value and mock cheerio.load() method with a fake implementation. After executing the getHtml and cheerioInit functions, make assertion for above mocks to check if they have been called with specific arguments.
E.g.
html.js:
const axios = require('axios');
const cheerio = require('cheerio');
const getHtml = async (url) => {
const { data } = await axios.get(url);
return data;
};
const cheerioInit = async (url) => cheerio.load(await getHtml(url));
module.exports = {
cheerioInit,
getHtml,
};
html.test.js:
const { getHtml, cheerioInit } = require('./html');
const axios = require('axios');
const cheerio = require('cheerio');
describe('html', () => {
afterEach(() => {
jest.restoreAllMocks();
});
describe('getHtml', () => {
it('should get html', async () => {
const getSpy = jest.spyOn(axios, 'get').mockResolvedValueOnce({ data: '<div>teresa teng</div>' });
const actual = await getHtml('http://localhost:3000');
expect(actual).toEqual('<div>teresa teng</div>');
expect(getSpy).toBeCalledWith('http://localhost:3000');
});
});
describe('cheerioInit', () => {
it('should initializes cheerio', async () => {
const loadSpy = jest.spyOn(cheerio, 'load').mockImplementation();
const getSpy = jest.spyOn(axios, 'get').mockResolvedValueOnce({ data: '<div>teresa teng</div>' });
await cheerioInit('http://localhost:3000');
expect(loadSpy).toHaveBeenCalledWith('<div>teresa teng</div>');
});
});
});
unit test result:
PASS examples/66304918/html.test.js
html
getHtml
✓ should get html (3 ms)
cheerioInit
✓ should initializes cheerio
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
html.js | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 4.088 s

How to check if mocked inner function has been called in jest?

here is my file under test:
file.js:
function handleRequest(grpcRequestObj, callback){
if(grpcRequestObj.type === REAL_CLIENT_REQUEST){
log.trace("Запрос от реального клиента", refId);
module.exports.realClientRequestWay(grpcRequestObj, callback);
return;
}
}
function realClientRequestWay(grpcRequestObj, callback){
//some logic
}
module.exports = {
handleRequest,
realClientRequestWay
}
test file:
test("should call real clients way", ()=>{
jest.mock("../lib/grpc/state");
const state = require("../lib/grpc/state");
state.ready = true;
const constants = require("../lib/grpc/constants");
const handleRequestModule = require("../lib/grpc/handleRequest");
const { handleRequest } = jest.requireActual("../lib/grpc/handleRequest");
handleRequestModule.realClientRequestWay = jest.fn();
const grpcRequest = {
type: constants.REAL_CLIENT_REQUEST,
refId: "123"
};
const mockCb = jest.fn();
handleRequest(grpcRequest, mockCb);
expect(handleRequestModule.realClientRequestWay).toHaveBeenCalledTimes(1);
});
I am mocking realClientRequestWay fucntion to be a jest mock function just to check if it runs,
but it is not calling, what am I doing wrong?
You can use jest.spyOn(object, methodName) and mockImplementation to overwrite the original function with a mocked one.
E.g.
file.js:
const log = { trace: console.log };
const REAL_CLIENT_REQUEST = 'REAL_CLIENT_REQUEST';
function handleRequest(grpcRequestObj, callback) {
const refId = '1';
if (grpcRequestObj.type === REAL_CLIENT_REQUEST) {
log.trace('Запрос от реального клиента', refId);
module.exports.realClientRequestWay(grpcRequestObj, callback);
return;
}
}
function realClientRequestWay(grpcRequestObj, callback) {
//some logic
}
module.exports = {
handleRequest,
realClientRequestWay,
};
file.test.js:
const file = require('./file');
describe('62079376', () => {
afterEach(() => {
jest.restoreAllMocks();
});
it('should request', () => {
jest.spyOn(file, 'realClientRequestWay').mockImplementationOnce();
const mCallback = jest.fn();
file.handleRequest({ type: 'REAL_CLIENT_REQUEST' }, mCallback);
expect(file.realClientRequestWay).toBeCalledWith({ type: 'REAL_CLIENT_REQUEST' }, mCallback);
});
it('should do nothing if type not match', () => {
jest.spyOn(file, 'realClientRequestWay').mockImplementationOnce();
const mCallback = jest.fn();
file.handleRequest({ type: '' }, mCallback);
expect(file.realClientRequestWay).not.toBeCalled();
});
});
unit test results with 100% coverage:
PASS stackoverflow/62079376/file.test.js (10.044s)
62079376
✓ should request (16ms)
✓ should do nothing if type not match (1ms)
console.log
Запрос от реального клиента 1
at Object.handleRequest (stackoverflow/62079376/file.js:7:9)
----------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
----------|---------|----------|---------|---------|-------------------
All files | 100 | 100 | 100 | 100 |
file.js | 100 | 100 | 100 | 100 |
----------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 11.393s, estimated 12s

How to mock external function call in jest test

Here is my Node.js module to test (userdata.js file):
const myService = require('./my-service')
class UserData {
getData(query) {
return new Promise((resolve, reject) => {
myService.getUserData(query)
.then((userdata) => {
myService.getManagerData(userdata)
.then((managerdata) => {
resolve(managerdata)
})
})
})
}
}
module.exports = UserData
and test file:
const UserData = require('/.userdata')
test('UserData.getData', () => {
expect(UserData.getData('John Smith')).toBe('John\' manager');
});
I want to mock myService.getUserData and/or myService.getManagerData functions call that I'm not directly declare in test file.. How do I mock them properly to return some dummy result?
You can use jest.spyOn(object, methodName) to make stub for myService.getUserData and myService. getManagerData methods.
E.g.
userData.js:
const myService = require('./myService');
class UserData {
getData(query) {
return new Promise((resolve, reject) => {
myService.getUserData(query).then((userdata) => {
myService.getManagerData(userdata).then((managerdata) => {
resolve(managerdata);
});
});
});
}
}
module.exports = UserData;
myService.js:
const myService = {
getUserData(query) {
return 'real user data';
},
getManagerData(userdata) {
return 'real manager data';
},
};
module.exports = myService;
userData.test.js:
const UserData = require('./userData');
const myService = require('./myService');
describe('61784452', () => {
afterEach(() => {
jest.restoreAllMocks();
});
it('should pass', async () => {
jest.spyOn(myService, 'getUserData').mockResolvedValueOnce('fake user data');
jest.spyOn(myService, 'getManagerData').mockResolvedValueOnce('fake manager data');
const userData = new UserData();
const actual = await userData.getData('query');
expect(actual).toEqual('fake manager data');
expect(myService.getUserData).toBeCalledWith('query');
expect(myService.getManagerData).toBeCalledWith('fake user data');
});
});
unit test results with coverage report:
PASS stackoverflow/61784452/userData.test.js (12.908s)
61784452
✓ should pass (5ms)
--------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
--------------|---------|----------|---------|---------|-------------------
All files | 84.62 | 100 | 71.43 | 84.62 |
myService.js | 50 | 100 | 0 | 50 | 3-6
userData.js | 100 | 100 | 100 | 100 |
--------------|---------|----------|---------|---------|-------------------
Test Suites: 1 passed, 1 total
Tests: 1 passed, 1 total
Snapshots: 0 total
Time: 13.99s

How to mock object creation and its method

new UrlBuilder(urlString).buildURL(params).getShortenedURL().then(data => {
.....
});
How can I stub the object creation and check whether getShortenedURL() has been called?
I tried
this.urlBuilder = sinon.stub(UrlBuilder.prototype, getShortenedURL).resolves({url: '/someUrl'});
But every time I run a test that has:
assert(this.urlBuilder.getShortenedURL.called);
it'll say
ReferenceError: getShortenedURL is not defined
Here is the unit test solution:
index.js:
const UrlBuilder = require('./urlBuilder');
function main() {
const urlString = 'https://stackoverflow.com/';
const params = {};
return new UrlBuilder(urlString)
.buildURL(params)
.getShortenedURL()
.then((data) => data);
}
module.exports = main;
urlBuilder.js:
class UrlBuilder {
constructor(url) {
this.url = url;
}
buildURL(params) {
return this;
}
getShortenedURL() {
return Promise.resolve('real data');
}
}
module.exports = UrlBuilder;
index.test.js:
const sinon = require('sinon');
const proxyquire = require('proxyquire');
const { expect } = require('chai');
describe('60214679', () => {
it('should pass', async () => {
const urlBuilderInstanceStub = {
buildURL: sinon.stub().returnsThis(),
getShortenedURL: sinon.stub().resolves('fake data'),
};
const urlBuilderStub = sinon.stub().callsFake(() => urlBuilderInstanceStub);
const main = proxyquire('./', {
'./urlBuilder': urlBuilderStub,
});
const actual = await main();
expect(actual).to.be.eq('fake data');
sinon.assert.calledWithExactly(urlBuilderStub, 'https://stackoverflow.com/');
sinon.assert.calledWithExactly(urlBuilderInstanceStub.buildURL, {});
sinon.assert.calledOnce(urlBuilderInstanceStub.getShortenedURL);
});
});
Unit test results with coverage report:
60214679
✓ should pass (2010ms)
1 passing (2s)
---------------|---------|----------|---------|---------|-------------------
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s
---------------|---------|----------|---------|---------|-------------------
All files | 70 | 100 | 40 | 70 |
index.js | 100 | 100 | 100 | 100 |
urlBuilder.js | 25 | 100 | 0 | 25 | 3,6,9
---------------|---------|----------|---------|---------|-------------------
Source code: https://github.com/mrdulin/expressjs-research/tree/master/src/stackoverflow/60214679

Categories

Resources