jest timeouts when calling a database query - javascript

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.

Related

Firebase getRedirectResult() doesn't solve

I am trying to implement the signInWithRedirect() function, but - weirdly enough , it doesn't work. In the below code , Check 2 and Check 3 never get logged - and no error is thrown :
const signInWithGoogle = async () => {
try {
console.log("Check 1")
await signInWithRedirect(auth, googleAuthprovider);
console.log("Check 2")
const result = await getRedirectResult(auth);
console.log("Check 3");
if (result) {
console.log(result.user);
}
} catch (e) {
console.log(e.message.slice(10));
}
};
Also, if I use the exact same Google account to sign in with the signInWithPopup() method, everything works as expected:
const signInWithGoogle = async () => {
const result = await signInWithPopup(auth, googleAuthprovider)
const user = result.user;
console.log(user)
};
I'd really appreciate some help. Thanks!
signInWithRedirect actually navigates away from the page and redirects back to your application so you'll need to handle responses in a separate function that fires when your application loads for the first time.
import {
signInWithRedirect,
getRedirectResult,
GoogleAuthProvider,
} from "firebase/auth"
const googleAuthProvider = new GoogleAuthProvider()
// On Button Click
const signUpGoogle = async () => {
try {
await signInWithRedirect(auth, googleAuthProvider)
} catch (error: any) {
console.log(error)
}
}
// When the page loads
const debugRedirectResult = async () => {
try {
const result = await getRedirectResult(auth)
if (result) {
const details = getAdditionalUserInfo(result)
console.log(details) // details.isNewUser to determine if a new or returning user
} else {
// Everything is fine
}
} catch (error) {
console.log(error) // Debug errors from redirect response
}
}
For example, in React you'd do something like:
// Something like an Auth context provider or App.js
React.useEffect(() => {
const debugRedirectResult = async () => {
try {
const result = await getRedirectResult(auth)
if (result) {
const details = getAdditionalUserInfo(result)
console.log(details) // details.isNewUser to determine if a new or returning user
} else {
// Everything is fine
}
} catch (error) {
console.log(error) // Debug errors from redirect response
}
}
signInWithRedirect()
}, [])
Some things to be aware of:
In certain circumstances getRedirectResult() doesn't throw errors saying an account already exists with another sign in method: https://github.com/firebase/firebase-js-sdk/issues/6051.
These error concerns can be resolved with an email verification flow as explained here: https://firebase.google.com/docs/auth/users#verified_email_addresses

Why is Mocha ignoring asynchronous function calls?

I am writing automated integration tests with Mocha and Chai. Here is a simplified version of the code I am testing:
exports.doSomething = async function (req, res) {
return executeRequest(req.body)
.then((response) => {
console.log("then running");
res.status(200).send(response);
})
.catch((err) => {
console.error(err);
res.status(500).send(err);
}
}
And here is what my test file looks like:
const { doSomething } = require("../../index");
const { assert } = require("chai");
const { stub } = require("sinon");
const req = { body: { *data* } };
const res = {
status: stub().returnsThis(),
send: stub().returnsThis(),
};
it(`Please work`, async () => {
await doSomething(req, res);
}
When that happens, neither the .then block nor the .catch blocks are entered—console.log does not run; res.send and res.status are never called.
Another interesting note: If I remove the async from the test call and save the result of doSomething() to a variable, it shows as a promise. When I include the async, the result of doSomething is undefined.
I am new to Mocha and have no idea why it seems to be ignoring the asynchronicity of the code.
Your doSomething implementation is broken, the promise that the async function returns will fulfill immediately - before executeRequest is done. You should write either
exports.doSomething = function (req, res) {
return executeRequest(req.body)
//^^^^^^
.then((response) => {
console.log("then running");
res.status(200).send(response);
})
.catch((err) => {
console.error(err);
res.status(500).send(err);
})
}
or
exports.doSomething = async function (req, res) {
try {
const response = await executeRequest(req.body);
// ^^^^^
console.log("then running");
res.status(200).send(response);
} catch(err) {
console.error(err);
res.status(500).send(err);
}
}
Only then your test can properly await the doSomething(req, res) call, and mocha won't prematurely kill the process.

Query not returning results nor failing. Only gives back an unresolved Promise

This is confusing me a lot, because I'm repeating the code structure I have on other parts of my project (and it works there).
This is the part where it doesn't work:
/utils/socketQueries.js
const db = require('../db')
exports.addMessage = async (message) => {
console.log('add message func', message)
try {
/* const res = await db.query('select 1', (err, res) => {
console.log(res)
})*/
const res = await db.query('select 1') // this doesn't work either
return res
} catch (error) { console.error('adding message error', error) }
}
This is called from /socketserver.js
exports.socketServer = (wss) => {
let socket_id = new Map()
wss.on("connection", (ws, req) => {
ws.on('message', (data) => { //messages from the client
parseMessage(ws, socket_id, data)
})
})
...
this is how I set up the db connection in db.js
require('dotenv').config()
const { Pool } = require('pg')
const connectionString = process.env.DBCONNSTRING
const db = new Pool({
connectionString: connectionString,
})
module.exports = db;
and an example of a working query function would be /api/health.js
const db = require('../db');
exports.check = async (req, res) => {
let response = {
apiResponsive: true
}
try {
dbResponsive = await db.query(`select 1`)
if (dbResponsive.rows[0]) response = {dbResponsive: true, ...response}
else response = {dbResponsive: true, ...response} }
catch(error) {
console.error('error on db health check', error)
response = {dbResponsive: 'error while checking', ...response}
}
res.json(response)
}
I've been trying different ways to run the query: .then, callback, async/await and it always returns either the unresolved promise or undefined - it never throws an error.
Can anyone sort out whats the (likely very basic) error I'm missing?
EDIT: Trying out the answers proposed I noticed that if I try an INSERT query, nothing is inserted on the DB. regardless of what I do with what db.query returns, the query should run.

neo4j Node js Unit test with Jest

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

How to fix "Function returned undefined, expected Promise or value"

What I am trying to accomplish in a Firebase Function:
Read from Firebase database email addresses to batch email.
Loop through each one and send out emails.
I am having an issue with closing promises I believe. These don't need to be ran in order, I just need to resolve all promises before ending.
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const https = require('axios');
exports.sendEmail = functions.pubsub.topic('nightly_topic').onPublish(() => {
let emailsToSend = [];
async function getTests (){
admin.firestore()
.collection("tests")
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
emailsToSend.push(doc.data())
});
})
.catch(function (error) {
console.error(error);
});
}
async function send (address){
let body = {
//MANDRILL INFO REMOVED
};
let endpoint = 'https://mandrillapp.com/api/1.0/messages/send-template.json';
https.post(endpoint, body)
.then((result) => {
console.log('SUCCESS');
})
.catch(function (error) {
console.error(error);
});
}
async function init() {
await getTests();
for (const email of emailsToSend) {
await send(email.address);
}
}
init();
});
You're missing return statements from your functions.
return https.post(... etc
Try this:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
admin.initializeApp();
const https = require('axios');
exports.sendEmail = functions.pubsub.topic('nightly_topic').onPublish(() => {
let emailsToSend = [];
function getTests (){
return new Promise((resolve, reject) => {
admin.firestore()
.collection("tests")
.get()
.then(querySnapshot => {
querySnapshot.forEach(doc => {
emailsToSend.push(doc.data())
});
resolve(emailsToSend);
})
.catch(function (error) {
reject(error)
});
});
}
async function send (address){
let body = {
//MANDRILL INFO REMOVED
};
let endpoint = 'https://mandrillapp.com/api/1.0/messages/send-template.json';
https.post(endpoint, body)
.then((result) => {
console.log('SUCCESS');
})
.catch(function (error) {
console.error(error);
});
}
async function init() {
const emailsToSend = await getTests();
for (const email of emailsToSend) {
await send(email.address);
}
}
init();
});
It might help you.
so you are almost there. The issue is that you are not returning anything. You should fix it by just doing:
Return Promise
// code ...
exports.sendEmail = functions.pubsub.topic('nightly_topic').onPublish(() => {
// code
return init();
}
Use async
// code ...
exports.sendEmail = functions.pubsub.topic('nightly_topic').onPublish(async () => {
// code
await init();
}
Note: an async function always returns a Promise.
Suggestion
In your code, you are sending emails one at a time. await send(email.address); This line of code waits until the email is sent, before sending the next one, which is not efficient.
My suggestion is sending all emails at the same time and return a promise that resolves when every email is sent. That should look something like this:
//change this
for (const email of emailsToSend) {
await send(email.address);
}
// --------------into this--------------------------------
//This is an array of promises
const promises = emailsToSend.map(email => {
return send(email.address);
});
await Promise.all(promises);
Hope that helps :)

Categories