Hello I have problem with .then() function while trying to implement jasmine unit testing.
Here is my code:
describe("getBuilding", function () {
it("checks getBuilding", function () {
var id_building = 4;
LocalDB.getTestData();
LocalDB.getBuilding(id_building).then(function (result) {
expect(result.name).toMatch("Something");
});
});
});
In this case, the result variable has a right value in then() function, but expect just doesnt work here. If i change "Something" to "something else" the tests will still succes, althought it should't.
I tried to solve it like this:
describe("getBuilding", function () {
it("checks getBuilding", function () {
var id_building = 4;
LocalDB.getTestData();
expect(LocalDB.getBuilding(id_building).name).toMatch("Something");
});
});
or
describe("getBuilding", function () {
it("checks getBuilding", function () {
var finalResult;
var id_building = 4;
LocalDB.getTestData();
LocalDB.getBuilding(id_building).then(function (result) {
finalResult=result.name;
});
expect(finalResult).toMatch("Something");
});
});
But in both cases, the value that's being matched is undefined. Can anyone give some advice pls?
Your 'then()' is probably not being run at all - since the promise is resolved asynchronously, you need to either ensure that the promises are resolved before exiting the test or use jasmine async to ensure that jasmine waits for the async method to resolve before moving on to the next test.
In unit tests with promises, often you need to manually notify the angularjs lifecycle that it's time for promises to be resolved.
Try bringing in the $rootScope dependency and adding a call to $rootScope.$digest() at the end of your test.
describe("getBuilding", function () {
it("checks getBuilding", function () {
var id_building = 4;
LocalDB.getTestData();
LocalDB.getBuilding(id_building).then(function (result) {
expect(result.name).toMatch("Something");
});
$rootScope.$digest();
});
});
If that doesn't work by itself, you may also need to use Jasmine Async
describe("getBuilding", function () {
it("checks getBuilding", function (done) {
var id_building = 4;
LocalDB.getTestData();
LocalDB.getBuilding(id_building).then(function (result) {
expect(result.name).toMatch("Something");
done();
}, function(){
done.fail('The promise was rejected');
});
$rootScope.$digest();
});
});
The jasmine async way using done is a better test, because it will fail if the promise is rejected. The first would silently pass if the promise was rejected. However, if you know that this particular promise will always resolve, the first way may be good enough for your scenario.
According to :http://jasmine.github.io/2.0/introduction.html#section-Asynchronous_Support
Jasmine has support for async methods. Essentially your issue is your asserting before your async call has responded. Therefore it has no data and your assert fails.
So according to the above link you could do something like (not tested, i haven't used jasmine so cannot be certain im following the link correctly either. Hopefully you can understand better than i).
describe("getBuilding", function () {
it("checks getBuilding", function () {
var id_building = 4;
LocalDB.getBuilding(id_building).then(function (result) {
expect(result.name).toMatch("Something");
done();
});
});
});
Try to return the promise.
return LocalDB.getBuilding(id_building)
.then(function (result) {
expect(result.name).toMatch("Something");
});
Related
The following async promise lives inside the Angular target that I am testing. I am unable to see the code within the 'then' being invoked and it it this code within the 'then' that I require to test.
angular.module('Ls', [
])
function Locale($rootScope, $http) {
var API = {
getAvailables: getAvailables
};
API.getAvailables().then(function(data) {
..........do stuff
........it what this code is doing that I want to test!!!
});
function getAvailables() {
return $http.get('/l.json').then(function(response) {
return response.data;
});
}
You can either stub getAvailables to always resolve, or you could extract the callback to a separate function and test that.
Option A
sinon.stub(API, 'getAvailables').resolves(data);
Option B
API.getAvailables().then(handleResponse);
^ Test handleResponse function
This fixed it for me
$httpBackend.flush()
https://docs.angularjs.org/api/ng/service/$http#writing-unit-tests-that-use-http
I have a log service that wraps console.log. I'm having difficulty testing it because console.log is async. I override console.log, but I'm still having async issues. The console.log function is being called after my assert.
wrapper(msg) {
console.log.bind(console); //I am binding it because in my real code the console is looked up in a map.
console.log(msg);
}
test('log() can handle valid mask', function (assert) {
let passed = false;
subject = this.subject();
console.log = function() {
passed = true;
};
subject.wrapper('testing');
assert.equal(passed, true);
});
How do I get it to wait for console.log to run? I attempted using promises, but I had no luck with them.
You can use async from qunit
test('log() can handle valid mask', function (assert) {
let passed = false;
debugger;
console.log = function() {
setTimeout(function() {
passed = true;
}, 0);
};
var done1 = assert.async();
wrapper('testing');
setTimeout(function() {
assert.equal(passed, true);
done1();
}, 100);
});
http://jsbin.com/nozoruxori/edit?js,output
works fine
with Ember for async checking you can use andThen wrapper ( for async assertion )
also looks like console.log.bind(console); //I am binding it because in my real code the console is looked up in a map. miss something cause in this state it has no sense
I have the following files:-
target.js
var target = function(repository, logger) {
return {
addTarget : function(target) {
repository.add(target).then(
function (newTarget) {
console.log("added");
logger.info("added");
},
function (err) {
console.log("error");
logger.info("error");
}
);
}
};
};
module.exports = target;
targetTest.js
var chai = require("chai"),
expect = chai.expect,
sinon = require("sinon"),
Promise = require("bluebird"),
baseTarget = require("../target");
describe("target", function(){
it("should log error when it occurs", function() {
var mockRepository = {
add : sinon.stub().returns(Promise.reject(new Error()))
};
var mockLogger = {
info : sinon.spy()
};
var target = baseTarget(mockRepository, mockLogger);
target.addTarget("target");
expect(mockLogger.info.calledWith("error")).to.be.true;
});
});
The issue I have is that expect(mockLogger.info.calledWith("error")).to.be.true; returns false because add method on the repository is async and so hasn't executed yet. Is there a pattern for doing this properly.
This is really more of a question about 'how Promises work' than how they work within test frameworks - the answer to which is that their behaviour remains exactly the same.
Is there a pattern for doing this properly.
It is not so much a pattern as it is what Promises are built to do. Each success handler of a then is executed in sequence on success of the last. In your code we can return the Promise created by calling repository#add as you would if you wanted to use its result or perform some external dependent operation outside of addTarget:
addTarget: function (target) {
return repository
// ^^^^^^
.add(target)
.then(function (newTarget) {
console.log("added");
logger.info("added");
}, function (err) {
console.log("error");
logger.info("error");
});
}
Then place your expectation inside a then that will be executed on success of all members of the Promise chain created in addTarget:
target.addTarget("target").then(function () {
expect(mockLogger.info.calledWith("error")).to.be.true;
cb();
});
Asynchronous Tests
You will notice in the example above that there is also a call to a function cb. Due to your test being asynchronous you need to 'tell' the test framework when the test has completed. This is most often done by declaring your it function with a parameter, from which the framework will infer that the test is asynchronous and pass in a callback:
describe("target", function () {
it("should log error when it occurs", function (cb) {
// ^^^^
});
});
I am using a database library that its callback-based interface looks like this:
var DB = {
insert: function(options, callback) {
}
}
I want to implement a wrapper around this database to convert its callback style API to a promise based API. To do this I have defined the following class:
var DatabaseWrapper = {
init: function(db) {
this.db = db;
},
insert: function(options) {
return Q.denodeify(this.db.insert.bind(this.db))(options);
}
}
I want to write a unit test to ensure that when I call DatabaseWrapper.insert it calls DB.insert. So far my test looks like this:
describe('DatabaseWrapper', function () {
var wrapper, insertSpy, bindStub;
beforeEach(function () {
wrapper = Object.create(DatabaseWrapper);
insertSpy = sinon.spy(function () {
console.log('insertSpy got called');
});
bindStub = sinon.stub();
wrapper.db = {
insert: function (options, callback) {
}
};
sinon.stub(wrapper.db.insert, 'bind').returns(insertSpy);
});
describe('#insert', function () {
it('should delegate to db.insert', function (done) {
wrapper.insert({herp: 'derp'});
expect(wrapper.db.insert.bind).to.have.been.calledOnce;
// This fails but I expect it to succeed
expect(promise).to.have.been.calledOnce;
})
});
});
The DB instance's insert method is actually getting called as after the test fails, as the 'insertSpy got called' message is printed in the console.
But apparently it gets called after the test has failed.
As far as I know, this is due to the way Node's process.nextTick works. So the call to the callback happens after the test fails. Is there a way I can fix this test without relying on third-party libraries (e.g. q-flush)?
You're performing an asynchronous action so it's best to perform an asynchronous test. Adding a setTimeout still leaves you prone to race conditions.
describe('#insert', function () {
it('should delegate to db.insert', function () { // no done here
// note the return here to signal to mocha this is a promise test
return wrapper.insert({herp: 'derp'}).then(function(){
// add expects here, rest of asserts should happen here
expect(wrapper.db.insert.bind).to.have.been.calledOnce;
});
})
});
});
let's take this as an example:
I have 3 urls in an array urls
require function returns a promise which just makes an $http call
this is a working code, but as the array can be '1 to n' this is obviously not what I want.
I need the 3 require as a waterfall, not in parallel.
in the last promise, I need to resolve a final promise which is the var deferred.
require(urls[0]).then(function () {
require(urls[1]).then(function () {
require(urls[2]).then(function () {
deferred.resolve();
});
});
})
this approach is not working, because this will do all the $http calls in parallel.
var promises = [];
angular.forEach(urls, function (value) {
promises.push(require(value));
});
$q.all(promises).then(function () {
deferred.resolve();
});
is there a nice way to do this with a for/cycle?
Create a function to handle the iterations:
function go (urls) {
if (urls[0]) {
require(urls[0]).then(function () {
go(urls.slice(1));
});
}
}
go(urls);
Here is an excellent blog post: http://www.codeducky.org/q-serial/
I will share only the part that is relevant.
First we define this helper method:
function serial(tasks) {
var prevPromise;
angular.forEach(tasks, function (task) {
//First task
if (!prevPromise) {
prevPromise = task();
} else {
prevPromise = prevPromise.then(task);
}
});
return prevPromise;
}
Then we use it.
serial([
function() { return require(urls[0]) },
function() { return require(urls[1]) },
function() { return require(urls[2]) }
]).then(function () {
deferred.resolve();
});
Just to offer another way, there's a "one-line" solution to this without having to make another method:
return promises.reduce($q.when, promises[0]);
See demo here: http://plnkr.co/edit/xlGxYj57lzXdAMM5Iv6s?p=preview (I changed the default $q.when to something else to show handling each promise.)
Update: Made the plunker more representative of OP's scenario.