Mocha's test code using ts-mockito does not work - node.js

mocha + chai + ts-mockito is executing unit-test of the node.js application.
In order to test the Service class, we mock the method of the Repository class which is called in the Service class.
Running will not work as expected.
I expect ErrorDto, but the string "TypeError: Can not read property 'then' of null" will be returned.
Please tell me something is wrong.
Test code.
let mockedRepository: MyRepository = tsmockito.mock(MyRepository);
describe("MyService Test", () => {
it("getAll() test", async () => {
const errorDto = new ErrorDto();
errorDto.addMessage("test message");
tsmockito.when(mockedRepository.getAll()).thenCall(() => {
return new Promise((resolve, reject) => {
reject(errorDto);
});
});
let mockedRepositoryInstance: MyRepository = tsmockito.instance(mockedRepository);
Container.set(MyRepository, mockedRepositoryInstance);
let service = new MyService();
let res = await service.getAll();
// I expect ErrorDto for res,
// but "TypeError: Can not read property 'then' of null" is returned.
if (res instanceof ErrorDto) {
// Do not reach below
let msg = res.getMessages();
expect(msg[0]).to.eql("test message");
} else {
// Test failure
expect(true).to.false;
}
});
});
Service class to be tested
#Service()
export default class MyService {
#Log()
public getAll() {
const repository = Container.get(MyRepository);
return new Promise<MyServiceTreeDto[]>((resolve, reject) => {
repository.getAll()
.then((res: MyTreeDomain[]) => {
const resDto = new Array<MyServiceTreeDto>();
//do something...
resolve(resDto);
}).catch((err) => {
reject(err);
});
});
}
}
Repository class to be mocked
#Service()
export default class MyRepository {
public async getAll(domain: MyDomain): Promise<MyTreeDomain[]> {
try {
let res: MyTreeDomain[] = new Array<MyTreeDomain>();
//do async process
return res;
} catch (err) {
if (err instanceof ErrorDto) {
throw err;
} else {
const errorDto = new ErrorDto();
errorDto.addMessage("error!");
throw errorDto;
}
}
}
}

Related

Jest Mocking: TypeError: this.A.getDynamoEntry is not a function

I have a class A that is using another class(B)'s method. I am trying to write test for the class B and mocking the methods of the class A. But even if I mock, I am getting TypeError: this.A.getDynamoEntry is not a function. I have followed exactly the same steps given by the docs.
test.js file:
import A from '../../src/dao/A'
import B from '../../src/dao/B'
jest.mock('../../src/dao/A', () => {
return jest.fn().mockImplementation(() => {
return {
getDynamoEntry: jest.fn(()=> Promise.resolve(2)),
putDynamoEntry: jest.fn(),
updateDynamoEntry: jest.fn(),
deleteDynamoEntry: jest.fn()
};
});
});
beforeAll(() => {
initConfig()
})
describe('Test', () => {
let entity
beforeEach(() => {
entity = new B()
})
it('getFraudLogosByOwnerId', async () => {
const resp = await entity.getFraudLogosByOwnerId(913035121393899)
expect(resp).toBe(2)
})
})
class A:
class A {
constructor(tableName, dynamoClient) {
this.dynamoClient = dynamoClient
this.tableName = tableName
}
async getDynamoEntry(query) {
try {
return await this.dynamoClient.query(query).promise()
} catch (error) {
throw error
}
}
async putDynamoEntry(imageEntity) {
try {
return await this.dynamoClient.put({ TableName: this.tableName, Item: imageEntity }).promise()
} catch (error) {
throw error
}
}
async updateDynamoEntry(params) {
try {
return await this.dynamoClient.update(params).promise()
} catch (error) {
throw error
}
}
async deleteDynamoEntry(criteria) {
try {
return await this.dynamoClient.delete(criteria).promise()
} catch (error) {
throw error
}
}
}
module.exports = A
Class B:
const dynamoQueryHelper = require('./DynamoQueryHelper')
const A = require('./A')
class B {
constructor() {
this.A = new A("table1", "client1")
}
async getFraudLogosByOwnerId(ownerId) {
const query = dynamoQueryHelper.getQuery("123", "table1")
try {
return await this.A.getDynamoEntry(query)
} catch (error) {
IPSLogger.logError(
error,
LogConstants.FRAUD_DATA_ACCESS_DAO,
LogConstants.GET_FRAUD_LOGO,
ownerId,
LogConstants.LOG_GET_FRAUD_IMAGE_BY_OWNER_ID.replace(LogConstants.PLACEHOLDER, ownerId)
)
throw error
}
}
}
module.exports = B
I tried the steps given in https://jestjs.io/docs/es6-class-mocks but to no avail

Nodejs - class with async await does nothing

I am fairly new to Node.JS, but have some experience in other languages. I am trying to achieve the following:
I want to perform a task and if it fails perform another task.
I have two files: one is the main function, the other contains the class.
First the main function (main.js):
(async function main() {
let { MyClass } = require("./my_class.js");
const mc = new MyClass();
await mc.do_stuff();
console.log(mc.message);
})();
The other is the class (my_class.js)
class MyClass {
constructor() {
this.message='hello';
}
do_stuff=async function() {
return new Promise((resolve,reject) => async function (){
let [res,rej]=await do_first('fail');
if(rej) {
console.log('do_first() failed.');
[res,rej]=await do_second('succeed');
if(rej) {
console.log('do_second() failed.');
reject('failed');
} else {
console.log('do_second() succeeded.');
resolve('success');
}
} else {
console.log('do_first() succeeded, no call to do_second().');
resolve('success');
}
});
}
do_first=async function(param) {
return new Promise((resolve,reject) => {
if(param==='fail') {
console.log('rejecting do_first()');
reject('failure');
} else {
console.log('resolving do_first()');
resole('success');
}
});
}
do_second=async function(param) {
return new Promise((resolve,reject) => {
if(param==='fail') {
console.log('rejecting do_second()');
reject('failure');
} else {
console.log('resolving do_second()');
resole('success');
}
});
}
}
exports.MyClass = MyClass
If I try to run it with node ./main.js nothing happens. If I run mc.do_stuff() without the await, I do get the hello... Which boats am I missing?
For that matter: I am running NodeJS v18.12.0
A few things need to be changed here to make it work:
When using await, only the Promise.resolve comes back to regular code execution. Promise.reject always raises an Exception.
Typo resole
changed code to consistently use arrow syntax. This requires referencing functions as instance members -> this.do_first. I suppose this was your intention. The syntax before did not execute the function as part of the object, but in global scope.
Here's your code in a working state
class MyClass {
constructor() {
this.message = "hello";
}
do_stuff = async () => {
return new Promise(async (resolve, reject) => {
try {
await this.do_first("fail");
console.log("do_first() succeeded, no call to do_second().");
resolve("success");
} catch (err) {
console.log("do_first() failed.");
try {
await this.do_second("succeed");
console.log("do_second() succeeded.");
resolve("success");
} catch (err) {
console.log("do_second() failed.");
reject("failed");
}
}
});
};
do_first = async (param) => {
return new Promise(async (resolve, reject) => {
if (param === "fail") {
console.log("rejecting do_first()");
reject("failure");
} else {
console.log("resolving do_first()");
resolve("success");
}
});
};
do_second = async (param) => {
return new Promise((resolve, reject) => {
if (param === "fail") {
console.log("rejecting do_second()");
reject("failure");
} else {
console.log("resolving do_second()");
resolve("success");
}
});
};
}
exports.MyClass = MyClass;
PS C:\Users\patrick\Documents\GitHub\stackoverflow-74714360> node ./main.js
rejecting do_first()
do_first() failed.
resolving do_second()
do_second() succeeded.
hello

Jest Unit Test for Node Service having async methods

I'm getting below errors. Why I'm receiving response as undefined from the service?
Is there anything wrong I did for providing mock implementations?
Service:
export class SaveDataService{
async save() : Promise<any> {
try{
return this.someFunction()
} catch(ex){
throw new Error('some error occured')
}
}
async someFunction() : Promise<any>{
const response = {
"file" : "<htm><body>This is sample response</body></html>"
}
return Promise.resolve(response);
}
}
Test/Spec file:
import { SaveDataService } from "./save-data.service";
jest.mock('./save-data.service')
describe('tests for SaveDataService', () => {
it('when save method is called and success result is returned', async () => {
let mockSaveDataServiceSomeFunction = jest.fn().mockImplementation(() => {
return Promise.resolve('Success Result')
});
SaveDataService.prototype.someFunction = mockSaveDataServiceSomeFunction;
let spy = jest.spyOn(SaveDataService.prototype, 'someFunction');
let service = new SaveDataService();
let data = await service.save()
expect(data).toEqual('Success Result')
expect(spy).toHaveBeenCalled()
})
it('when save method is called and error is returned', async () => {
let mockSaveDataServiceSomeFunction = jest.fn().mockImplementation(() => {
throw new Error('ERROR')
});
SaveDataService.prototype.someFunction = mockSaveDataServiceSomeFunction;
let spy = jest.spyOn(SaveDataService.prototype, 'save');
let service = new SaveDataService();
service.save()
expect(spy).toThrowError('ERROR')
})
})
A mock replaces the dependency. You set expectations on calls to the dependent object, set the exact return values it should give you to perform the test you want, and/or what exceptions to throw so that you can test your exception handling code.
In this scenario, you are mocking save-data.service by calling jest.mock('./save-data.service'). So that your class may looks like this:
async save() : Promise<any> {
// do nothing or undefined
}
async someFunction() : Promise<any> {
// do nothing or undefined
}
So you must implement the body yourself to expect what exactly you want the method/function to do for you. You are mocking only the someFunction:
...
let mockSaveDataServiceSomeFunction = jest.fn().mockImplementation(() => {
return Promise.resolve('Success Result')
});
SaveDataService.prototype.someFunction = mockSaveDataServiceSomeFunction;
...
So when you call the save() method you still get nothing/undefined.
You are overwriting the whole behavior of the service that I think your test may not be useful. But you can fix your test this way:
import { SaveDataService } from "./save-data.service";
jest.mock('./save-data.service');
describe('tests for SaveDataService', () => {
beforeEach(() => {
SaveDataService.mockClear();
});
it('when save method is called and success result is returned', async () => {
const spy = jest
.spyOn(SaveDataService.prototype, 'save')
.mockImplementation(async () => Promise.resolve('Success Result'));
const service = new SaveDataService();
const data = await service.save();
expect(data).toEqual('Success Result');
expect(spy).toHaveBeenCalled();
})
it('when save method is called and error is returned', async () => {
const spy = jest
.spyOn(SaveDataService.prototype, 'save')
.mockImplementation(() => {
throw new Error('ERROR');
});
const service = new SaveDataService();
expect(service.save).toThrowError('ERROR');
expect(spy).toHaveBeenCalled();
});
});

Calling a function return Promise

I was trying to implement Promises when I get error saying
TypeError: productService.getSwapItems is not a function
I have created a DB class as
const mysql = require('mysql')
class Database {
constructor( config ) {
this.connection = mysql.createConnection( config );
}
query(sql, args) {
return new Promise( (resolve, reject) => {
this.connection.query(sql, args, (error, result) => {
if(error) {
return reject(error);
}
resolve(result);
});
});
}
close() {
return new Promise( (resolve, reject) => {
this.connection.end( err => {
if(err) {
return reject(err);
}
resolve();
})
});
}
}
module.exports = Database;
And then a service class
let Database = require('./mysql.db');
const database = new Database({
host: "db-host",
user: "username",
password: "password",
database: "databasename"
});
class ProductService {
getSwapItems(item_ids_array) {
this.queryStr = "SELECT * FROM Item WHERE from_item_id IN (" + item_ids_array + ")";
return database.query(this.queryStr, null); // database.query returns a promise, so getSwapItems() will also return promise??
}
}
module.exports = ProductService;
When productService using code below, I get error.
var item_ids_array = <Array Values>;
productService.getSwapItems(item_ids_array)
.then( rows => {
console.log(rows);
}).catch( err => {
console.log(err);
});
Error is
productService.getSwapItems(item_ids_array)
TypeError: productService.getSwapItems is not a function
Your module exports a class ProductService with regular method getSwapItems. Classes are first-class citizens in JS, so you can assign them (as value) to any variable any way you like - including require-ing a module.
const ProductService = require('./db/product.service');
But the class is like a recipe for creating an instance of the class you can use, not an instance of the class itself. To actually create an instance of the class, use the new keyword:
const productService = new ProductService();
Only after that you'll be able to use methods of this class the usual way.

Mock Constructor in ES6 class in NODE using SINON

service.js
Class ClassWithConstructor {
constructor(arg1, arg2) {
super();
this.param1 = arg1;
this.param2 = arg2;
}
getInfo() {
//returns promise
}
}
controller.js
export function getData(req, res) {
const svc = new ClassWithConstructor.ClassWithConstructor(req.user.param1, req.user.param2);
svc.getInfo()
.then(result => {
return respondWithSearchResult(res, 200, result, 'success');
})
.catch(err => {
//return error
});
}
For unit test getData() method I need to mock the line const svc = new ClassWithConstructor.ClassWithConstructor(req.user.param1, req.user.param2);
I am using Sinon for mocking. I have been trying for a long. Can someone help me out?

Resources