why I get error when test my code in nodejs - node.js

I am using MongoDB, NodeJs,and Chai to test the code.
connecting to mongodb :
if (!!connection) {
model = connection.model('client', clientSchema, collections.clients[env]);
} else {
model = mongoose.model('client', clientSchema, collections.clients[env]);
}
This is the unit tests:
describe('Bad VSA card test', () => {
it('should contains VSA accounts', async (done) => {
const vsaCard = await updatedVSA();
console.log(vsaCard);
expect(vsaCard.length).to.equal(5);
done();
});
afterAll(() => {
client.disconnect();
});
});
When I run this test code, I get an error:
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.
Actually, I searched for this error first. And I found a similar issue. His error was fixed by closing db connection. Why am I still getting this error by closing MongoDB connection?

Related

Silent errors using mocha with delay flag

We are using mocha on our Open Source project https://opentermsarchive.org and ended up in the CI deploying our code despite errors in the tests.
Problem is that those errors failed silently with an exit code of 0, which is really bad.
This means
tests are launched
tests fail with no error
CI considers tests have passed even though they did not run completely
We are using mocha programmatically with the following config
const mocha = new Mocha({
delay: true, // as the validation script performs an asynchronous load before running the tests, the execution of the tests are delayed until run() is called
failZero: true, // consider that being called with no service to validate is a failure
});
const VALIDATE_PATH = path.resolve(__dirname, '../scripts/validation/validate.js');
(async () => {
mocha.addFile(VALIDATE_PATH); // As `delay` has been called, this statement will not load the file directly, `loadFilesAsync` is required.
await mocha.loadFilesAsync() // Load files previously added to the Mocha cache with `addFile`.
.catch(error => {
console.error(error);
process.exit(2);
});
let hasFailedTests = false;
mocha.run()
.on('fail', () => { hasFailedTests = true; })
.on('end', () => {
if (hasFailedTests) {
process.exit(1);
}
process.exit(0);
});
})();
Well
this is due to the fact that mocha is silenting unhandledRejection when you are using the delay property
You can see that here https://github.com/mochajs/mocha/blob/master/lib/runner.js#L198
So a way to bypass this is to add
process.on('unhandledRejection', reason => {
// Mocha catch unhandled rejection from the user code and re-emit them to the process (see https://github.com/mochajs/mocha/blob/master/lib/runner.js#L198)
// Re-throw them so that the validation command fails in these cases (for example, if there is a syntax error when parsing JSON declaration files)
console.error(reason); // keep the console error to have the whole stack trace
throw reason;
});
before the instantiation of mocha

Sinon multiple stubs in a single test

I want to test the saveRecords function for the failure and before that, I have to authenticate and connect the MongoDB. This is the code.
before(() => {
sinon.stub(Authentication, 'authenticate').returns(true);
sinon.stub(mongodb, 'connect').resolves("connected");
sinon.stub(models, 'saveRecords').throws(new Error("Error while saving record"));
});
it('Should error out if record is not inserted into the mongodb
collection', () => {
orderWebhook(req, res)
expect(res.result).to.contain("Error while saving record");
});
Here is the code I am testing.
exports.orderWebhook = async (req, res) => {
try {
const isAuthenticated = Authentication.authenticate(req);
if (isAuthenticated) {
await mongodb.connect();
await models.saveRecords(req.body");
res.status(200).send('Saved Successfully!');
} else {
res.status(403).send('Error! Auth failed!');
}
} catch (error) {
res.status(400).send(error.message);
}
}
I am assuming that this code will stub the authenticate then connect MongoDB and then try to insert the record and throw the error. But it is running two times when I debug with the VSCode debugger.
The first time it is returning true for the authenticate function and not resolving the MongoDB connect and return to expect immediately.
The second time it is running all three properly and throwing the expected error.
It is failing when I run the test in the terminal, What could be the issue?
Update: I noticed that the problem is related to the promise. Sinon is resolving the request and I am using await mongodb.connect(); but it is not working as expected, and if I remove await and return value instead of promise then it works.

Mocha hangs after execution when connecting with Mongoose

Talk is cheap, show me the code
Linus Torvald
Doing integration tests with mocha and supertest. Here's the code
//app.js
mongoose.Promise = global.Promise;
mongoose.connect(config.mongoURL, error => {
if (error) {
throw error;
}
console.log('Connected to mongodb');
});
modules.export = app;
// test.js
it('returns 200', () => {
return supertest(app).get('/').expect(200);
});
Basically what happens is that the output "Connected to mongodb" logs after the tests are run (I have like 3 tests only, none use the db), and afterwards mocha hangs there and I have to Ctrl+C. I probably missed some configuration but I can't see it.
Needless to say, commenting the mongoose lines (mongoose.connect(...)) fixes it.
What am I missing?
You have to disconnect from the database after the tests are done. This can be done in the after function, for example.
after((done) => {
app.close(() => {
mongoose.connection.close(done);
});
});
If you don't disconnect you'll get the symptoms you are describing.
a more simplified answer
after((done) => {
mongoose.connection.close(done);
});

How to unit test a pool connection?

I would like to unit test (mocha & chai) a pool connection (mysql) in my node.js app. I don't know if I'm using the tests in the correct way and, if so, why they are always qualified as "pending".
Giving the following code, how would I test it?
var pool = mysql.createPool({
connectionLimit: 100,
host: 'localhost',
user: 'userName',
password: 'userPass',
database: 'userDatabase',
debug: false
});
I have tried in many ways but it doesn't seem to work. Best I got was this:
describe("Database", function () {
describe("Connection", function () {
it("Should connect without an error", pool.getConnection(function (err, connection) {
expect(err).to.be.null;
})
);
})
});
Which would return, if credentials are correct:
Express server listening on port 8080
Database
Connection
- Should connect without an error
0 passing (15ms)
1 pending
And return, if credentials are incorrect:
Express server listening on port 8080
Database
Connection
- Should connect without an error
1) Uncaught error outside test suite
0 passing (23ms)
1 pending
1 failing
1) Database Connection Uncaught error outside test suite:
Uncaught AssertionError: expected [Error: ER_DBACCESS_DENIED_ERROR: Access denied for user 'userName'#'localhost' to database 'userDatabase'] to be null
Thank you in advance.
What you pass to it in the 2nd argument must be a function. Right now you are doing:
it("Should connect without an error", pool.getConnection(...))
pool.getConnection takes a callback so in all likelihood, it returns undefined. So it looks like this to Mocha:
it("Should connect without an error", undefined)
And this is a pending test because having undefined for the callback is the way to tell Mocha the test is pending. You need to wrap your call to pool.getConnection in a function:
it("Should connect without an error", function (done) {
pool.getConnection(function (err, connection) {
if (err) {
done(err); // Mocha will report the error passed here.
return;
}
// Any possible tests on `connection` go here...
done();
});
});
See testing asynchronous code in the mocha docs. Your it function should look similar to the below.
it('Should connect without an error', function (done) {
pool.getConnection(done);
});
Or, if you want to add assertions inside your callback do the following:
it('Should connect without an error', function (done) {
pool.getConnection((err, connection) => {
try {
expect(connection).to.not.be.null;
expect(connection).to.have.property('foo');
done();
} catch (error) {
done(error);
}
});
});
Note you should preferably test with promises because this allows you to run expect statements on the connection object without extra try/catch/done statements. For example, if pool.getConnection returns a promise, you can do:
it('Should connect without an error', function () {
return pool.getConnection(connection => {
expect(connection).to.have.property('foo');
// more assertions on `connection`
});
});
Also note that these are not "unit tests", but integration tests, as they are testing that two systems work together rather than just your application behaving as expected on its own.

Error connecting to database when using mockgoose

The tests run well when using the real database, but after I mocked it with mockgoose, it reports an error
Uncaught Error: Error connecting to database: failed to connect to [yankiserver-test:27017]
at null.
(/Users/twer/GDrive/2Dev/node/yankiServer/node_modules/mongoose/node_modules/mongodb/lib/mongodb/connection/server.js:555:74)
at emit (events.js:118:17)
...
My project is based on MEAN.JS. I have added the mocking part to test.js.
var mongoose = require('mongoose');
var mockgoose = require('mockgoose');
console.log('mocking goose');
mockgoose(mongoose);
It works well for saving model directly:
it('should be able to save without problems', function(done) {
return article.save(function(err) {
should.not.exist(err);
done();
});
});
But when I try to hit database through express
it('should be able to get a list of articles', function(done) {
request(app).get('/articles/')
.end(function(req, res) {
done();
});
});
It throws the above error.
Note: The connection has been established before running the test based on my debuging.

Resources