neo4j Node js Unit test with Jest - javascript

I use the Jest framework to create unit tests. When I run them. there is the message at the end:
"Jest did not exit one second after the test run has completed.
This usually means that there are asynchronous operations that weren't stopped in your tests. Consider running Jest with --detectOpenHandles to troubleshoot this issue."
To exit, I use the command "--forceExit".
Also, I've tried to find an issue with --detectOpenHandles, but it didn't show anything.
I can't find what it hasn't closed, session or driver, or something else.
How could it be fixed?
const neo4j = require("neo4j-driver");
const driver = neo4j.v1.driver(
`bolt://${host}`,
neo4j.v1.auth.basic(username, password)
);
beforeAll(async () => {
await cleanDB();
});
afterAll(async () => {
await cleanDB();
driver.close();
});
async function cleanDB() {
await runQuery(`...query`);
}
async function runQuery(query) {
const session = driver.session();
return session
.writeTransaction(tx => tx.run(query))
.then(result => {
session.close();
return result;
})
.catch(error => {
session.close();
return { error };
});
}
describe(`bla-bla-bla`, function() {
beforeAll(async () => {
await dataBaseLoader(data);
});
test(`bla-bla-bla`, async function() {
const result = await runQuery(
'...query' );
//Body of Test
expect(result).toStrictEqual(expected);
});

There is no need to use async before function if you don't use await in body, also if function is not async access it without await
function cleanDB() {
runQuery(`...query`);
}
function runQuery(query) {
const session = driver.session();
return session
.writeTransaction(tx => tx.run(query))
.then(result => {
session.close();
return result;
})
.catch(error => {
session.close();
return { error };
});
}
and so on, check all your functions, maybe it will help

Related

Node.js PM2: programmatically retrieving all process IDs

I'm trying to programmatically get an array of all of the PM2 process IDs in cluster mode.
const pm2 = require("pm2");
let allPids;
async function getPids() {
return await new Promise(resolve => {
pm2.list((err, list) => {
if (err) {
console.error(err);
} else {
resolve(list.map(process => process.pid));
}
});
});
}
getPids().then(pids => {
console.log(pids); // outputs an array of PIDs
allPids = pids;
});
console.log(allPids); // outputs undefined
The above code successfully gets all of the PIDs with pm2.list(), but I'm unable to access them outside of the .then() callback.
const pm2 = require("pm2")
let pids;
pm2.list((err, list) => {
if (err) {
console.log(err);
} else {
pids = list.map(process => process.pid);
};
});
console.log(pids); // outputs undefined
setTimeout(() => {
console.log(pids); // outputs array of PIDs
}, 1000);
This code also worked, but only in the setTimeout() callback.
The PM2 documentation was no help whatsoever.
Is there a way access the PIDs without placing all of my code in the .then()/setTimeout() callback? Or, is there a better solution?
Your function is async, so why not await?
const pm2 = require("pm2");
let allPids;
async function getPids(): number[] {
let pids = [];
try {
pids = await pm2.list();
} catch (err) {
console.error(err);
}
return list.map(process => process.pid);
}
(async () => {
allPids = await getPids();
console.log(allPids);
})();

jest timeouts when calling a database query

I have a test file like this.
const { silBastan } = require("../database.js");
const axios = require('axios').default;
describe("authentication", () => {
describe("when data schema is valid", () => {
test("returns 201 response code if the user doesnt already exists", async () => {
await silBastan();
const response = await axios.post('http://localhost:8000/auth/register', {
email: "my_email",
password: "1234"
});
expect(response.status).toBe(201);
});
});
});
And silBastan is defined here like this
const pg = require("pg");
const client = new pg.Client();
async function silBastan() {
return await client.query(`DELETE FROM account`);
}
Of course i made sure the server started and connected to the database before running the tests.
I wondered if there is something wrong with silBastan and tested it inside a express route handler like this
router.post('/register', async (req, res) => {
const { email, password } = req.body;
await silBastan();
try {
await db.createAccount(email, password);
res.sendStatus(201);
} catch (e) {
res.status(400).json({ err: "Already exists" });
}
});
and there was no timeout. And after this i returned another promise from silBastan like this:
async function silBastan() {
// return await client.query(`DELETE FROM account`);
return new Promise((resolve) => setTimeout(() => resolve(), 1000));
}
And again there is no timeout. I tried couple of other variations as well like these:
function silBastan() {
return client.query(`DELETE FROM account`);
}
async function silBastan() {
await client.query(`DELETE FROM account`);
}
Nothing worked i always get this message:
thrown: "Exceeded timeout of 5000 ms for a test.
Use jest.setTimeout(newTimeout) to increase the timeout value, if this is a long-running test."
I don't think the problem is with the function because i would get the same behavior in the route handler too.

How do I setup this JS code to do better testing?

Hi guys I'm having trouble testing the below JS using Jest. It starts with waitForWorker. if the response is 'working' then it calls waitForWorker() again. I tried Jest testing but I don't know how to test an inner function call and I've been researching and failing.
const $ = require('jquery')
const axios = require('axios')
let workerComplete = () => {
window.location.reload()
}
async function checkWorkerStatus() {
const worker_id = $(".worker-waiter").data('worker-id')
const response = await axios.get(`/v1/workers/${worker_id}`)
return response.data
}
function waitForWorker() {
if (!$('.worker-waiter').length) {
return
}
checkWorkerStatus().then(data => {
// delay next action by 1 second e.g. calling api again
return new Promise(resolve => setTimeout(() => resolve(data), 1000));
}).then(worker_response => {
const working_statuses = ['queued', 'working']
if (worker_response && working_statuses.includes(worker_response.status)) {
waitForWorker()
} else {
workerComplete()
}
})
}
export {
waitForWorker,
checkWorkerStatus,
workerComplete
}
if (process.env.NODE_ENV !== 'test') $(waitForWorker)
Some of my test is below since i can't double check with anyone. I don't know if calling await Worker.checkWorkerStatus() twice in the tests is the best way since waitForWorker should call it again if the response data.status is 'working'
import axios from 'axios'
import * as Worker from 'worker_waiter'
jest.mock('axios')
beforeAll(() => {
Object.defineProperty(window, 'location', {
value: { reload: jest.fn() }
})
});
beforeEach(() => jest.resetAllMocks() )
afterEach(() => {
jest.restoreAllMocks();
});
describe('worker is complete after 2 API calls a', () => {
const worker_id = Math.random().toString(36).slice(-5) // random string
beforeEach(() => {
axios.get
.mockResolvedValueOnce({ data: { status: 'working' } })
.mockResolvedValueOnce({ data: { status: 'complete' } })
jest.spyOn(Worker, 'waitForWorker')
jest.spyOn(Worker, 'checkWorkerStatus')
document.body.innerHTML = `<div class="worker-waiter" data-worker-id="${worker_id}"></div>`
})
it('polls the correct endpoint twice a', async() => {
const endpoint = `/v1/workers/${worker_id}`
await Worker.checkWorkerStatus().then((data) => {
expect(axios.get.mock.calls).toMatchObject([[endpoint]])
expect(data).toMatchObject({"status": "working"})
})
await Worker.checkWorkerStatus().then((data) => {
expect(axios.get.mock.calls).toMatchObject([[endpoint],[endpoint]])
expect(data).toMatchObject({"status": "complete"})
})
})
it('polls the correct endpoint twice b', async() => {
jest.mock('waitForWorker', () => {
expect(Worker.checkWorkerStatus).toBeCalled()
})
expect(Worker.waitForWorker).toHaveBeenCalledTimes(2)
await Worker.waitForWorker()
})
I think there are a couple things you can do here.
Inject status handlers
You could make the waitForWorker dependencies and side effects more explicit by injecting them into the function this lets you fully black box the system under test and assert the proper injected effects are triggered. This is known as dependency injection.
function waitForWorker(onComplete, onBusy) {
// instead of calling waitForWorker call onBusy.
// instead of calling workerComplete call onComplete.
}
Now to test, you really just need to create mock functions.
const onComplete = jest.fn();
const onBusy = jest.fn();
And assert that those are being called in the way you expect. This function is also async so you need to make sure your jest test is aware of the completion. I notice you are using async in your test, but your current function doesnt return a pending promise so the test will complete synchronously.
Return a promise
You could just return a promise and test for its competition. Right now the promise you have is not exposed outside of waitForWorker.
async function waitForWorker() {
let result = { status: 'empty' };
if (!$('.worker-waiter').length) {
return result;
}
try {
const working_statuses = ['queued', 'working'];
const data = await checkWorkerStatus();
if (data && working_statuses.includes(data.status)) {
await waitForWorker();
} else {
result = { status: 'complete' };
}
} catch (e) {
result = { status: 'error' };
}
return result;
}
The above example converts your function to async for readability and removes side effects. I returned an async result with a status, this is usefull since there are many branches that waitForWorker can complete. This will tell you that given your axios setup that the promise will complete eventually with some status. You can then use coverage reports to make sure the branches you care about were executed without worrying about testing inner implementation details.
If you do want to test inner implementation details, you may want to incorporate some of the injection principals I mentioned above.
async function waitForWorker(request) {
// ...
try {
const working_statuses = ['queued', 'working'];
const data = await request();
} catch (e) {
// ...
}
// ...
}
You can then inject any function into this, even a mock and make sure its called the way you want without having to mock up axios. In your application you simply just inject checkWorkerStatus.
const result = await waitForWorker(checkWorkerStatus);
if (result.status === 'complete') {
workerComplete();
}

Test Javascript calls to api with jest

I am trying to test the call to github api using jest to see if the results are returned (the aim of this is to test my unit testing skills). But for some reasons, my code works fine but still fails my test. My suspicion is that i most likely don't understand how to write these kind of test. Below is my code
const functions = {
getUserRepo: async (username) => {
const url = `https://api.github.com/users/${username}/repos`;
console.log(url);
let result = [];
await axios.get(url)
.then(function (response) {
response.data.forEach(value => result.push(value.name));
return result;
})
.catch(function (error) {
return error;
});
}
}
This code above returns the right results in an array format but fails the test below
describe('Check repos from git api', () => {
test('Should return user repos', async () => {
await functions.getUserRepo('whitehox')
.then((response) => {
expect(response.data).toEqual([ '57','decafreelance','decases','eexport','exportchat','flisch', 'gitprac', 'itravelcentral', 'pollark', 'portfolio', 'startereit', 'talkative', 'team-portfolio'])
})
});
});
Please what is the issue with this test and how do i fix it?
Two things need to be fixed.
You need to return the result from your function. It can be simplified to this:
const functions = {
getUserRepo: (username) => {
const url = `https://api.github.com/users/${username}/repos`;
console.log(url);
return axios.get(url) // <= return the result
.then(function (response) {
return response.data.map(value => value.name);
})
.catch(function (error) {
return error;
});
}
}
...which makes response the array so test it directly:
describe('Check repos from git api', () => {
test('Should return user repos', async () => {
await functions.getUserRepo('whitehox')
.then(response => {
// response **is** the array
expect(response).toEqual(['57', 'decafreelance', 'decases', 'eexport', 'exportchat', 'flisch', 'gitprac', 'itravelcentral', 'pollark', 'portfolio', 'startereit', 'talkative', 'team-portfolio', 'YorubaIndigenous']); // Success!
})
});
});
(...and there is also a new repo called 'YorubaIndigenous', I added it to the expected value).

How to cover setInterval in the unit test case in javascript

Hi I am write a unit test case of this function. When I run this function from the unit test case then it covers all statements but setInterval complete lines are not covered.
Does anyone know how to cover it in javascript? I am using mocha.
const open = async function (config) {
...... set of lines..
let retryIn = setInterval(async () => {
try {
client = await connect(config);
clearInterval(retryIn);
return client;
} catch (err) {
//error
}
}, 20000);
};
I am simply calling it like this
it("###test", async () => {
open(config);
});
});
First of all, you should never use setInterval in the case where you want to retry a task that has failed. You should use setTimeout instead.
Besides that, you cannot return a value from a classical callback base function like setInterval or setTimeout. So in its current form, the promise returned when calling open will be resolved before any connection is made.
With await/async you can create a clean and simple setup for such a situation:
function wait(seconds) {
return new Promise((resolve, _) => setTimeout(resolve, seconds))
}
async function connect() {
throw new Error('failed')
}
async function open(config) {
let client;
while (client === undefined /* || retries > maxRetries*/ ) {
try {
client = await connect(config);
} catch (err) {
// if connection failed due to an error, wait n seconds and retry
console.log('failed wait 2 seconds for reconnect');
await wait(2000)
// ++retries
}
}
if (!client) {
throw new Error('connection failed due to max number of retries reached.')
}
return client
}
async function main() {
let connection = await open()
}
main().catch(err => console.log(err))
You can further extend this snippet by adding a retry limit. See the comments for a rough idea on how that can be achieved.
To test the above code, you would write:
it("###test", function() {
return open(config);
});
Someone posted an answer about fake timers and then deleted it , The answer was correct so I re-posted again.
You can use sinonjs to create fake timers
Fake timers are synchronous implementations of setTimeout and friends
that Sinon.JS can overwrite the global functions with to allow you to
more easily test code using them
But from your code, it seems you are trying to test async code, in mocha, this can be achieved like this
describe('somthing', () => {
it('the result is 2', async () => {
const x = await add(1, 1)
expect(x).to.equal(4);
});
});
With something closer to your code
async function open() {
return new Promise((resolve, reject) => {
setTimeout(() => {
resolve('done')
}, 1000);
});
};
describe('somthing', () => {
it('###test', async () => {
const x = await open()
chai.expect(x).to.equal("done");
});
});
Just wrap to Promise
const open = async function (config) {
...... set of lines..
return new Promise((resolve, reject) => {
let retryIn = setInterval(async () => {
client = await connect(asConfigParam);
clearInterval(retryIn);
return client;
}, 20000);
return resolve(retryIn);
});
};
it("###test", async () => {
const result = await open(config);
console.log('result', result)
});

Categories