Nodejs - class with async await does nothing - node.js

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

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

Sinon Fake Timer Call multiple Times In Test Only Firing Once

I have a function that calls itself recursively until the function it's calling is done.
Here is the function under test (I have modified it in order to post on Stackoverflow as it is proprietary.):
private async awaitQueryCompletion(queryId: string): Promise<void> {
setTimeout(async () => {
const output: ExecutionOutput =
await this.getQueryExecution({ QueryExecutionId: queryId }).promise();
let state: string | undefined;
if (ExecutionOutput.QueryExecution !== undefined && ExecutionOutput.QueryExecution.Status) {
state = ExecutionOutput.QueryExecution.Status.State;
}
if (state !== undefined && state === "RUNNING") {
await this.awaitQueryCompletion(queryId);
}
}, this.RETRY_INTERVAL);
}
Here is my test:
Setup:
beforeEach(() => {
sandbox = createSandbox();
getQueryExecutionStub = sandbox.stub(QueryClass, "getQueryExecution")
timer = sandbox.useFakeTimers({ shouldAdvanceTime: true});
});
it.only("Should call getQueryExecution twice with correct params", async () => {
const INTERVAL: number = 5010;
getQueryExecutionStub.onFirstCall()
.returns({
promise: async (): Promise<ExecutionOutput> => {
return Promise.resolve({
QueryExecution: {
Status: {
State: "RUNNING"
}
}
});
}
});
getQueryExecutionStub.onSecondCall()
.returns({promise: async (): Promise<ExecutionOutput> => {
return Promise.resolve({
QueryExecution: {
Status: {
State: "SUCCEEDED"
}
}
});
}
});
await selector.query(testInput);
timer.tick(INTERVAL);
timer.tick(INTERVAL);
expect(getQueryExecutionStub.calledTwice).to.equal(true);
});
});
What I want is for the getQueryExecutionStub to be called twice so I'm mocking the setTimeout function and trying to act as thought two cycles of the timeout have happened. I get it to run the timeout once but I can't figure out how to make it run again. Any and all help would be greatly appreciated! I've looked through both the lolex docs:(https://github.com/sinonjs/lolex) and sinon fake timers docs (https://sinonjs.org/releases/v8.0.4/fake-timers/).
So I was able to figure this out after a little digging.
private async awaitQueryCompletion(queryId: string, context: Context): Promise<void> {
return new Promise(async (resolve: Function, reject: Function): Promise<void> => {
// tslint:disable-next-line: no-inferred-empty-object-type
this.timeout(async () => {
try {
log.debug("Checking query completion");
const queryExecutionOutput: Athena.GetQueryExecutionOutput =
await this.athenaClient.getQueryExecution({ QueryExecutionId: queryId }).promise();
let state: string | undefined;
if (queryExecutionOutput.QueryExecution !== undefined
&& queryExecutionOutput.QueryExecution.Status !== undefined) {
state = queryExecutionOutput.QueryExecution.Status.State;
}
if (state !== undefined && state === "RUNNING") {
if (context.getRemainingTimeInMillis() > this.TIMEOUT_PADDING_MS) {
await this.awaitQueryCompletion(queryId, context);
resolve();
} else {
log.error(`Failure: Unable to complete query before lambda shut down...`);
reject();
}
} else if (state === "SUCCEEDED") {
resolve();
} else if (state === "FAILED") {
throw new Error(state);
} else {
log.error("Unable to determine the state of the query...");
reject();
}
} catch (e) {
log.error(`${JSON.stringify(e)}`);
return reject(e);
}
}, this.RETRY_INTERVAL_MS);
});
}
What I needed was to wrap my function in a promise and after each tick resolve that promise to the next tick could fire.

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

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;
}
}
}
}

How to run same promises one after another NodeJs

I am trying to solve the following problem.
Consider the following case. I need to check if an array of servers is alive. Or to be more specific I need to find the first working server from the provided list, I need to do this one by one.
For example if the first server doesn't work, check another and another ...
As far as NodeJS is asynchronous I cannot do this in a for loop. So I tried to implement something similar to recursion, it looks ugly and doesn't work, but I've tried)
static findWorkingServer(servers, payload) {
return NetworkUtils.getMyPublicIP()
.then((ip) => {
return new Promise(function (resolve, reject) {
let currentIndex = -1;
if (servers.length > 0) {
let currentServer;
let serverCheckCallback = function (result) {
if (result) {
resolve({working: currentServer, payload: payload});
}
else {
if (currentIndex < servers.length-1) {
currentIndex++;
currentServer = servers[currentIndex];
NetworkUtils.checkIfServerWorking(currentServer, ip)
.then(serverCheckCallback);
}
else {
reject(new Error("No working servers found"))
}
}
};
serverCheckCallback(false);
}
else {
resolve(new Error("No servers provided"));
}
})
});
}
static checkIfServerWorking(credentials, publicIp) {
return new Promise(function (resolve, reject) {
if(credentials) {
request({
url: credentials.url,
agentClass: agentClass,
agentOptions: {
// Agent credentials
}
})
.then(res => {
// Do some stuff with resposne
resolve(someCondition);
})
.catch(err => {
resolve(false);
});
}else {
resolve(false);
}
});
}
Please help to get the desired result, maybe it is possible to run requests synchronously.
Could be done with await/async:
let servers = ["test0.com","test1.com","test2.com","test3.com","test4.com"]
class ServerTest {
static async checkServer(name) {
if (name === "test3.com")
return true //returns promise that resolves with true
else
return false //returns promise that resolves with false
}
}
(async()=>{ //IIFE (await can only be used in async functions)
let targetServer
for (i in servers) {
if (await ServerTest.checkServer(servers[i]) === true) {
targetServer = servers[i]
break
}
}
console.log("Found a working server: " + targetServer)
})()

Herarchy query using sequelize / nodejs

I am trying to load a hierarchy in my database. I have a column with parentId in my table so every row can have a parent. But I am having problems using recursion and promises.
function read (options) {
return serviceItemAttributeModel.findOne({
id: options.id,
id_organization: options.idOrganization
})
.then((attribute) => {
if (attribute) {
return loadChildren(attribute, attribute);
} else {
return attribute;
}
});
}
function loadChildren (root, attribute) {
return serviceItemAttributeModel.findAll({
where: {
id_parent: attribute.id
}
})
.then((attributes) => {
if (!attributes) {
return root;
} else {
attribute.serviceItemAttributes = [];
attributes.forEach(function (each) {
attribute.serviceItemAttributes.push(each);
return loadChildren(root, each);
});
}
});
}
So, I call read that calls loadChildren to recursively try to load all entities (by looking children of an entity) and I get an undefined value. Any ideas?
I am also getting an error on console: a promise was created in a handler but was not returned from it.
EDIT:
Came up if this solution after Nosyara help. thanks!:
function read (options) {
return serviceItemAttributeModel.findOne({
where: {
id: options.attributeId,
id_organization: options.idOrganization
}
})
.then((attribute) => {
if (!attribute) {
return new Promise(function (resolve, reject) {
resolve(attribute);
});
} else {
return new Promise(function (resolve, reject) {
attribute.queryCount = 1;
resolve(attribute);
})
.then((attribute) => loadChildren(attribute, attribute));
}
});
}
function loadChildren (root, attribute) {
return new Promise(function (resolve, reject) {
return serviceItemAttributeModel.findAll({
where: {
id_parent: attribute.id
}
})
.then((attributes) => {
attributes.length = attributes.length || 0;
root.queryCount = root.queryCount - 1 + attributes.length;
if (root.queryCount === 0) {
resolve(root);
} else if (root.queryCount > 10) {
let error = new Error('Service attribute hierarchy cant have more then 10 levels');
error.statusCode = 500;
reject(error);
} else {
attribute.serviceItemAttributes = [];
attributes.forEach(function (each) {
attribute.serviceItemAttributes.push(each);
return loadChildren(root, each).then(() => {
resolve(root);
});
});
}
});
});
}
You messing up with async calls and returns. You can convert both function to async, and pass through result structure to be updated. Example:
function read(...) {
return new Promise(function (accept, reject) {
// You code goes here, but instead of return
accept(resultFromAsyncFunction);
});
}
// ...
read(...).then(function(resultData) { ... });
Here is example of Promise recursion.

Resources