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
Related
Hi I am trying to get the result from function test() and use it to set variable stageIs however it keeps coming back undefined. Any help would be greatly appreciated I have been trying to figure it out for hours now.
var stage;
import { CONTRACT } from '../contract'
import _ from 'lodash'
export default {
data () {
return {
stageIs: null,
amount: null
}
},
mounted () {
this.coinbase = CONTRACT._eth.coinbase
this.test()
},
methods: {
test () {
CONTRACT.name1(function(err, res) {
stage = (res);
});
alert(stage);
this.stageIs= (stage)
}
When I do the alert inside the test() it works however it will not set {{ stageIs }} for some reason.
test () {
CONTRACT.name1(function(err, res) {
stage = (res);
alert(stage)
this.stageIs = (stage)
})
You have an anonymous function as an argument to CONTRACT.name1. By the signature of this anonymous function, name1 seems to be asynchronous.
As a result, the call to name1 will return immediately, while the work that is supposed to be done by name1 will execute later in the event loop (or it is waiting for IO). As a result, stage would always be undefined.
What you want to do is this:
test () {
let that = this;
CONTRACT.name1(function(err, res) {
stage = (res);
alert(stage)
that.stageIs = stage;
});
}
There are two things happening here. We are assigning a value to stage when the callback is invoked by the asynchronous function name1. We are also assigning a reference to this inside test, because the anonymous function will execute in a different context (and therefore the anonymous function's this would point to something else).
Or you could also use arrow functions to get rid of the this binding problem.
test () {
CONTRACT.name1((err, res) => {
stage = (res);
alert(stage)
this.stageIs = stage;
});
}
I'm trying to wait the browser with browser.wait with a custom ExpectedCondition like this
The FunctionReturningANumber returns only a number and the numberToCheck is the number to check the number for.
var conditionFn = function () {
return functionReturningANumber(param) === numberToCheck;
};
var condition = EC.and(conditionFn);
browser.wait(condition, 50000);
But if I execute this, I get the error: fn(...).then is not a function which basically says, that it expects an promise. I have looked up the documentation about ExpectedConditions, and the example for a custom one is like this:
// You can define your own expected condition, which is a function that
// takes no parameter and evaluates to a promise of a boolean.
var urlChanged = function() {
return browser.getCurrentUrl().then(function(url) {
return url === 'http://www.angularjs.org';
});
};
And I do not see how here a promise is created. I only see, that a boolean is returned, and the documentation says evaluates to a promise of a boolean which confuses me even more.
This above is for waiting a response from an API, this is caused, because the test triggers a backend process, which protractor then needs to wait for. If there is any better way of doing this, I would greatly appreciate a better way.
I am using protractor 3.1.1.
Any help really apprectiated.
Edit:
I found a way to solve this, for some reason the logical solution by #alecxe didn't work, even if it makes sense:
var numberFound = 0;
var done = false;
var check = function () {
numberFound = functionReturnungANumber(param);
if (numberFound != numberToCheck) {
setTimeout(check, 4000);
} else {
done = true;
}
};
check();
return done;
If I add this to the function and retrieve the return value in the test, which calls this function, and add a browser.wait(function () {
return done;
}); there it works.
It's not beautiful, but for some reason, its the only thing working.... for me at least.
It's just that you don't need to wrap your Expected Condition function into EC.and:
browser.wait(conditionFn, 5000);
Try this one.
browser.wait(conditionFn () {
return url === 'http://www.angularjs.org';
}, 8000);
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;
});
})
});
});
I have a handler (callback), an object to handle and four functions, which collect the data to object. In my case I wish to asynchronously call four data retrievers and when execution of all four is complete, handle the resulting object (something similar to the following):
var data = {};
function handle (jsObj) {}
// data retrieving
function getColorData () {}
function getSizeData () {}
function getWeightData () {}
function getExtraData () {}
data.color = getColorData();
data.size = getSizeData();
data.weight = getWeightData();
data.extra = getExtraData();
handle( data );
Of course, this code will not work properly. And if I chain data retrieving functions, they will be called one after another, right?
All four functions should be called asynchronously, cause they are being executed for too long to call them one by one.
Updated:
Thanks to everybody for your suggestions! I prefered $.Deferred(), but I found it slightly difficult to make it work the way I need. What I need is to asynchronously make a view, which requires four kinds of data (extraData, colorData, sizeData & weightData) and I have three objects: App, Utils & Tools.
Just a small description: view is created by calling App.getStuff passed App.handleStuff as a callback. Callback in the body of App.getStuff is called only $.when(App.getExtraData(), App.getColorData(), App.getSizeData(), App.getWeightData()). Before that Utils.asyncRequest passed Tools.parseResponse as a callback is called.
So, now the question is should I create four deferred objects inside each App.get*Data() and also return deferred.promise() from each of them?
And should I deferred.resolve() in the last function in my order (Tools.parseResponse for App.getExtraData in my example)?
var view,
App,
Utils = {},
Tools = {};
// Utils
Utils.asyncRequest = function (path, callback) {
var data,
parseResponse = callback;
// do something with 'data'
parseResponse( data );
};
// Tools
Tools.parseResponse = function (data) {
var output = {};
// do something to make 'output' from 'data'
/* So, should the deferred.resolve() be done here? */
deferred.resolve(output);
/// OR deferred.resolve();
/// OR return output;
};
// App
App = {
// Only one method really works in my example
getExtraData : function () {
var deferred = new jQuery.Deferred();
Utils.asyncRequest("/dir/data.txt", Tools.parseResponse);
return deferred.promise();
},
// Others do nothing
getColorData : function () { /* ... */ },
getSizeData : function () { /* ... */ },
getWeightData : function () { /* ... */ }
};
App.getStuff = function (callback) {
$.when(
App.getExtraData(),
App.getColorData(),
App.getSizeData(),
App.getWeightData()
)
.then(function (extraData, colorData, sizeData, weightData) {
var context,
handleStuff = callback;
// do something to make all kinds of data become a single object
handleStuff( context );
});
};
App.handleStuff = function (stuff) { /* ... */ };
/// RUN
view = App.getStuff( App.handleStuff );
I did not expect the code in my example above to work, it is for illustrative purposes.
I've been trying to solve this for quiet a long time and it still gives no result. The documentation for jQuery.Deferred() and discussions around this, unfortunately, did not help me. So, I would be very glad and greatful for any help or advise.
Conceptually, you would use a counter that gets incremented as each asynchronous call completes. The main caller should proceed after the counter has been incremented by all the asynchronous calls.
I think what you're looking for are Promises / Deferreds.
With promises you can write something like:
when(getColorData(), getSizeData(), getWeightData(), getExtraData()).then(
function (colorData, sizeData, weightData, extraData) {
handle(/*..*/);
}
)
The get*Data() functions will return a promise that they fulfill when their assynchronous call is complete.
Ex:
function getData() {
var promise = new Promise();
doAjax("getData", { "foo": "bar" }, function (result) {
promise.resolve(result);
});
return promise;
}
The when simply counts the number arguments, if all it's promises are resolved, it will call then with the results from the promises.
jQuery has an OK implementation: http://api.jquery.com/jQuery.when/
What I could suggest for this scenario would be something like that.
write a function like this
var completed = 0;
checkHandler = function() {
if(completed == 4) {
handle(data);
}
}
where completed is the number of positive callbacks you must receive.
As soon as every function receives a callback you can increment the "completed" counter and invoke the checkHandler function. and you're done!
in example
function getColorData() {
$.get('ajax/test.html', function(data) {
completed++;
checkHandler();
});
}