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.
Related
I have an express app (REST API) which connects to a mongoDB cluster on MongoDB Atlas (the cloud database) during tests. I'm using Mocha to test.
I have an end-to-end test (which uses the database) but for the majority of the tests I want to mock/stub the calls to the database so that it's isolated.
I've tried using nock to intercept the network connections and mock the response, but from what I can see nock is only for http calls and mongoDB Atlas uses DNS (starts with mongodb+srv:, see here for more info) and I think this is why I can't get this to work.
I've also trying to stub the Model. I'm struggling to get this working but it seems like it might be an option?
// The route
router.post('/test', async (req, res) => {
const { name } = req.body;
const example = new ExampleModel({ name: name})
// this should be mocked
await example.save();
res.status(200);
});
// The test
describe('POST /example', () => {
it('Creates an example', async () => {
// using supertest to make http call to my API app
const response = await request(app)
.post('/test')
.type("json")
.send({ 'name': 'test-name' })
// expect the model to have been created and then saved to the database
});
});
I'm expecting that when I run the test, it will make a POST to the API, which won't make a call to the database but will return fake data (as though it had).
I've found some really useful resources and sharing them:
Isolating mongoose unit tests (including model methods like findOne guide
Stubbing the save method on a model: Stubbing the mongoose save method on a model (I just used `sinon.stub(ExampleModel.prototype, 'save').
// example code
it('Returns 400 status code', async () => {
sinon.stub(ExampleModel, 'findOne').returns({ name: 'testName' });
const saveStub = sinon.stub(ExampleModel.prototype, 'save');
const example = new ExampleModel({ name: 'testName' })
const response = await request(app)
.post('/api/test')
.type("json")
.send({ name: 'testName' })
sinon.assert.calledWith(Hairdresser.findOne, {
name: 'testName'
});
sinon.assert.notCalled(saveStub)
assert.equal(response.res.statusCode, 400);
});
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.
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?
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.
I'm working with mongojs and writing tests for mocha running coverage with istanbul. My issue is that I would like to include testing db errors.
var mongojs = require('mongojs');
var db = mongojs.connect(/* connection string */);
var collection = db.collection('test');
...
rpc.register('calendar.create', function(/*... */) {
collection.update({...}, {...}, function (err, data) {
if (err) {
// this code should be tested
return;
}
// all is good, this is usually covered
});
});
the test looks like this
it("should gracefully fail", function (done) {
/* trigger db error by some means here */
invoke("calendar.create", function (err, data) {
if (err) {
// check that the error is what we expect
return done();
}
done(new Error('No expected error in db command.'));
});
});
There is a fairly complex setup script that sets up the integration testing environment. The current solution is to disconnect the database using db.close() and run the test resulting in an error as wanted. The problem with this solution arises when all the other tests after that require the database connection fail, as I try to reconnect without success.
Any ideas on how to solve this neatly? Preferably without writing custom errors that might not be raised by next version of mongojs. Or is there a better way of structuring the tests?
What about mocking the library that deals with mongo?
For example, assuming db.update is eventually the function that gets called by collection.update you might want to do something like
describe('error handling', function() {
beforeEach(function() {
sinon.stub(db, 'update').yields('error');
});
afterEach(function() {
// db.update will just error for the scope of this test
db.update.restore();
});
it('is handled correctly', function() {
// 1) call your function
// 2) expect that the error is logged, dealt with or
// whatever is appropriate for your domain here
});
});
I've used Sinon which is
Standalone test spies, stubs and mocks for JavaScript. No dependencies, works with any unit testing framework.
Does this make sense?