How do I make QUnit block until a module is complete? - javascript

I'm trying to use QUnit to test a bunch of javascript. My code looks something like this:
module("A");
doExpensiveSetupForModuleA();
asyncTest("A.1", testA1);
asyncTest("A.2", testA3);
asyncTest("A.3", testA3);
module("B");
doExpensiveSetupForModuleB();
asyncTest("B.1", testB1);
asyncTest("B.2", testB3);
asyncTest("B.3", testB3);
If I run this as-is, then doExpensiveSetupForModuleB() runs while the async tests are running, causing failures.
If doExpensiveSetupForModuleB() is run before testA*, then those tests will either fail or undo the expensive setup work so that testB* fails.
Is there a way to have QUnit block on the next module? Or to have it block starting a new test until the previous asynchronous test has completed? Or is there a better framework for JS testing that I should be using?
Note: I understand that my unit tests are not perfectly atomic. I do have cleanup code that helps make sure I don't get any dirty state, but doExpensiveSetupFor*() is prohibitively expensive, such that it wouldn't be realistic to run it before each test.

Could you use the module lifecycle?
function runOnlyOnce(fn) {
return function () {
try {
if (!fn.executed) {
fn.apply(this, arguments);
}
} finally {
fn.executed = true;
}
}
}
// http://api.qunitjs.com/module/
module("B", {
setup: runOnlyOnce(doExpensiveSetupForModuleB)
});

This is an example, adapted from your original code, that executes the setup method for each test method:
function doExpensiveSetupForModuleA() {
console.log("setup A");
}
function testA1() {
console.log("testA1");
start();
}
function testA2() {
console.log("testA2");
start();
}
function testA3() {
console.log("testA3");
start();
}
function doExpensiveSetupForModuleB() {
console.log("setup B");
}
function testB1() {
console.log("testB1");
start();
}
function testB2() {
console.log("testB2");
start();
}
function testB3() {
console.log("testB3");
start();
}
QUnit.module("A", { setup: doExpensiveSetupForModuleA });
asyncTest("A.1", testA1);
asyncTest("A.2", testA2);
asyncTest("A.3", testA3);
QUnit.module("B", { setup: doExpensiveSetupForModuleB });
asyncTest("B.1", testB1);
asyncTest("B.2", testB2);
asyncTest("B.3", testB3);
This will work independent of the order in which the tests are executed and also independent of the time spent by each method to terminate.
The calls to start() will assure that the test results will be collected only in that point of the method.
More detailed examples can be found in the QUnit Cookbook:
http://qunitjs.com/cookbook/#asynchronous-callbacks
Updated:
if you don't want your expensive methods to be executed before each test method, but actually only once per module, just add control variables to your code to check if the module was already set up:
var moduleAsetUp = false;
var moduleBsetUp = false;
function doExpensiveSetupForModuleA() {
if (!moduleAsetUp) {
console.log("setting up module A");
moduleAsetUp = true;
}
}
...
function doExpensiveSetupForModuleB() {
if (!moduleBsetUp) {
console.log("setting up module B");
moduleBsetUp = true;
}
}
...
In this sample, the output would be:
setting up module A
testA1
testA2
testA3
setting up module B
testB1
testB2
testB3
This way you are using your expensive methods as module setup instead of test method setup.
Unit tests are supposed to be atomic, independent, isolated, and thus the order in which they run shouldn't be relevant.
Qunit doesn't always run tests in the same order, anyway, if you want your tests to run in specific order, you can just tell QUnit to don't reorder them:
QUnit.config.reorder = false;
This way you can ensure that testA will run before testB.

I think you have a misunderstanding on how the test declarations work.
QUnit can run any test independently. Just because you declare a test with test() or asyncTest() does NOT mean QUnit will call the function passed in. The "Rerun" links next to each test reload the page and skip every test but the specific one.
So if you want to rerun a B module test, your code will set up A module, even though it does not need to.
The module setup solution posted by others is likely the way to go here.

Related

Global function not available in Window object when using Jasmine & Headless Chrome

I'm having a hard time figuring out how I can access a function that is usually available as a method of the window object in the browser. I'm using Karma, Headless Chrome and Jasmine.
Here is a simplification of my issue:
I have a module called add-numbers-together.js:
function addTogether(a, b) {
return a + b;
}
(function(){
addTogether(2,5);
})();
That is being tested by this Jasmine test:
describe('add-numbers-together.js', function() {
it('Should add numbers together', function() {
require('module/add-numbers-together');
console.info(window.addTogether);
});
});
The require statement is definitely retrieving the module ok, I have tested that.
I was expecting the console.info to print out the definition of the function, as is the case when I do this in an actual browser, but instead this console.info returns undefined. Why is this? and how can I access the addTogether function after the module has been required in the test?
I'm guessing this is some quirk of Jasmine or Headless Chrome but I can't find the answer anywhere no matter how hard I search!
Also, please note: I do not want to add any test code to the module itself, that is not an option for me.
I changed the test slightly to check that the function is not undefined, but it failed regardless of Chrome or ChromeHeadless as the browser.
describe('add-numbers-together.js', function() {
it('Should add numbers together', function() {
require('module/add-numbers-together');
expect(window.addTogether).not.toBeUndefined();
});
});
To get a version of this test passing, you have several options:
Make the code under test a real module and export the function, then change the test to import that module (recommended). This can also be define and require if using AMD.
Configure your build setup to force a global export from that module without changing the code (webpack can do this, and it's kind of hackey, but it works if you can't edit that script). This is usually only done with 3rd party scripts.
Put the script content in the test file above the test code (not recommended, since you are copy-pasting and changes won't be synced up).
Load the script under test and then the test in the fixture markup (works, but kind of lame since your test fixture HTML now hard codes a script reference).
Here is the code under test rewritten for option #1 with the export of the function.
export function addTogether(a, b) {
return a + b;
}
(function () {
addTogether(2, 5);
})();
And here is the test rewritten for option #1 with the import of the module under test.
import * as addNumbersTogether from 'add-numbers-together';
describe('add-numbers-together.js', function () {
it('Should add numbers together', function () {
expect(addNumbersTogether.addTogether).not.toBeUndefined();
});
});

How to clean up after failed Intern functional tests?

I have some functional tests that run using Intern (3) and the last step in the test is to do some cleanup, including clearing localStorage on the remote browser, and switching back to the original window by storing the window handle right away and switching back to it before the tests end (so any subsequent tests don't fail because they're trying to run on a closed window if the previous test ended on a different one). However if some chaijs assertions fail in a .then() the cleanup code at the end gets skipped. Is there a better way to do cleanup for functional tests that will still get run even when some assertions fail?
this.leadfoot.remote
.get(require.toUrl(url))
.execute(function() { return document.querySelector('#welcome').textContent})
.then(welcome => {
assert.equal(welcome, 'hello world', 'properly greeted');
})
.execute(function() {
localStorage.clear();
});
If the assertion fails it'll never clear localStorage at the end and if the next test that runs expects localStorage to be empty it will fail too. Is there a better way to clean up after a functional test?
Use an afterEach method.
afterEach() {
return this.remote
.execute(function () {
localStorage.clear();
});
},
'my test'() {
return this.remote
.get(...)
.execute(...)
.then(welcome => {
assert.equal(welcome, ...);
});
}
in our project we do it like this:
afterEach: function() {
var command = this.remote;
if(intern.variables.currentCase && !intern.variables.currentCase.hasPassed) {
command = command.execute(function () {
localStorage.clear();
});
}
return command;
},
and local Storage.clear() will be executed only if the test has failed:

Including external .js files for unit tests

I am trying to run coverage tests for my JavaScript unit tests (written in QUnit [not my idea, legacy project]) and run them via command line.
Problem i am facing is references to external bits of code.
Look at example bellow:
Code:
var DateHelper = function() {
return {
GetUtcDate: function (date) {
if (DateTypeChecker.Data["date"]) {
return new Date();
}
return date;
}
}
Test:
QUnit.test('GetUtcNow - compare UTC date', function(assert) {
var currentUtcDate = DateHelper.GetUtcNow();
var nowDate = new Date();
assert.equal(nowDate.getUTCFullYear() == currentUtcDate.getFullYear(), 'dates are the same');
});
So a very simple test that checks two dates, this works lovely when run in the browser, because the external javascript file containing DateTypeChecker is loaded in the HEAD.
But this test fails in the command line as node (or w/e is performing the test) doesn't have a reference to DateTypeChecker object.
My question is, how do i fix this, so that the file for DateTypeChecker is loaded/required? (i know that i can do this with RequireJS, but i don't wan't to add more dependencies and frameworks)
I think this is a general question for js unit testing (not just QUnit).
Two options: (a) mock out the external dependency or (b) actually include the external dependency JS file. For the second option (b), I would use a test runner like Karma and hook up QUnit to it. The configuration is pretty straight forward on that linked site.
The first option (a) is what I would recommend, however. It makes your tests more idempotent and thus loosely coupled. In QUnit you can set up a mock pretty easy, we just use a simple beforeEach function:
QUnit.module( "testing DateHelper", {
beforeEach: function() {
// before each test runs, we can create a "fake" DateTypeChecker
// Note that it doesn't matter what this thing does, so long as it
// satisfies your dependency in the DateHelper
window.DateTypeCheker = {
Data: { date: true }
};
}
});
QUnit.test( ... ); // your normal stuff

Reuse scenarios by using mocha

Recently I've started to use JS and mocha.
I've wrote some tests already, but now I got to the point when I need to reuse my already written tests.
I've tired to look for "it" / "describe" reusing, but didn't find something useful...
Does anyone have some good example ?
Thanks
Considering that if you only do unit testing, you won't catch errors due to integration problems between your components, you have at some point to test your components together. It would be a shame to dump mocha to run these tests. So you may want to run with mocha a bunch of tests that follow the same general patter but differ in some small respects.
The way I've found around this problem is to create my test functions dynamically. It looks like this:
describe("foo", function () {
function makeTest(paramA, paramB, ...) {
return function () {
// perform the test on the basis of paramA, paramB, ...
};
}
it("test that foo does bar", makeTest("foo_bar.txt", "foo_bar_expected.txt", ...));
it("test what when baz, then toto", makeTest("when_baz_toto.txt", "totoplex.txt", ...));
[...]
});
You can see a real example here.
Note that there is nothing that forces you to have your makeTest function be in the describe scope. If you have a kind of test you think is general enough to be of use to others, you could put it in a module and require it.
Considering each test is only designed to test a single feature/unit, generally you want to avoid reusing your tests. It's best to keep each test self-contained an minimize the dependencies of the test.
That said, if you have something you repeat often in your tests, you can use a beforeEach to keep things more concise
describe("Something", function() {
// declare your reusable var
var something;
// this gets called before each test
beforeEach(function() {
something = new Something();
});
// use the reusable var in each test
it("should say hello", function() {
var msg = something.hello();
assert.equal(msg, "hello");
});
// use it again here...
it("should say bye", function() {
var msg = something.bye();
assert.equal(msg, "bye");
});
});
You can even use an async beforeEach
beforeEach(function(done) {
something = new Something();
// function that takes a while
something.init(123, done);
});

Revealing Module Pattern - Unit Testing with Jasmine

After a brief romance with the revealing module pattern I've come to realise a set-back when it comes to unit-testing modules. I cannot however decide if it is my approach to testing a module or whether there is some form of work-around.
Consider the following code:
var myWonderfulModule = (function () {
function publicMethodA (condition) {
if(condition === 'b') {
publicMethodB();
}
}
function publicMethodB () {
// ...
}
return {
methodA : publicMethodA,
methodB : publicMethodB
}
}());
If I wanted to test (using Jasmine) the various paths leading through publicMethodA to publicMethodB. I might write a small test like so:
it("should make a call to publicMethodB when condition is 'b'", function() {
spyOn(myWonderfulModule , 'publicMethodB');
myWonderfulModule.publicMethodA('b');
expect(myWonderfulModule.publicMethodB).toHaveBeenCalled();
});
If I understand correctly, there's a copy of publicMethodB within the closure that cannot be changed. Even if I change myWonderfulModule.publicMethodB afterwards:
myWonderfulModule.publicMethodB = undefined;
calling myWonderfulModule.publicMethodA will still run the original version of B.
The example above is of course simplified but there are plenty of scenarios I can think of where it would be convenient to unit test conditional paths through a method.
Is this a limitation of the revealing module pattern or simply a misuse of unit testing? If not what work-arounds are available to me? I'm considering moving to something like RequireJS or reverting back to non-modular code.
Any advice appreciated!
You cant test the intern methodes of a closure. And you also shouldn't spy on it. Think about about your module as a black box. You put something in and you get something out. All you should test is that the thing you get out of your module is the one that you expect.
Spying on methodes in your module makes not much sense. Think about it. You spy on it, the test passes. Now you change the functionality so it creates a bug, the test still passes cause the function is still called but you never mention the bug. If you just test the thing that cames out you dont need to spy on internal methodes cause, that they are called is implicite when the outcome of the module is what you expect.
So in your case there is no thing that goes in and nothing comes out. This makes not much sense but I believe that your module interacts with DOM or makes an ajax call. This are things that you can test (DOM) or you should spy on (ajax).
You should also make you self familiar with Inversion of Control and Dependency Injection. These are patterns that will make your modules much more easier to test.
If you use the keyword "this" when you call publicMethodB() from publicMethodA() it will work. For example:
var myWonderfulModule = (function () {
function publicMethodA (condition) {
if(condition === 'b') {
this.publicMethodB();
}
}
function publicMethodB () {
// ...
}
return {
methodA : publicMethodA,
methodB : publicMethodB
}
}());

Categories

Resources