I'm trying to run tests on my npm module. The code below will work if I comment out either of the 2 it blocks, but times out if I leave them both in as below. How can wait for "ready" before running my tests (I'd like to add more but they too need to await "ready")?
describe("GA analytics", function() {
var report = new Report(private_key, SERVICE_EMAIL, 1);
it("should connect and emit <ready>", function(done) {
report.on('ready', function() {
console.log("test.js: Token: ", report.token);
expect(report.token).toBeDefined();
done();
});
});
it("should get data correctly", function(done) {
report.on('ready', function() {
report.get(query, function(err, data) {
if (err) throw err
expect(data.rows).toEqual([ [ '5140' ] ]);
done();
});
});
});
});
I guess it is happening because you create a new instance of the Report only once per test file, therefore the ready event only fires once and only the first it block in the test will catch it and process. The rest of the it blocks won't receive any more ready events, so they silently wait for it until Jasmine times out. The solution will be to create a new Report instance before each it block, which can be easily done with the help of Jasmine beforeEach:
describe("GA analytics", function() {
var report;
beforeEach(function () {
report = new Report();
});
// ....
});
See the working example here on Plunker (open a "script.js" file)
Related
I'm running some tests using Mocha and chai. One of the tests is hanging at a .should.be.deep.equal call.
Here's the test code:
// Make the fake connection before running tests
before(function(done) {
mongoose.connect('mongodb://fake.test/TestingDB', function(err) {
done(err);
});
});
// Test Cases
describe('Testing the functions that deal with users and locations:', function() {
// Test Setup
var req = {};
beforeEach(function(done) {
mockgoose.reset()
async.parallel([function(callback){
sensors.create(testData.deviceData, function(err, model) {
if (err) {console.log(err)}
callback();
});
}, function(callback) {
locations.create(testData.locationData, function(err, model) {
if (err) {console.log(err)}
callback();
});
}], function(err) {
done();
});
});
afterEach(function(done) {
mockgoose.reset();
done();
});
// Tests
describe('function locationList', function() {
it('should list the test location', function(done) {
dbFunctions.locationList(req, function(result) {
console.log(result) //Prints the whole result
console.log(testData.locationList)
result.should.exist; //This doesn't cause it to hang
result.should.be.deep.equal(testData.locationList) //hangs here
done(result);
});
})
})
});
And here's the function it's testing:
exports.locationList = function(req, callback) {
listLocations().then(
function(data) {
callback(data);
},
function(err) {
console.log('Error Retrieving Location Information: ' + err);
callback(err);
});
};
As I note in the comments, the results object exists and gets printed to the console. results.should.exist; doesn't throw an exception and if I comment out everything but it the test works fine. For some weird reason, despite both the testData.locationList and result object existing, the test times out. I have 14 other tests that use the exact same syntax without any problems. Does anyone know what could be causing this to happen for this specific test?
Here's the output from the tests:
Testing the functions that deal with users and locations:
function locationList
[ { devices: {},
address: '123 Fake St, Waterloo, On',
location: 'Unittest',
owner: 'unit#test.com',
_id: '-1' } ]
[ { devices: {},
address: '123 Fake St, Waterloo, On',
location: 'Unittest',
owner: 'unit#test.com',
_id: '-1' } ]
1) should list the test location
0 passing (2s)
1 failing
1) Testing the functions that deal with users and locations: function locationList should list the test location:
Error: timeout of 2000ms exceeded. Ensure the done() callback is being called in this test.
at null.<anonymous> (C:\Users\My Name\AppData\Roaming\npm\node_modules\mocha\lib\runnable.js:189:19)
Extending the timeout doesn't work. Nor does putting something random (ie. the integer 1 in the .should.be.deep.equal() function.
My guess is that the callback in exports.locationList is called synchronously, and that your test case is actually failing, throwing an exception, which never gets caught because the callback is (synchronously) called from within a promise handler (more info here).
Try and see if this works better:
dbFunctions.locationList(req, function(result) {
setImmediate(function() {
console.log(result) //Prints the whole result
console.log(testData.locationList)
result.should.exist; //This doesn't cause it to hang
result.should.be.deep.equal(testData.locationList) //hangs here
done(result);
});
});
// or use a module like dezalgo (https://github.com/npm/dezalgo)
The underlying cause may be mockgoose.
Also, you're not using the proper Node.js conventions where the first argument to a callback function is "reserved" for errors. In other words, your code should look similar to this:
if (err) {
callback(err);
} else {
callback(null, data);
}
You're now passing both errors and data as the first argument.
A guess: Maybe the issue lies with mongoose decorating the result with it's own functions/members, and one of them somehow getting stuck in an infinite loop when chai tries to enumerate them all to perform a deep comparison.
I am using Mocha as a testing framework for my node.js application.
I have an existing module that uses async-waterfall node module.I am trying to write a unit test case for it. I am unable to write a test case for the second function in the array. Any tips on how would I pass the result of one function to the next function in the array
var async = require('async');
module.exports.resetPassword = function(req,res,next){
async.waterfall([
function(done){
var token = do something;
done(err,token);
},
function(token,done){
//do some stuff
res.status(200).send('success');
},
]function(err){
//send failure response
});
};
I think I understand the issue now.
In your test - you execute the line:
user.resetPassword(request,response,next);
And immediately after that - the line:
cryptoStub.restore();
The issue is - that async.waterfall will start the first method, but before it runs the second one, it will run the next line from the unit test, and therefore you don`t see the next method. Code that will solve it will be like:
user.resetPassword(request,response,function(err) {
cryptoStub.restore();
done();
});
Does it look better?
My code is as follows. My issue is around writing a unit test case for this method. I am using mocha along with sinon for stubbing. The unit test that I have written is
Unit Test
it("Should return an error if there is an error in retrieving the user details from the db",function(done)
{
request={
body:{
email:'test#test.com'
}
};
var expectedMessageFromCrypto = '12121212121';
var cryptoStub = sinon.stub(crypto, "randomBytes",function(err,callback){
callback(null,expectedMessageFromCrypto);
});
user.resetPassword(request,response,next);
cryptoStub.restore();
done();
});
});
The resetPassword module
methods.exports.resetPassword = function (req, res, next) {
var token = null;
async.waterfall([
function (done) {
crypto.randomBytes(16, function (err, buf) {
if(err){
return res.status(400);
}
else{
token = buf.toString('hex');
}
done(err, token);
});
},
function (token, done) {
var user = getUserInformation(req.body.email);
sendEmail(user, done);
}
], function (err) {
if (err) {
logger.error('error in sending confirmation mail');
return next(err);
}
res.status(200).send('success');
});
};
I have a series of Mocha/Chai tests that are set up as follows:
var mongoTest = require('../mongoTest.js');
//Connect to test DB before tests and disconnect after
before(function(done) {
mongoTest.mongoConnect(done);
});
after(function(done) {
mongoose.disconnect(done);
})
//Load Data Files
var testData = require('../testData.js')
var deviceAndLocationAnswers = testData.deviceAndLocationAnswers
//Repeated Functions:
var clearCollections = function(coll, callback) {
mongoose.connection.db.dropCollection(coll.collectionName,
function(err, result) {
callback();
});
}
describe('Testing functions that use the Breakers collections', function(){
//Test Setup
var req = {query: {device: testData.powerConsumptionDevice}}
before(function(done) {
this.timeout(15000);
async.forEach(mongoose.connection.collections, clearCollections,
function(err) {
if (err) {console.log(err)};
done();
})
});
before(function(done) {
this.timeout(15000);
Breakers.create(testData.breakersData, function(err, model){
done(err);
});
});
after(function(done) {
this.timeout(15000);
async.forEach(mongoose.connection.collections, clearCollections,
function(err) {
if (err) {console.log(err)};
done();
})
});
// Tests
describe('Testing powerConsumption Function', function() {
it('Should produce some output', function(done) {
this.timeout(15000);
dbFunctions.powerConsumption(req, function(result) {
result.should.exist;
done();
});
});
it('Should produce the same results as the mock up from testData', function(done) {
this.timeout(15000);
dbFunctions.powerConsumption(req, function(result) {
result.should.be.deep.equal(testData.powerConsumptionResults);
done();
});
});
});
});
mongoTest comes from the following file I have:
var mongoose = require('mongoose')
var dBaseURL = 'mongodb://xxxx:yyyyy#ds#####.mongolab.com:zzzz/myDB'; // details removed
exports.mongoConnect = function(callback) {
mongoose.connect(dBaseURL, function(err) {
if(err) {
console.log('MongoDB Connection Error', err);
} else {
console.log('MongoDB Connection Successful')
}
callback();
});
};
I have a total of 14 tests, set up similarly to the ones I've used as examples. The first time I run these tests, a few will always fail (it's never the same few). If I run the tests again immediately after, all of them will pass.
Failure takes the form of the .should.be.deep.equal() calls failing with large diffs. I'm not sure how this could happen, as the data doesn't change between tests.
I've checked the database between tests and the collections are always deleted after the tests have run.
Does anyone have any ideas as to what could be going on here? I'm new to node.js, so it's very likely I've missed some bit of best practice that's causing all of this.
Also, I am aware that it is best practice to mock out the database. I already have a set of tests that do this. I also want a set of tests that use the database so that I can test the actual behavior.
ETA:
Turns out my problems had nothing to do with the code I had posted here.
The functions that would occasionally fail the tests were those that had database calls that didn't sort the output in any particular way. It turns out that Mongoose would sometimes (but not always? WHY?) sort the query results in such a way that they would pass the test. I'd be interested to hear an explanation of how this is the case, but my question can be considered solved.
I'm basing this off of the Page Loading section of http://phantomjs.org/quick-start.html
I want to do something like this:
tests.js
var should = require('chai').should();
var page = require('webpage').create();
describe('test website with phantomJS', function() {
it('should load html from page', function() {
page.open('myHomePageToTest.html', function(status) {
if (status === 'success') {
page.content.should.equal('<!DOCTYPE html>...etc...</html>');
}
});
});
});
If I try to run this with 'mocha-phantomjs test.js' I get the error 'Failed to start mocha: Init timeout'
If I try to run this with 'mocha test.js' I get the error 'Cannot find module "webpage"'
I'm sure those are the expected error messages given the code. It's my understanding that is failing. The code is my description of what I want to do. After several hours of treading water last night, I have no idea how to actually do it.
Thank you for any help or nudge in the right direction.
var assert = require('assert');
var phantom = require('phantom');
describe('Mocha and phantom', function () {
this.timeout(150000);
it('Tweeking with phantomjs', function (done) {
phantom.create(function (ph) {
ph.createPage(function (page) {
page.open('https://www.facebook.com/', function (status) {
page.evaluate(function () {
return document.all[0].outerHTML //can check different elements
}, function (result) {
console.log('----------->>>>result',result);
assert.equal(status,'success','Not appropriate status');
done();
})
})
})
})
})
})
I took the example code from npmjs > jsdom. This process is performed in a few seconds and only after it I want to run a second action, such as console.log. But do not insert the code in the body of jsdom. Maybe it's work with Node.js > Stream
Whant to create a chain of functions, next process start as soon as the end of the previous.
Where i can read about sequence in Node.js?
var jsdom = require("jsdom");
jsdom.env({
url: "http://news.ycombinator.com/",
scripts: ["http://code.jquery.com/jquery.js"],
done: function (errors, window) {
var $ = window.$;
console.log("HN Links");
$("td.title:not(:last) a").each(function() {
console.log(" -", $(this).text());
});
}
});
console.log("The end");
You're looking for Async.js.
To be specific, you're looking for its series() functionality (Run an array of functions in series, each one running once the previous function has completed).
Code example (based on it's docs):
async.series([
function(callback){
jsdom.env({
url: "http://news.ycombinator.com/",
scripts: ["http://code.jquery.com/jquery.js"],
done: function (errors, window) {
var $ = window.$;
console.log("HN Links");
$("td.title:not(:last) a").each(function() {
console.log(" -", $(this).text());
});
callback(null, 'one');
}
});
},
function(callback){
// do some more stuff (second task) ...
callback(null, 'two');
}
],
// optional callback
function(err, results){
console.log("The end");
});