How to wait for the end of the function - javascript

I have some task.
I'm creating my library which has a connection function written in it (several processes are included) and a creation function.
Need to clarify. The library doesn't deal with any http/https requests. Everything happens locally and without server requests.
Code from the testing side of the library
module.exports = async function connect(argument) {
const { save, models } = argument;
var prom = new Promise((resolve, reject) => {
setTimeout(() => {
checkDir(models);
// check models
checkBaseModels(models);
checkModels(models);
resolve();
});
});
prom.then(() => {
return new Promise((resolve, reject) => {
setTimeout(() => {
loadModels();
resolve();
}, 2000);
});
}).then(() => {
setTimeout(() => {
saveModels(save);
models_list();
});
});
};
const cloud = require('cloud');
const cloud = cloud.connect({ save: 1000 });
const create = cloud.create({
name: "Test",
description: "Abc"
});
What can be used to make other processes stop while the connection in my library is running.
I need to somehow fix this problem without using setTimeout and so on in the test. It is desirable to leave this code as it is.
I need to connect first, and then create.
The code on the test side, if possible, should preferably not be edited.

connect function is not returning the promise
module.exports.connect = async function connect(argument) {
// ...
return prom;
}
Connection file
(async () => {
const cloud = await cloud.connect({ save: 1000 });
const create = cloud.create({
name: "Test",
description: "Abc",
});
})();

Related

Node.js and Jest: Testing promise loop, count how many times function has been called

I want to test my code using JEST, but I'm having some issues. I want to check, if restart() function has been called.
My code works like this, it's waiting for the data, and if there's no data it's calling the same function again. Basically something like a loop.
myCode.js file:
module.exports = {
getSomething: async () => {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve("");
}, 1000);
});
},
doSomething: async () => {
const data = await module.exports.getSomething();
if (!data) {
return module.exports.restart();
}
return data;
},
restart: async () => {
return module.exports.doSomething();
}
};
myCode.test.js file:
const myCode = require("./exampleCode")
describe("test", () => {
test("Is it doing something more than once?", async () => {
const restartSpy = jest.spyOn(myCode, 'restart');
myCode.doSomething()
expect(restartSpy).toHaveBeenCalledTimes(1);
})
})
My problem is that expect(restartSpy).toHaveBeenCalledTimes(1); is returning false.
The question is - what I'm doing wrong? Is there a way to test this code?
The main problem here is the lack of await before myCode.doSomething(). All your functions are asynchronous, so you need to wait for them to finish before checking the spy:
await myCode.doSomething();
Another issue is the fact that it's an infinite recursion loop - jest will timeout after 5000ms (by default) if you won't modify the code that is calling restart, for example:
doSomething: async (restartCounter = 0) => {
const data = await module.exports.getSomething();
if (!data && ++restartCounter < 2) {
return module.exports.restart(restartCounter);
}
return data;
},
restart: async (restartCounter) => {
return module.exports.doSomething(restartCounter);
}
Actually, I've found a workaround.
describe("test", () => {
test("Is it doing something more than once?", async () => {
myCode.restart = jest.fn()
const restartSpy = jest.spyOn(myCode, 'restart');
await myCode.doSomething()
expect(restartSpy).toHaveBeenCalledTimes(1);
})
})
I'm overwriting restart() function. So now, I'm able to add await to doSomething() function and it will no longer be inifinite loop. Now I can check if the restart function has been called

Mocha.run() exits without awaiting async tests

I want to use mocha to run some basic post-deploy tests against live services. I want to programmatically load tests based upon a config object passed to the test script.
The problem I'm encountering is that mocha.run() executes and exits the node process without continuing with the rest of the code. It is not clear to me how to force node to wait for the mocha result and continue with the rest of the code.
mocha-setup.js
const Mocha = require('mocha');
const util = require('util');
const { Test, Suite } = Mocha;
const timeoutMillis = 300000; // five minutes
const mocha = new Mocha({
timeout: timeoutMillis,
reporter: 'mochawesome',
reporterOptions: {
reportDir: '../reports/unit'
},
color: true,
});
const makeSuite = (suiteName) => Suite.create(mocha.suite, suiteName);
const runMochaTests = async (tests, config) => {
const suite = makeSuite('My programmatic test suite');
tests.forEach(({ test, statement }) => {
suite.addTest(new Test(statement, async () => {
await test(config);
}));
});
console.log('This logs as expected.');
const promisifyMocha = util.promisify(() => mocha.run());
const result = await promisifyMocha(); // code seems to exit here
console.log('I am never logged');
console.log(result); // also never logged
// `result` is never returned, and higher level code implementing `runMochaTests` does not continue either
return result; // Eventually, I want to return the number of failures
};
module.exports = {
runMochaTests,
};
The plan is for runMochaTests to return the number of failures. runMochaTests() will be used by different higher order code modules as necessary.
Lastly, in my best life, I would not have to manually promisify mocha at all. If there was a way to use something like const result = await mocha.run(), that feels like the best implementation.
My problem was that Mocha is fundamentally about event listeners, not promises. Using this reference code, I ended up with...
const runMochaTests = async (tests, config) => new Promise((resolve, reject) => {
const testResults = [];
let numberOfFailures = 0;
try {
const suite = makeSuite('Verify Regional Apps');
tests.forEach(({ test, statement }) => {
suite.addTest(new Test(statement, async () => {
await test(config);
}));
});
const runner = mocha.run();
runner.on('test end', (testResult) => {
if (testResult.state === 'failed') numberOfFailures += 1;
testResults.push(testResult);
});
runner.on('end', () => {
runner.removeAllListeners('test end');
runner.removeAllListeners('end');
ClearModule.all(); // Needed to ensure all tests are executed every execution.
resolve(numberOfFailures);
});
} catch (err) {
reject(err);
}
});

Querying multiple promises with a callback

In node.js i have a databaseMapper.js file, that uses the Ojai node MapR api. to extract data. So far i have it working with single documents, but since this is an async api, i have a bit of issues with querying multiple documents.
This is what i have so far:
function queryResultPromise(queryResult) {
//this should handle multiple promises
return new Promise((resolve, reject) => {
queryResult.on("data", resolve);
// ...presumably something here to hook an error event and call `reject`...
});
}
const getAllWithCondition = async (connectionString, tablename, condition) =>{
const connection = await ConnectionManager.getConnection(connectionString);
try {
const newStore = await connection.getStore(tablename);
const queryResult = await newStore.find(condition);
return await queryResultPromise(queryResult);
} finally {
connection.close();
}
}
here it will only return the first because queryResultPromise will resolve on the first document.. however the callback with "data" may occur multiple times, before the queryResult will end like this queryResult.on('end', () => connection.close())
i tried using something like Promise.all() to resolve all of them, but I'm not sure how i include the queryResult.on callback into this logic
This will work
const queryResultPromise = (queryResult) => {
return new Promise((resolve, reject) => {
let result = [];
queryResult.on('data', (data) => {
result.push(data)
});
queryResult.on('end', (data) => {
resolve(result);
});
queryResult.on('error', (err) => {
reject(err);
})
});
};

Halt Execution of Network Request If It Takes Too Long?

I have some code that basically calls fetch in Javascript. The third party services sometimes take too long to return a response and in an attempt to be more user-friendly, I want to be able to either post a message or stop the connection from being open after N milliseconds.
I had recently come across this post:
Skip the function if executing time too long. JavaScript
But did not have much luck and had issues getting it to work with the below code. I was also hoping that there was a more modern approach to do such a task, maybe using async/await?
module.exports = (url, { ...options } = {}) => {
return fetch(url, {
...options
})
}
You can use a combination of Promise.race and AbortController, here is an example:
function get(url, timeout) {
const controller = new AbortController();
return Promise.race([fetch(url, {
signal: controller.signal
}), new Promise(resolve => {
setTimeout(() => {
resolve("request was not fulfilled in time");
controller.abort();
}, timeout)
})]);
}
(async() => {
const result = await get("https://example.com", 1);
console.log(result);
})();
The native Fetch API doesn't have a timeout built in like something like axios does, but you can always create a wrapper function that wraps the fetch call to implement this.
Here is an example:
const fetchWithTimeout = (timeout, fetchConfig) => {
const FETCH_TIMEOUT = timeout || 5000;
let didTimeOut = false;
return new Promise(function(resolve, reject) {
const timeout = setTimeout(function() {
didTimeOut = true;
reject(new Error('Request timed out'));
}, FETCH_TIMEOUT);
fetch('url', fetchConfig)
.then(function(response) {
// cleanup timeout
clearTimeout(timeout);
if(!didTimeOut) {
// fetch request was good
resolve(response);
}
})
.catch(function(err) {
// Rejection already happened with setTimeout
if(didTimeOut) return;
// Reject with error
reject(err);
});
})
.then(function() {
// Request success and no timeout
})
.catch(function(err) {
//error
});
}
from here https://davidwalsh.name/fetch-timeout

Opening maxmind DB and accessing it in nodejs

Previously I was using like this:
Opening Maxmind db in Nodejs
Now, updated the modules as per node 10.
So, need help to integrate it.
reference
const maxmind = require('maxmind');
exports.getIsoCountry = function(pIpAddress) {
modules.debugLog('inside getIsoCountry : ',pIpAddress);
maxmind.open(sGlAppVariable.maxmindDbPath)
.then(function(lookup) {
var ipData = lookup.get(pIpAddress);
//console.log(ipData);
console.log('iso_code',ipData.country.iso_code);
return ipData.country.iso_code;
});
}
console.log(getIsoCountry('66.6.44.4')); it should print country code. but it is undefined always. because this is a promise.
How to call this getIsoCountry function?
Any help will be appreciated.
You need to wait for execution to complete, for that, you should use Promise.
Modify your code as below, then it should work:
const maxmind = require('maxmind');
exports.getIsoCountry = function(pIpAddress) {
return new Promise((resolve, reject) => {
modules.debugLog('inside getIsoCountry : ',pIpAddress);
maxmind.open(sGlAppVariable.maxmindDbPath)
.then(function(lookup) {
var ipData = lookup.get(pIpAddress);
console.log('iso_code',ipData.country.iso_code);
resolve(ipData.country.iso_code);
});
});
}
getIsoCountry("66.6.44.4").then((rData) => {
console.log(rData)
});
Below is sample code:
var getIsoCountry = function(pIpAddress) {
return maxmind().then(function() {
return "Code for IP: " + pIpAddress;
});
function maxmind() {
return new Promise((resolve, reject) => {
resolve("done")
});
}
}
getIsoCountry("1.1.1.1").then((data) => {
console.log(data)
});

Categories

Resources