The code below has two functions being tested. The contents of these two functions is completely irrelevant. Below these two functions are two additional test functions of which each is testing one of the two previous functions.
The problem
The only output I get in the Qunit display is the results of the first test function which in this case is "add function". I would like to see both and any additional tests in the same output.
Am I missing some syntax that tells Qunit that I want to see the test results of both?
Thank you.
Code
function add(a,b){
return a+b;
};
var answer = add(2,2);
function mathy(a,b,callback){
return callback(a,b)
}
var mathFunc = mathy(2,2,add)
// Test one
test( "add function", function() {
ok(answer === 4);
});
// Test2
test( "callback function", function() {
ok(mathFunc === 4)
});
Use the Qunit autostart flag and the init() and start() methods to run the tests manually:
function add(a,b){
return a+b;
};
var answer = add(2,2);
function mathy(a,b,callback){
return callback(a,b)
}
var mathFunc = mathy(2,2,add)
QUnit.config.autostart = false;
QUnit.init();
QUnit.start();
// Test one
test( "add function", function() {
ok(answer === 4);
});
// Test2
test( "callback function", function() {
ok(mathFunc === 4)
});
References
Managing QUnit Test Suites with Async Module Dependencies | Ian Chan's Blog
Testing Oracle JET Applications
Related
I have been tasked with writing unit tests for some AngularJS code that was written by another team, who didn't write any tests
They have written the following function but I cannot figure out how to test it
function showCallAlerts(callRecord, isInEditMode, callBack) {
var callAlerts = populateCallAlertOnEditCall(callRecord.callAlert);
var callModalInstance = openAlertModalInstance('Call', callAlerts, callBack);
if (callModalInstance !== undefined && callModalInstance !== null) {
callModalInstance.result.then(function() {
// Show equipment alerts based on company details
showEquipmentAlertsBasedOnCompanyDetails(callRecord, isInEditMode, callBack);
});
} else {
// Show equipment alerts based on company details
showEquipmentAlertsBasedOnCompanyDetails(callRecord, isInEditMode, callBack);
}
}
I need to test that each of the functions are called, not worrying about what they do as I'll test them separate, just that they are called.
When populateCallAlertOnEditCall is called it needs to either return an empty array or an array with some items in it
When openAlertModalInstance is called it needs to either return undefined or something that passes through to showEquipmentAlertsBasedOnCompanyDetails
showEquipmentAlertsBasedOnCompanyDetails should actually be called, I'll test that method separate, just that it was called
I have manged to write code to test simple functions but nothing like this one so any help will be much appreciated, I spent most of this afternoon trying to figure it out
You can use jasmine to mock the function calls that you are not interested in testing. For example, you can tell jasmine to return an empty array every time 'populateCallAlertOnEditCall' is called. I will write an example that might give you an insight:
describe('My Test Spec', function() {
var myController;
...
beforeEach( inject(($controller) => {
myController = $controller("myControllerName");
}));
it('Testing showCallAlerts when populateCallAlertOnEditCall returns an empty array', inject(function($controller) {
//setup
//this will replace every call to populateCallAlertOnEditCall with
//the function inside callFake
spyOn(myController, 'populateCallAlertOnEditCall ').and.callFake(function() {
return []; //returning an empty array.
});
//action
myController.showCallAlerts(...);
//assert
//Do your checking here.
}));
it('Testing showCallAlerts when populateCallAlertOnEditCall returns a non-empty array', inject(function($controller) {
//setup
//this will replace every call to populateCallAlertOnEditCall with
//the function inside callFake
spyOn(myController, 'populateCallAlertOnEditCall ').and.callFake(function() {
return [1,2,3,4]; //returning a non-empty array.
});
//action
myController.showCallAlerts(...);
//assert
//Do your checking here.
}));
});
the test that something has been called, you can use a Spy
your assertion would look like:
spyOn(obj, 'populateCallAlertOnEditCall')
expect(obj.method).toHaveBeenCalled()
UPDATED:
populateCallAlertOnEditCall = {}
spyOn(obj, 'populateCallAlertOnEditCall.result')
expect(obj.method).toHaveBeenCalled()
The kind of behaviour you want is called mocking
In Jasmine, mocking is done with Spy Objects, you can read more about those here
Basically, you can use mocks to test if functions were called with the expected parameters.
var xhr = mock( XMLHttpRequest );
xhr.send();
expect( xhr.send ).toHaveBeenCalled();
I have a requirejs module created with the following pattern:
// foo.js
define(function(){
var x = 0;
function doStuff(){
return ++x;
}
return { doStuff: doStuff };
});
And a QUnit test which looks something like this:
// testfoo.js
define(['QUnit, foo'], function(QUnit, foo){
function setup(){
//...?
}
function teardown(){
//...?
}
function runTests(){
QUnit.test('foo counter remains at 1 on multiple tests', function(assert){
assert.equal(foo.doStuff(), 1); // this will work
});
QUnit.test('foo counter remains at 1 on multiple tests', function(assert){
assert.equal(foo.doStuff(), 1); // this obviously won't
});
}
return runTests;
});
How can I reset foo for each test?
I would like to keep foo a revealing module, i.e. not converting it to a constructor function with an altered prototype.
I tried var foo = require('foo');, but since requirejs is AMD based, it will complain about things getting loaded in the wrong order.
I suggest checking out SquireJS to create an isolated context for your tests. Squire is designed to inject mock dependencies by creating an isolated RequireJS context. A side effect of this is that the 'foo' library will be reload each time you call injector.require(), resetting the state of your library. The only downside is that your tests will need to be asynchronous.
// testfoo.js
define(['Squire', 'foo'], function (Squire, foo) {
'use strict';
QUnit.start();
QUnit.module('foo', {
setup: function () {
},
teardown: function () {
}
});
QUnit.test('Testing foo counter in main context.', 2, function (assert) {
assert.equal(foo.doStuff(), 1); // this will work
assert.equal(foo.doStuff(), 2); // this should work also.
});
QUnit.test('Testing foo counter in context created by Squire.', 1, function (assert) {
var done = assert.async(),
injector = new Squire();
injector.require([
'foo'
], function (foo) {
assert.equal(foo.doStuff(), 1); // this will work.
done();
});
});
});
I've posted a sample project here: qunit-squirejs
While this certainly isn't the cleanest way about it, by saving the function as a string, and recreating the function before each test, you can accomplish the same effect.
var fooString = foo.toString();
QUnit.testStart(function() { eval('foo = ' + fooString});
I am trying to do the following thing in Jasmine but not sure if it is possible :
I Got a service object with 2 methods, A and B.
Method A calls method B (B is in fact a $http call which I do not want to do during my test : I want to mock it).
In my BeforeEach section I do this :
spyOn(Serviceinstance, 'B').and.callFake(function(){
return true;
});
in my Test :
var result = Serviceinstance.A();
expect(result).toBeTrue();
Of course, the real code of B returns false.
My problem is that my test always fails. the function provided in the spy is never called by method A.
On the other hand, If I call B like this :
var result = Serviceinstance.B();
Then the function of the spy is called, and my test passes.
So should I modify my instance like this :
Serviceinstance.B = function(){return true;}
because Jasmine cannot mock a "second" level of the call stack ? (seems totally unlikely to me)
I am definitively missing something....
This is a code that works:
describe('Service test suite', function() {
it('should return true', function() {
var Serviceinstance = new Service();
spyOn(Serviceinstance, 'B').and.callFake(function() {
return true;
});
expect(Serviceinstance.A()).toBe(true);
})
});
https://jsfiddle.net/ronapelbaum/9moLhhbr/
This is my code:
var testStacks = new Array();
function test(elem) {
console.log(elem);
... asynch operations
}
testStacks.push(test("hello 0"));
testStacks.push(test("hello 1"));
testStacks.push(test("hello 2"));
testStacks.push(test("hello 3"));
testStacks.push(test("hello 4"));
// init first 3 functions
testStacks[0];
testStacks[1];
testStacks[2];
and I want to execute 3 functions at time. So hello 0, hello 1 and hello 2 start together at the beginning. Than, once one function finish (they do asynch ops) it must calls the next one (not executed yet) from the array. And so on...
Seems that testStacks[0] does nothing, and when I push the function, it will be executed.
How can I do this? (I want to avoid setInterval()).
A simple approach could be pushing both the function AND the parameters.
var testStacks = new Array();
function test(elem) {
console.log(elem);
... asynch operations
}
testStacks.push({func: test, param: "hello 0"});
testStacks.push({func: test, param: "hello 1"});
testStacks.push({func: test, param: "hello 2"});
testStacks.push({func: test, param: "hello 3"});
testStacks.push({func: test, param: "hello 4"});
// init first 3 functions
testStacks[0].func(testStacks[0].param);
testStacks[1].func(testStacks[1].param);
testStacks[2].func(testStacks[2].param);
This could be generalized and cleaned up in many ways, of course, but should give you a basic idea.
You are executing the function and pushing the return value. Push a function instead:
testStacks.push(function(){ test("hello 0"); });
Whatever solution you'll choose, you'll need something like a third party object to manage the current call stack, and a way to notify this object whenever an operation is completed. Regarding the following (pretty dirty) code, I've decided to use a simple callback called from the test function :
var Stack = function (maxCalls, stack) {
this.ongoing = 0;
this.maxCalls = maxCalls;
Array.prototype.push.apply(this, stack);
this.next(); // starts immediately
};
Stack.prototype = Object.create(Array.prototype);
Stack.prototype.next = function () {
var me = this;
while (this.length && this.ongoing < this.maxCalls) {
this.ongoing++;
// calls the next function
// passing a callback as a parameter
this.shift()(function () {
me.ongoing--;
me.next();
});
}
};
See this demo for a use case : http://jsfiddle.net/wared/5eu8b/. As you can see, functions are called one after the other in a First In First Out way, but they complete in any order.
Hope it can help somehow :)
I'm just giving a try to unit testing in javascript/coffeescript with jasmine, very nice.
I've been trying to use jasmine.Clock.Mock() to advance in time and fire setTimeout callbacks.
Alas the jasmine.Clock.tick(1001) did not seem to have any effect !
I then discovered sinon.js that had its own time mock, and using this one it was allright. I'd like to understand why.
Here is a dummy jquery plugin to be tested:
dummy_method = function(callback) {
fire_callback = function() {
callback();
}
setTimeout("fire_callback()", 1000);
}
And here are both versions of the specs :
# Working test (spy was called as expected), using sinon FakeTimers
describe "jQuery.fn.countdown", ->
beforeEach () ->
this.clock = sinon.useFakeTimers();
afterEach () ->
this.clock.restore()
it 'should fireup the callback', ->
countdown_callback = jasmine.createSpy('countdown_callback');
dummy_method(countdown_callback)
this.clock.tick(1001)
expect(countdown_callback).toHaveBeenCalled()
# Non-working test (spy is never called), using jasmine Clock Mock
describe "jQuery.fn.countdown", ->
beforeEach () ->
jasmine.Clock.useMock()
it 'should fireup the callback', ->
countdown_callback = jasmine.createSpy('countdown_callback');
dummy_method(countdown_callback)
jasmine.Clock.tick(1001)
expect(countdown_callback).toHaveBeenCalled()
Jasmine just try to call a function where sinon test if the passed argument is a function or a string. If its a string it call eval.
Jasmine:
jasmine.getGlobal().setTimeout = function(funcToCall, millis) {
if (jasmine.Clock.installed.setTimeout.apply) {
return jasmine.Clock.installed.setTimeout.apply(this, arguments);
} else {
return jasmine.Clock.installed.setTimeout(funcToCall, millis);
}
};
Sinon:
if (typeof timer.func == "function") {
timer.func.apply(null, timer.invokeArgs);
} else {
eval(timer.func);
}
So this will pass the Jasmin test
setTimeout(fire_callback, 1000);
while this will fail
setTimeout("fire_callback()", 1000);