node.js and mocha-qunit-ui: test with asynchronous requirejs dependencies - javascript

Short description first: The test in the following snipped is never executed:
setTimeout(function() {
test("test", function() {
ok(true, "okay");
})
}, 1000);
Is there any way not to autostart the mocha-qunit-ui but wait for some asynchronous callbacks to create tests?
So, why would I need it this way?
I'm trying to run in-browser-tests for my classes with nodejs and the mocha-qunit-ui. The classes are loaded asynchrously by requirejs.
So I could create a test like this:
test("test", function() {
stop();
requirejs(
['Dependency'],
function(Dependency)
{
expect(1);
var d = new Dependency();
ok(d.test(), "test");
start();
}
);
}
But I want to run multiple tests on the same class with the same dependencies, so I thought of creating a test object
var d = new Dependency();
outside of the test. But then the test would be inside an asynchronous call, and therefore is never called.

Well, I'm not terribly familiar with mocha-qunit-ui plugin specifically, but QUnit has a config object that you can use to tell it not to run until you are ready (so you can load all of your classes, etc first):
<script src="path/to/qunit.js"></script>
<script>
QUnit.config.autostart = false; // be sure this is set BEFORE you add your actual tests
require(
[ "whatever", "your", "dependencies", "are" ],
function() {
QUnit.start(); // tell QUnit you're ready to go
}
);
<script>

Related

How not to run certain codes in BeforeAll for a specific Describe() block in Jasmine

I'm working on a Jasmine unit test spec. There are multiple describe() blocks in the JS file.
In BeforeAll, I want to only call function for Describe-Block "A" and "C", so how can I do that? The logic is like this:
//SampleSpec.js
BeforeAll(function() {
if(descirbe name !== "B"){
DoSomething();
}
});
descirbe("A", function() {
//...
});
descirbe("B", function() {
//..
});
descirbe("C", function() {
//...
});
Without knowing more about your setup, beforeAll will always run. But you could create your own sharedSetup() function & just call it at the top of A and C, but not B. If it is promise based, you can sharedSetup.then() to defer running the rest of your code until the promise resolves.
This is beneficial as it keeps the logic for a test clearly within that test, rather than having a conditional for the test elsewhere in the test file.

Using Jasmine to test a module calling another module

I'm trying to use Jasmine to test that some modular JavaScript is initiating as expected. But I'm going round in circles.
As a simplified example, I have these two files:
// myObj.all.js
;(function() {
window.myObj = window.myObj || {};
myObj.all = {
init: function() {
myObj.page.init();
}
};
}());
// myObj.page.js
;(function() {
window.myObj = window.myObj || {};
myObj.page = {
init: function() {
console.log('hello');
}
};
}());
And in the HTML I would call:
myObj.all.init();
to initialise everything. There are more modules in addition to myObj.page, and one call to myObj.all.init() initialises all of them.
I want to test that when myObj.all.init() is called, then myObj.page.init() is also called. I thought something like this would do it, but the test fails:
spyOn(myObj.page, 'init');
myObj.all.init({});
expect(myObj.page.init).toHaveBeenCalled();
How should I test this?
I have never used jasmine but an easy way to verify that methods are being called from within another method is to mock the methods that should be called.
It looks like jasmine has support for mocking.
In this case you could mock myObj.page.init() and all other methods that should be called from myObj.all.init(). The mocking should provide a method to assert that the mocked method was actually called.

Ember Data's store promises don't work in quint tests

Update
A bit of context into some quirks of the illustrative code below. StoreProxy exists as a model, created by the ApplicationRouter, that has a reference to the store. This lets other objects access the store directly (for singletons, tests, etc). Example:
MyApp.StoreProxy = DS.Model.extend();
MyApp.ApplicationRoute = U.Route.extend({
model: function () {
return this.store.createRecord('storeProxy');
}
});
Before the route is executed, StoreProxy doesn't have a store property. After, it does. I can only assume this is because of some ember-data magic.
I very well realize your reaction to this may be "Ugh! No! You're doing it wrong!". Noted. We'll move to do it the right way from here over time. That said, this is where the code is now. So, given that, and given this method for getting a reference to the current store, why doesn't the code below call its accept or rejection handlers?
Original question
I'm writing a qUnit unit test for ember. I'm using fixture data. The findAll call on the store isn't resolving or rejecting the promise.
test('Find all in store', function() {
expect(1);
var findPromise;
findPromise = MyApp.StoreProxy.store.findAll('rule');
findPromise.then(function(result) {
console.log('yes');
ok(true);
}, function(error) {
console.log('no');
});
});
I tried using async tests mentioned in this question:
testing ember fixture data with quint but the resolve and reject are never called, so the test hangs indefinitely.
I've also tried placing Ember.run calls around my code, in case it's a weird run loop thing. But to no avail.
asyncTest('Find all in store', 1, function() {
var findPromise;
Ember.run(function() {
findPromise = MyApp.StoreProxy.store.findAll('rule');
findPromise.then(function(result) {
console.log('yes');
ok(true);
start();
}, function(error) {
console.log('no');
start();
});
});
});
The code I'm testing runs fine when I run the application normally (fixture adapter or no), so it feels like something with the test environment.
Any thoughts on what to try? I'm stumped.
The way that you're writing your asynchronous tests is incorrect. Check out QUnit's page on async testing. Your test should look something like this:
asyncTest('Find all in store', function() {
var findPromise = ...;
findPromise.then(function(result) {
start();
ok(result);
}, function() {
start();
ok(false);
});
});
Specifically:
You put an extra parameter in the asyncTest function, which likely causes the test to not run at all.
You're using Ember.Application.store, which is not how you should access your store (and probably isn't even a valid store). I'm not sure what your context is, but you should be getting your store from elsewhere.
You're putting the start() calls after your assertions when they should be before.

Is there a YUI equivalent to jQuery's $.holdReady()?

I have a situation where some third party code is executing a callback with
YUI({
delayUntil: 'domready'
}).use(....)
My issue is that I'm using another asynchronous script loader for my code, and I need to delay that callback until after my scripts have loaded. I'm using Yeti for unit testing which injects YUI into test pages, otherwise my code has nothing to do with YUI.
jQuery has a holdReady method that delays executing domready handlers registered through jQuery until some later time. I'm wondering if YUI has some equivalent method. This is for a test page and the code under test doesn't use YUI, so if the solution involves some ugly hack that'll be fine.
EDIT:
It turns out that Yeti uses its own scoped YUI object, and there isn't a way to access it anyway, so even if I found an answer to this question, it wouldn't help me here. In case anyone is wondering how I fixed the Yeti specific problem without finding a way in YUI to defer document ready handlers, here is my code:
!function(){
var mochaListeners = [];
var fakeRunner;
// Stub for Yeti in case mocha isn't loaded on domready
window.mocha = {
run : function(){
return fakeRunner = {
on : function(type, fn){
mochaListeners.push([type, fn]);
}
};
}
};
yepnope([
{
load : [
'assets/lib/lodash.js',
'assets/lib/jquery.js',
'assets/lib/css/mocha.css',
'assets/lib/mocha.js',
'assets/lib/chai.js',
'assets/lib/sinon.js'
],
complete : function(){
mocha.setup('bdd')
}
},{
load : 'assets/js/my_tests.js',
complete : function(){
executeTests = function(){
var runner = mocha.run();
runner.ignoreLeaks = true;
_.forEach(mochaListeners, function(listener){
runner.on(listener[0], function(){
_.extend(fakeRunner, runner);
listener[1].apply(this, arguments);
});
});
};
if(document.readyState === 'complete')
executeTests();
else
$(executeTests);
}
}]);
}();

Convert async calls to sync?

I got problems to handle async calls.
For example I want to load some modules dynamically with requirejs.
Currently I use the subscriber-publisher pattern. Unfortunately this makes my code
in some situation really confusing...:
imagine there is a working event system in the object
var loader = {
load: function(modules) {
// do a async requirejs call
require(modules, function(){
// map arguments to normal array
var modules = [].slice().call(arguments);
// fire loaded event, pass modules
this.trigger('loaded', modules);
}.bind(this));
}
};
var parent = {
// do some initialization work
initialize: function() {
// execute the second initialization when our modules have finished loading async
loader.on('loaded', this.secondInitialize, this);
// require the given modules in the array
loader.load(['one', 'two', 'three']);
},
secondInitialize: function(modules) {
var three = new modules[2]();
// do something with the 'three' module
}
};
As you see this is really confusing.
Are there any other design patterns which allow handsome handling of async calls?
Look into the jQuery Deferred object. (Even without jq, most libraries have an implementation of javascript promises)
With it you can do something like this:
var loadingOne = getLibOne(); //returns a jquery deferred promise
var loadingTwo = getLibTwo(); //returns another one
var loadingAllLibraries = $.when(loadingOne, loadingTwo);
loadingAllLibraries.done(function(lib1, lib2) {
//... stuff
});
Not exactly your scenario but you get the idea. It becomes relatively easy to compose asynchronous atoms.

Categories