I want to test some promises with jasmine node. However, the test runs but it says that there are 0 assertions. This is my code, is there something wrong? The then part is successfully called, so if I have a console.log there, it gets called. If I have the code test a http request, on the success, the assertion is correctly interpretated.
describe('Unit tests', function () {
it("contains spec with an expectation", function() {
service.getAllClients().then(function (res) {
expect("hello world").toEqual("hello world");
done();
}).catch(function (err) {
fail();
});
});
});
You need to specify the done argument to the callback you pass to it, so Jasmine knows you are testing something asynchronously:
it("contains spec with an expectation", function(done) {
// ...
When you include that parameter, Jasmine will wait for a while for you to call done so it knows when you're done.
done();
Secondly, in an asynchronous test, it probably is better to fail with a call of done.fail:
done.fail();
Related
I'm working to understand unit testing in JavaScript, using Mocha/Sinon/Chai. I have seen the function done() used. But I cannot seem to find documentation for this function. It does not seem to be a part of the JavaScript language. If it were, I would expect to see it in the Mozilla documentation under [something].prototype.done(). But it's not there. I don't see it under jQuery's documentation, nor under Mocha's.
On another thread, I see this example of done():
it('should have data.', function () {
db.put(collection, key, json_payload)
.then(function (result) {
result.should.exist;
done();
})
.fail(function (err) {
err.should.not.exist;
done();
})
})
What is done(), what language or tooling is it a part of, and where is the documentation for it? Is done() just a naming convention for a callback function?
Done is a callback that mocha will provided as the first parameter to a unit testing it block. It is usually needed when testing asynchronous code, as it can be call to notify mocha that the it block is completed. It is good practice to name the callback done. However, you can name it as you want.
You can find its documentation here just hit ctrl + f on windows or ⌘ + f on MAC, then enter done.
it('should have data.', function (done) { // inject done here
db.put(collection, key, json_payload)
.then(function (result) {
result.should.exist;
done();
})
.fail(function (err) {
err.should.not.exist;
done();
})
})
Copied the following from mocha website.
Testing asynchronous code with Mocha could not be simpler! Simply invoke the callback when your test is complete. By adding a callback (usually named done) to it(), Mocha will know that it should wait for this function to be called to complete the test. This callback accepts both an Error instance (or subclass thereof) or a falsy value; anything else will cause a failed test
I am trying to write get the test working that has nested promises. For some reason the promise is never returning.
For example
describe('Some tests', function ()
{
it("Should complete the test with the nested promises", function(done)
{
inject(function (SomeService, $rootScope)
{
SomeService.somePromise().then(function(err)
{
console.log("Message 1");
expect(err).toBeNull();
SomeService.someOtherPromise.then(function(res)
{
console.log("Message 2");
// Check some data
done();
});
});
$rootScope.$digest();
});
});
});
The strange thing is, if this test is run by its self it passes. But if there is more than one of these tests it fails.
When the test fails it seems as though the first promise is never returned. So we don't even see the first console message.
My question is how to get this kind of test running and why is it not working correctly.
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
I have such test for angular app:
it("should return false if all products loaded", function () {
$httpBackend.flush();
scope.loadNextProducts(15).then(function (isThereMoreToLoad) {
expect(isThereMoreToLoad).toBe(false);
});
scope.$apply();
});
If i forget to write ether $httpBackend.flush(); or scope.$apply(); test will never reach expect() part and test will be successful.
Is there way to ensure that jasmine test executed expect(), and if not then it should fail?
Something like specifying to it() how many expect() to expect, or tell jasmine that each test should execute at least one expect() otherwise it should fail.
Try this:
afterEach(function() {
$httpBackend.verifyNoOutstandingExpectation();
$httpBackend.verifyNoOutstandingRequest();
});
That should, well, verify that your tests have no expectations that have not been visited and it should also verify that all of your expected server calls have been called.
You can find more info on the Angular $backend docs
I'm using Mocha to test an asynchronous function that returns a promise.
What's the best way to test that the promise resolves to the correct value?
Mocha has built-in Promise support as of version 1.18.0 (March 2014). You can return a promise from a test case, and Mocha will wait for it:
it('does something asynchronous', function() { // note: no `done` argument
return getSomePromise().then(function(value) {
expect(value).to.equal('foo');
});
});
Don't forget the return keyword on the second line. If you accidentally omit it, Mocha will assume your test is synchronous, and it won't wait for the .then function, so your test will always pass even when the assertion fails.
If this gets too repetitive, you may want to use the chai-as-promised library, which gives you an eventually property to test promises more easily:
it('does something asynchronous', function() {
return expect(getSomePromise()).to.eventually.equal('foo');
});
it('fails asynchronously', function() {
return expect(getAnotherPromise()).to.be.rejectedWith(Error, /some message/);
});
Again, don't forget the return keyword!
Then 'returns' a promise which can be used to handle the error. Most libraries support a method called done which will make sure any un-handled errors are thrown.
it('does something asynchronous', function (done) {
getSomePromise()
.then(function (value) {
value.should.equal('foo')
})
.done(() => done(), done);
});
You can also use something like mocha-as-promised (there are similar libraries for other test frameworks). If you're running server side:
npm install mocha-as-promised
Then at the start of your script:
require("mocha-as-promised")();
If you're running client side:
<script src="mocha-as-promised.js"></script>
Then inside your tests you can just return the promise:
it('does something asynchronous', function () {
return getSomePromise()
.then(function (value) {
value.should.equal('foo')
});
});
Or in coffee-script (as per your original example)
it 'does something asynchronous', () ->
getSomePromise().then (value) =>
value.should.equal 'foo'