Jasmine - Running beforeAll blocks in series - javascript

Before testing a certain feature of my Meteor application with Jasmine I have to prepare different things for the tests. Therefore I use beforeAll blocks.
Reset the database
Create a lecture in the database
Create a question in the database
Go to the page of the just created lecture
Wait for the Router to finish routing
These asynchronous tasks have to run in series. I can not first go to the lecture page and then create it in the database. Sadly beforeAll blocks in Jasmine will not automatically run in series.
This is my current code:
beforeAll(function(done) {
Fixtures.clearDB(done);
});
beforeAll(function(done) {
Fixtures.createLecture({}, function(error, result) {
lectureCode = result;
done();
});
});
beforeAll(function(done) {
Fixtures.createQuestion({}, done);
});
beforeAll(function(done) {
Router.go('lecturePage', {lectureCode: lectureCode});
Tracker.afterFlush(done);
});
beforeAll(waitForRouter);
it("....", function() {
...
});
How can I write this code in Jasmine in a pretty style without going into callback hell?
The Source Code of the entire application is open source and can be found on GitHub
Thank you very much in advance,
Max

Here you are:
beforeAll(function(done) {
async.series([
function(callback) {
Fixtures.clearDB(callback)
},
function(callback) {
Fixtures.createLecture({}, function(error, result) {
lectureCode = result;
callback();
});
},
function(callback) {
Fixtures.createQuestion({}, callback);
},
function(callback) {
Router.go('lecturePage', {lectureCode: lectureCode});
Tracker.afterFlush(callback);
}],function(err, results){ // callback called when all tasks are done
done();
});
}
I haven't tested it but I hope you get an idea. You need to create list of functions, each of them will be provided with callback function that you need to call to make next function run. After that final callback is called where we can call done() to tell jasmine that we're done. Hope this helps.

My general approach would be to have a single beforeAll block.
Inside that block, use a promise API to chain all these calls as promises.
beforeAll(function(done) {
Fixtures.clearDB(done).then(...
});
beforeAll(waitForRouter);
it("....", function() {
...
});

Related

Jasmine async testing without settimeout

I'm looking to create some jasmine specs for a piece of code that has async functionality.
In the jasmine docs it shows the example:
it("takes a long time", function(done) {
setTimeout(function() {
done();
}, 9000);
});
Using the done function and a setTimeout, my issue with this is setTimout could be fragile i.e. delays in test runs in enviros
is there an alternative solution to such tests where I don't have to use a timeout?
Thanks in advance
In this example setTimeout is actually the function being tested. It's used as a representative example of an asynchronous function. The key point is that you must explicitly call done() when your test is complete. Your code should look something like:
it("takes a long time", function(done) {
myMethod('foo', 'bar', function callback() {
assert(...)
done();
}); // callback-style
}
it("takes a long time", function(done) {
myMethod('foo', 'bar').then(function() {
assert(...)
done();
}); // promise-style
});
it("takes a long time", async function(done) {
await myMethod('foo', 'bar')
assert(...)
done()
});
The documented function is intended to illustrate using the done callback following a long-running method, and should not be used for actual tests.
Normally, you would expect a long running function to be supplied with a callback in which you would call the done function. For example, you could write a unit test involving a file that took a long time to write data:
it("writes a lot of data", function(done) {
var fd = 999; // Obtain a file descriptor in some way...
fs.write(fd, veryLongString, function (err, written, string) {
// Carry out verification here, after the file has been written
done();
});
Again, this is only illustrative, as you would generally not want to write to a file within the body of a unit test. But the idea is that you can call done after some long-running operation.

Using promises to wait for function to finish

I've read some tutorials online for the Promises method but I'm still a bit confused.
I have a Node app.js which performs several functions including connecting to a db.
db.connect(function(err) {
setupServer();
if(err) {
logger.raiseAlarmFatal(logger.alarmId.INIT,null,'An error occurred while connecting to db.', err);
return;
}
Now I have written a mocha unit test suite, which encapsulates this app and performs several request calls to it. In some cases what occurs is that the the test initializes without confirmation that the db has successfully connected i.e: setupServer() has been performed.
How would I implement the promises method to this bit of asynchronous code, and if not promises, what should I use ? I have already tried event emitter but this still does not satisfy all the requirements and causes failures during cleanup.
If you're using mocha, you should use asynchronous code approach. This way you can instruct mocha to wait for you to call done function before it goes on with the rest.
This would get you started:
describe('my test', function() {
before(function(done) {
db.connect(function(err) {
setupServer(done);
});
})
it('should do some testing', function() {
// This test is run AFTER 'before' function has finished
// i.e. after setupServer has called done function
});
});
assuming that your setupServer calls the done function when it's done:
function setupServer(done) {
// do what I need to do
done();
}
You will need to use Promise inside the body of function that has async work. For your case, I think that is setupServer() which you said contains ajax requests.
conts setupServer = () => {
return new Promise((resolve, reject) => {
//async work
//get requests and post requests
if (true)
resolve(result); //call this when you are sure all work including async has been successfully completed.
else
reject(error); //call this when there has been an error
});
}
setupServer().then(result => {
//...
//this will run when promise is resolved
}, error => {
//...
//this will run when promise is rejected
});
For further reading:
Promise - MDN

Unit testing async functions in Ember controllers

I've hit a very weird problem: I'm trying to make unit tests to achieve 100% testing coverage on my application.
And of course I wrote some tests for my controllers but it seems like there is no way to test anything async in Ember (2.4.0) using ember-cli.
I have a function in controller that does this:
readObject() {
this.store.findRecord('myModel',1).then(function(obj) {
this.set('property1',obj.get('property2');
}.bind(this));
}
I'm writing a test that should cover this function.
test('action readObject', function (assert) {
const cont = this.subject();
cont.readObject();
assert.equal(cont.get('property1'), 'someValue);
});
Obivously, this assert wouldn't work because readObject() is async call but this isn't the root of the problem. The problem is that then a callback in this.store.findRecord is being executed - my controller is already destroyed! So I get "calling set on destroyed object" error there.
In other words - even if I wrap my function in a promise and reformat both functions like this:
readObject() {
return new Promise(function(resolve) {
this.store.findRecord('myModel',1).then(function(obj) {
this.set('property1',obj.get('property2');
resolve();
}.bind(this));
}.bind(this));
}
and
test('action readObject', function (assert) {
const cont = this.subject();
cont.readObject().then(function() {
assert.equal(cont.get('property1'), 'someValue);
});
});
It wouldn't work, because after executing readObject() my controllers become immediately destroyed, not waiting for any callbacks.
So, it could be any async call instead of store.findRecord - it could be Ember.run.later, for example.
Does anybody had the same issue? I've read a lot of articles I can't believe that Ember with such a big community doesn't provide a way to make async unit tests.
If anyone has any clues - please give me a hint, cause I'm kinda lost here. At the moment I have two thoughts:
I'm making controllers wrong, Ember doesn't suppose any async operations inside of it. But even if I move async calls to services - I hit the same problem with writing unit tests for them.
I have to decompose my functions to
readObject() {
this.store.findRecord('myModel',1).then(this.actualReadObject.bind(this));
}
actualReadObject(obj) {
this.set('property1',obj.get('property2');
}
to have at least callbacks body covered with tests, but this means I never get 100% testing coverage in my app.
Thank you in advance for any clues. :)
I had a similar problem and looking at the QUnit API - async I solved it. Try out following:
// ... in your controller ...
readObject() {
return this.store.findRecord('myModel',1).then(function(obj) {
this.set('property1', obj.get('property2');
}.bind(this));
}
// ... in your tests, either with assert.async: ...
const done = assert.async(); // asynchronous test due to promises usage
Ember.run(function(){
subject.readObject().then(function(){
// once you reach this point you are sure your promise has been resolved
done();
});
});
// or without assert.async
let promise;
Ember.run(function(){
promise = subject.readObject();
});
return promise;
In a case of unit tests I do also mock other dependencies, for example: store.
this.subject({
property1: null,
store: {
findRecord(modelName, id){
assert.equal(modelName, "myModel1");
assert.equal(id, 1);
return new Ember.RSVP.Promise(function(resolve){
resolve(Ember.Object.create({ property2: "a simple or complex mock" }));
})
}
}
});
I am not sure about the second case (the one without assert.async). I think it would work too, because the test suite returns a promise. This gets recorgnized by QUnit that waits for the promise.
I copy my own solution here, cause code formatting in comments isn't too good.
test('async', function (assert) {
const cont = this.subject();
const myModel = cont.get('store').createRecord('myModel'); //
// Make store.findRecord sync
cont.set('store',{
findRecord(){
return { then : function(callback) { callback(myModel); } }
}
});
// Sync tests
assert.equal(cont.get('property2'), undefined);
cont.readObject(); // This line calls store.findRecord underneath
assert.equal(cont.get('property2'), true);
});
So, I just turned store.findRecord into a sync function and it runs perfect. And again - many thanks to Pavol for a clue. :)

should.js not causing mocha test to fail

I'm very new to unit tests, mocha, and should.js, and I'm trying to write a test for an asynchronous method that returns a promise. Here is my test code:
var should = require("should"),
tideRetriever = require("../tide-retriever"),
moment = require("moment"),
timeFormat = "YYYY-MM-DD-HH:mm:ss",
from = moment("2013-03-06T00:00:00", timeFormat),
to = moment("2013-03-12T23:59:00", timeFormat),
expectedCount = 300;
describe("tide retriever", function() {
it("should retrieve and parse tide CSV data", function() {
tideRetriever.get(from, to).then(
function(entries) { // resolve
entries.should.be.instanceof(Array).and.have.lengthOf(expectedCount);
},
function(err) { // reject
should.fail("Promise rejected", err);
}
);
});
});
When I manually test the tideRetriever.get method, it consistently resolves an array of 27 elements (as expected), but the test will not fail regardless of the value of expectedCount. Here is my simple manual test:
tideRetriever.get(from, to).then(
function(entries) {
console.log(entries, entries.length);
},
function(err) {
console.log("Promise rejected", err);
}
);
I can also post the source for the module being tested if it's necessary.
Am I misunderstanding something about Mocha or should.js? Any help would be greatly appreciated.
UPDATE
At some point Mocha started to support returning Promise from test instead of adding done() callbacks. Original answer still works, but test looks much cleaner with this approach:
it("should retrieve and parse tide CSV data", function() {
return tideRetriever.get(from, to).then(
function(entries) {
entries.should.be.instanceof(Array).and.have.lengthOf(expectedCount);
}
);
});
Check out this gist for complete example.
ORIGINAL
CAUTION. Accepted answer works only with normal asynchronous code, not with Promises (which author uses).
Difference is that exceptions thrown from Promise callbacks can't be caught by application (in our case Mocha) and therefore test will fail by timeout and not by an actual assertion. The assertion can be logged or not depending on Promise implementation. See more information about this at when documentation.
To properly handle this with Promises you should pass err object to the done() callback instead of throwing it. You can do it by using Promise.catch() method (not in onRejection() callback of Promise.then(), because it doesn't catch exceptions from onFulfilment() callback of the same method). See example below:
describe("tide retriever", function() {
it("should retrieve and parse tide CSV data", function(done) {
tideRetriever.get(from, to).then(
function(entries) { // resolve
entries.should.be.instanceof(Array).and.have.lengthOf(expectedCount);
done(); // test passes
},
function(err) { // reject
done(err); // Promise rejected
}
).catch(function (err) {
done(err); // should throwed assertion
});
});
});
PS done() callback is used in three places to cover all possible cases. However onRejection() callback can be completely removed if you don't need any special logic inside it. Promise.catch() will handle rejections also in this case.
When testing asynchronous code, you need to tell Mocha when the test is complete (regardless of whether it passed or failed). This is done by specifying an argument to the test function, which Mocha populates with a done function. So your code might look like this:
describe("tide retriever", function() {
it("should retrieve and parse tide CSV data", function(done) {
tideRetriever.get(from, to).then(
function(entries) { // resolve
entries.should.be.instanceof(Array).and.have.lengthOf(expectedCount);
done();
},
function(err) { // reject
should.fail("Promise rejected", err);
done();
}
);
});
});
Note that the way Mocha knows this is an async test and it needs to wait until done() is called is just by specifying that argument.
Also, if your promise has a "completed" handler, which fires both on success and failure, you can alternatively call done() in that, thus saving a call.
More info at:
http://mochajs.github.io/mocha/#asynchronous-code

Any established convenient callback writing styles for javascript?

Callbacks are more and more a requirement in coding, especially when you think about Node.JS non-blocking style of working. But writing a lot of coroutine callbacks quickly becomes difficult to read back.
For example, imagine something like this Pyramid Of Doom:
// This asynchronous coding style is really annoying. Anyone invented a better way yet?
// Count, remove, re-count (verify) and log.
col.count(quertFilter, function(err, countFiltered) {
col.count(queryCached, function(err, countCached) {
col.remove(query, function(err) {
col.count(queryAll, function(err, countTotal) {
util.log(util.format('MongoDB cleanup: %d filtered and %d cached records removed. %d last-minute records left.', countFiltered, countCached, countTotal));
});
});
});
});
is something we see often and can easily become more complex.
When every function is at least a couple of lines longer, it starts to become feasible to separate the functions:
// Imagine something more complex
function mary(data, pictures) {
// Do something drastic
}
// I want to do mary(), but I need to write how before actually starting.
function nana(callback, cbFinal) {
// Get stuff from database or something
callback(nene, cbFinal, data);
}
function nene(callback, cbFinal, data) {
// Do stuff with data
callback(nini, cbFinal, data);
}
function nini(callback, data) {
// Look up pictures of Jeff Atwood
callback(data, pictures);
}
// I start here, so this story doesn't read like a book even if it's quite straightforward.
nana(nene, mary);
But there is a lot of passing vars around happening all the time. With other functions written in between, this becomes hard to read. The functions itself might be too insignificant on their own to justify giving them their own file.
Use an async flow control library like async. It provides a clean way to structure code that requires multiple async calls while maintaining whatever dependency is present between them (if any).
In your example, you'd do something like this:
async.series([
function(callback) { col.count(queryFilter, callback); },
function(callback) { col.count(queryCached, callback); },
function(callback) { col.remove(query, callback); },
function(callback) { col.count(queryAll, callback); }
], function (err, results) {
if (!err) {
util.log(util.format('MongoDB cleanup: %d filtered and %d cached records removed. %d last-minute records left.',
results[0], results[1], results[3]));
}
});
This would execute each of the functions in series; once the first one calls its callback the second one is invoked, and so on. But you can also use parallel or waterfall or whatever flow matches the flow you're looking for. I find it's much cleaner than using promises.
A different approach to callbacks are promises.
Example: jQuery Ajax. this one might look pretty familiar.
$.ajax({
url: '/foo',
success: function() {
alert('bar');
}
});
But $.ajax also returns a promise.
var request = $.ajax({
url: '/foo'
});
request.done(function() {
alert('bar');
});
A benefit is, that you simulate synchronous behavior, because you can use the returned promise instead of providing a callback to $.ajax.success and a callback to the callback and a callback.... Another advantage is, that you can chain / aggregate promises, and have error handlers for one promise-aggregate if you like.
I found this article to be pretty useful.
It describes the pro and cons of callbacks, promises and other techniques.
A popular implementation (used by e.g. AngularJS iirc) is Q.
Combined answers and articles. Please edit this answer and add libraries/examples/doc-urls in a straightforward fasion for everyone's benefit.
Documentation on Promises
Asynchronous Control Flow with Promises
jQuery deferreds
Asynchronous Libraries
async.js
async.waterfall([
function(){ // ... },
function(){ // ... }
], callback);
node fibers
step
Step(
function func1() {
// ...
return value
},
function func2(err, value) {
// ...
return value
},
function funcFinal(err, value) {
if (err) throw err;
// ...
}
);
Q
Q.fcall(func1)
.then(func2)
.then(func3)
.then(funcSucces, funcError)
API reference
Mode examples
More documentation

Categories