Tag Archives: RequireJs

Using Blanket with Jasmine and Require

Using Blanket with Jasmine and Require

UPDATE: So Alex Seville has pointed out in a comment that there is a much simpler solution to this problem – Adding a second script tag for blanket right after the require script tag. I can think of no good reason not to do this instead of what I’ve done below. I’ll leave it here in case it’s useful to someone though.

So I’ve Talked about Require and Jasmine and even how to get them to work together. I’ve also talked about the magical code coverage tool Blanket. Today I’m going to talk about getting all three of these working well together.

Using Blanket with Jasmine is trivial, that’s part of the point behind Blanket. It’s just a case of including it in the page. With Require in the mix it gets a little more complex. I’m going to pick up here from where I left the code getting Require and Jasmine working together. So if you’ve not read that, it might be an idea now.

All on the same page? Good. So, we’re going to be doing everything in specRunner.js. The first thing to do is download blanket-jasmine

The second thing we need to do is load Blanket in with require. Blanket is not a require module and it depends on Jasmine, so it will also need shimming. We’ve already got some Shims set up, so just add blanket: {deps: ['jasmine'], exports: 'blanket'} to it to produce something like this

shim: {
  jasmine: {
    exports: 'jasmine'
  },
  jasmineHtml: ['jasmine'],
  jasmineHelper: ['jasmine'],      
  jasmineJquery: ['jasmine'],
  blanket: {
      deps: ['jasmine'],
      exports: 'blanket'
  },
  jquery: {
      exports: '$'
  }
}

You will recall that we’ve got a pair of nested require calls, one loading in Jasmine the other loading in all our specs. Add blanket to the one loading in jasmine.

Then we’ve got two more changes to make, one before the require call loading in the specs one after. Before loading in the specs add this line:

blanket.setFilter(['path/to/your/jsFolder']);

The parameter for the setFilter function tells Blanket what files to pay attention to and which to ignore. Using this lets you avoid being shouted at for not testing your external libraries. It takes an array, so you can define multiple paths but I only needed the one.

After loading in your specs add this

jasmineEnv.addReporter(new jasmine.BlanketReporter());

No thought required here, this just turns Blanket on. Job done.

And with that, we have Blanket working! Blanket does have two down sides, though. One is that a file which is not referenced at any point in the tests will not show up in the results. Since we already had a file linking Jasmine into Gradle, it wasn’t too hard to add a stage which compared the list of files picked up by Blanket to the list of files in our js folders to catch anything completely untested. I’ll talk about this a bit in the future, but I can’t really take credit for or claim to understand most of it.

The other down side to Blanket is it cannot be run with the file:// protocol in most browsers because it issues cross domain requests. It is convenient to be able to quickly run our tests on a local device through the file:// protocol so I preferred the notion of not losing this.

I actually came up with two solutions, one which required no effort on the developer in question’s part and one which required a bit of set up by whoever wanted to do it.

The first solution was detecting if we were running through the file:// protocol in the specRunner, and not turning on blanket if we are. To do this, I created a boolean called onServer and put all of our Blanket modifications inside if statements on this boolean. In the case of adding blanket to the array of required modules this meant taking it out of the initialization and adding this line:

if (onServer) {
	requiredModules.push('blanket');
}

Then, to detect if we were on a server I used this code

var phantom = navigator.userAgent.indexOf('Phantom') !== -1 ? true : false,
http = document.location.protocol === 'http:' ? true : false,
onServer = (phantom || http);

Since we run our tests in Phantom, which uses the file:// protocol without complaining about cross domain calls I’ve got an extra bit detecting if we’re in Phantom. Now, if we can handle it our tests run Blanket, otherwise they run fine without. Lovely.

The other solution was sorting out an easy local server for running our tests on. I can’t really take too much credit for this, because it’s blanket’s own recommendation. Blanket provides a simple node server, download that and put it somewhere that it doesn’t need to go up a level in the file structure to reach your jasmine tests.

If you don’t have node installed then what are you doing? Install node (and grunt while you’re at it.

In the command line navigate to the folder you’re keeping this test server in and type npm install express. This installs a plugin used by this server. Still in the command line, type node testserver.js which will start your server running. Finally, in a browser navigate to localhost:3000/path/to/your/specRunner.html

Tah-dah. Jasmine-Require-Blanket.

Advertisements
Tagged , , , , , ,

Testing require Main files with Jasmine

So last week I spoke about testing require modules with jasmine. The problem with this approach is it can’t be used on the main files. This is for a couple of reasons.

Main files do not define themselves as modules and as such aren’t really equipped to be loaded in through a require call like the rest of our modules. Also, the main files are where we bind everything to on page load. This means that to test these modules we need to simulate a page load event.

A couple of weeks ago we resigned ourselves to not testing these because the functionality is pretty basic, all there is to test in ours at least is that the relevant script has been triggered. But then I found myself with an afternoon to spare and used it to come up with this. It’s imperfect and dirty, but it’s better than doing nothing.

At the top of a main test, in place of the require call most modules get, we need to mock any scripts being loaded into the main file. For most scripts this is just a case of creating an object with functions inside them for what is being called by the main file. It doesn’t matter what these functions do, we’re not testing them here. This is just so there is something to be called. Like this:
var FirstPageScript = {init: function(){}}

The exception to this is whatever is being used for the domReady event. We’re using the require domReady plugin for mobile and jQuery for desktop. We need to replace whichever is being used with something that instead binds what we want happening on page load to a triggerable event. For jQuery:

var fakeJQuery = function(func){
	bodyTag.bind('domReady', function(){
	    func();
	});
}

You’ll note that this only mocks out the $() shorthand for $(document).ready() and no other jQuery functions. This might be a problem if we used jQuery for anything other than domReady in the main file, but we don’t. If we did It would be necessary to mock out other functions, but main files should be lightweight anyway.

This is almost the same but less problematic with the domReady plugin. It only does one thing, so just mocking that thing does the business.

var fakeDomReady = function(func){
        bodyTag.bind('domReady', function(){
            func();
        });
    }

Let’s take a quick look at what this is doing. When this mock domReady function is called, it binds the function that was passed to it to the 'domReady' event being triggered on the body tag. It’s irrelevant what this is called or even what it’s bound to. I used the body tag because I already had it in variable, and it could just as well be called 'ponyAttack'. All it is is an event we can trigger at will. So in this case, bodyTag.trigger('domReady'); will fire whatever is supposed to happen at domReady.

So we’ve now got everything we need mocked, we just need to insert these mocks into the main file in place of the real things. The answer is spies. With Jasmine, the answer is always spies. Spies are awesome.

By creating a spy on the require function which calls a fake function that triggers the function passed into the require call with our mocks instead of the intended objects, we can do this. That make sense? No? Ok. Let’s look at some code.

requireSpy = spyOn(window, 'require').andCallFake(function(){
    requireSpy.mostRecentCall.args[1](fakeDomReady, FirstPageScript, SecondPageScript, ThirdPageScript);
});

requireSpy.mostRecentCall.args is an array containing the arguments passed into the most recent call to the spied on function. The first argument is the array of required modules, the second is the function being triggered. Therefore requireSpy.mostRecentCall.args[1] refers to the function that the require call was going to trigger. We’re then passing into this call all of our mocks, in the same order that they are expected in the main file. Now, when require is called, we will instead trigger the main file’s function but using mocks.

Finally we need to trigger the require call. We can’t load the main file in alongside the rest of our scripts. Apart from anything else, we can’t load it until after our requireSpy has been created or it won’t work. That means we need to load the file here.

I am doing this by appending and removing a script tag pointing at the main file. I see no reason why you couldn’t use a jQuery load, but I didn’t.

$('head').append('');

Then for neatness’ sake, I added an afterEach for removing this tag

afterEach(function(){
   $('#mobileMainScriptTag').remove();
});

So, putting all this together we get the full set up for a main test:

describe('mobileMain.js', function(){
	var FirstPageScript = {init: function(){}},
	    SecondPageScript = {init: function(){}},
	    ThirdPageScript = {init: function(){}},
	    bodyTag = $('body');
	beforeEach(function(){
	    var fakeDomReady = function(func){
	            bodyTag.bind('domReady', function(){
	                func();
	            });
	        },
	        Browser = {getByTag: function(){ return bodyTag; }},
	        requireSpy = spyOn(window, 'require').andCallFake(function(){
	            requireSpy.mostRecentCall.args[1](fakeDomReady, FirstPageScript, SecondPageScript, ThirdPageScript);
	        });
	    $('head').append('');
	});

	afterEach(function(){
	   $('#mobileMainScriptTag').remove();
	});

This is a relatively complex main file because it’s filling the role of Backbone’s concept of a router, the others mostly just have jQuery and a single script mocked.

But the set up alone isn’t going to test anything, let’s quickly write some tests.

it('initializes the script', function(){
	spyOn(Script, 'init');
	bodyTag.trigger('domReady');
	expect(Script.init).toHaveBeenCalled();
});

That’s pretty much it. Because the example I’ve been using has a bit more going on, what with detecting what page we’re on that got to have a helper function for doing that set up. But it’s not all that interesting and is pretty specific to our needs so I’ll omit it at least for now.

So, that’s a dirty hack to test your main files. The approach has some down sides. We’re not actually testing that the correct script is being called, we’re testing that the object being passed into the require function in that order is called. It’s a pretty small risk though, and I can’t think of a way to check that without straying away from unit testing and into integration testing.

It is also impossible to run the test using the file:// protocol, which is annoying but I’m increasingly finding the advantages of being able to run the tests that easily are being outweighed by being able to do more stuff by running them on a local server.

The most unfortunate thing about this though is that loading in the files like this means that they are not picked up by blanket‘s coverage report. This is a shame because it was blanket that originally prompted me to start trying again to get these files tested., but hey-ho.

Speaking of Blanket, I’ve not spoken about Blanket before. It’s pretty incredible. I’m pretty sure it’s the work of at least one wizard. I’ll talk about it next time.

Tagged , , , , , ,

Using Jasmine with Require

Last week I spoke about the basic use of Jasmine, a JavaScript testing framework. The problem presented to us by using Jasmine was that it is not currently designed to work with RequireJs. This meant we had to find a way to get them to play nicely together.

Most of the work for this I stole from Ben Nadel and Uzi Kilon but I did find I needed and wanted to make some minor changes to the code to make it work as I liked.

The fundamental problem is that require needs you to load in any used files through a call to the require function, and needs all the code to be kicked off by the main file. Require, on the other hand, expects all the files, specs and source, to be loaded in with script tags. These two approaches are not one and the same.

To get around this, first I needed to replace the main file from our actual code with some code for setting up and triggering the Jasmine tests. This Spec runner takes out the inline code from the html file and is therefore responsible for setting up any config, loading in the core libraries needed throughout the tests, loading in the tests and launching Jasmine.

Setting up config

Let’s look at this in order then, the first thing we do is load in the Require Config from our real code. Because our tests are kept a few folders away from our production code, this isn’t massively pretty but otherwise it’s the same as our regular main files:
require(['../../../main/web/js/mobile/mobileRequireConfig.js'], function(){

Then I needed to set up variables to link back to the files in the Jasmine folder since we are setting the base url to be inside the source folder. They’re a bit dirty, but they work:

    var jasmineFolder = "../../../test/javascript/jasmine/",
        specsFolder = jasmineFolder + 'mobileSpecs/';

When appended to the front of urls for files they guide us back to the jasmine folders. This means that all of the dirty business of keeping tests separate from source is dealt with here rather than impacting the production code.

Although the regular config isn’t quite perfect for us, becuase we need to replace some settings and add a few too. We do this quite simply with a call to require.config:

  require.config({
    baseUrl: "../../../main/web/js/",
    urlArgs: "cb="+Math.random(),
    paths: {
        jasmine: jasmineFolder+'lib/jasmine-1.2.0/jasmine',
        jasmineHtml: jasmineFolder+'lib/jasmine-1.2.0/jasmine-html',
        jasmineHelper: jasmineFolder+'lib/jasmine-1.2.0/jasmine-helper',
        jasmineJquery: jasmineFolder+'lib/jasmine-jquery',
        jquery: 'lib/jquery'
    },
    shim: {
      jasmine: {
        exports: 'jasmine'
      },
      jasmineHtml: ['jasmine'],
      jasmineHelper: ['jasmine'],      
      jasmineJquery: ['jasmine'],
      jquery: {
          exports: '$'
      }
    }
  });

Overwriting options like baseUrl is as easy as resetting them, because the loaded in config is processed first the config set here overrides it. However, we also need to set up some new options as well. We need to overwrite the baseUrl because it is set up relative to the html file, which is a long way from here. This is the last bit of dirtiness needed to get this all working beautifully.

urlArgs isn’t important, but by adding a random number to them we prevent files from being cached, which is just convenience. We’re also adding all the components of Jasmine to the paths and shimming it so that it can be loaded with Require.

Loading Jasmine files

Loading in the core libraries and the specs requires a nested pair of require calls. The first layer loads in the core libraries and initializes Jasmine. The second layer loads in the specs and triggers Jasmine’s execute function. Let’s take a look:

var requiredModules = [
     'jquery',
     'jasmine',
     'jasmineHtml',
     'jasmineHelper',
     'jasmineJquery'
 ];

require(requiredModules, function(){
	var jasmineEnv = jasmine.getEnv();
	jasmineEnv.updateInterval = 1000;

	var htmlReporter = new jasmine.HtmlReporter();

	jasmineEnv.addReporter(htmlReporter);

	jasmineEnv.specFilter = function(spec) {
	  return htmlReporter.specFilter(spec);
	};
	var specs = [
	    specsFolder+'myFile',
	    specsFolder+'mySpec',
	    specsFolder+'yourSpec'
	];

	require(specs, function(){
		jasmineEnv.execute();
	});

});

I have set up the list of required modules in both cases before the require call because it makes it easier to add or remove modules depending on if you’re running the tests on a server or not, which will become significant when I talk about Blanket.js. It’s not necessary, you could put those arrays straight into the require calls if you like.

Setting up a Spec

With the main file replaced I then needed each indvidual test suite have access to the modules it was testing. This involves putting a beforeEach at the top of every spec file requiring in the desired files for the test:

describe('myfile.js', function(){
	var Utils;
	beforeEach(function(){
		var flag = false;
		require(['Utils'], function(_Utils){
			Utils =  _Utils;
			flag = true;
		});

		waitsFor(function(){
			return flag;
		});

	});

...some specs...
});

Let’s pick this apart a bit. The whole test is inside a describe call. At the top of this any variables to be defined by the require call are instantiated so that all the specs have the necessary scope.

Then, inside a beforeEach we create a variable equal to false which only becomes inside the require block. This means that this will only become true once all the required modules are loaded and their variables initialized.

The waitsFor function means that this beforeEach is not considered complete until that flag becomes true, so no test will run until the modules have been loaded.

Finally, loading in the modules is done with a regular require call. You may notice that the variable being brought into the require function is _Utils when we intend to be referring to it throughout the suite as Utils. This is to avoid naming conflicts between the variable local to the require call and the variable for the whole suite.

Just to finish off let’s have a quick look at the html used to launch all this off. All it does it loads in the Jasmine CSS and favicon. Then loads require with the specRunner javascript file we just set up as its main file. This is all inside the head of the file, with a completely empty body tag.

<title>Mobile Spec Runner</title>

<link rel=”shortcut icon” type=”image/png” href=”libs/jasmine-1.2.0/jasmine_favicon.png”>
<link rel=”stylesheet” type=”text/css” href=”lib/jasmine-1.2.0/jasmine.css”>
<script type=”text/javascript” src=”../../../main/web/js/lib/require.js” data-main=”mobileSpecRunner”></script>

 

Et voila, a require-friendly suite of Jasmine tests. We’ve divided our specs into three spec runners: mobile, desktop, and shared. This is to accommodate the fact that we have a separate requireConfig for desktop and mobile. You could do more or less as you like really.

Those of you paying altogether too much attention may have noticed that this means that our main files are being untested. I couldn’t find a neat way around that problem, but I have found a way. Of sorts. Which I’ll talk about next time.

Tagged , , , ,

Using Backbone with Require

So we’ve done Backbone, we’ve done Require. Let’s put them together. Previously we wrote a pointless little Backbone app. Now, we’re going to Require-ify it.

Require.js is, as you know, all about modularisation. Fortunately, Backbone makes it pretty obvious what makes up a Module. Is it a distinct Backbone entity? A Model, a Collection or a View? Boom. It’s a module.

So with the difficult decision making done, let’s look at how we’d do this.

Starting from the beginning, our require config. You might recognise this from my original require post. That is because I am lazy.

File: js/requireConfig.js

require.config({
	paths: {
		//libraries
		jquery: 'libs/jquery',
		underscore: 'libs/underscore',
		backbone: 'libs/backbone',

		//scripts
		developerModel: 'models/DeveloperModel',
		developerCollection: 'collections/DeveloperCollection',
		developerListView: 'views/DevelopersListView'
	},
	shim: {
		jquery: {
			exports: "$"
		},
		underscore: {
			exports: "_"
		},
		backbone: {
			deps: ['underscore', 'jquery'],
			exports: "Backbone"
		}
	}
});

File: js/index.main.js

require(['requireConfig'], function(){
	require(['developerListView'], function(DeveloperListView){
		var myView = new DeveloperListView();
	});
});

File: index.html

<!DOCTYPE html>
<html lang="en">
	<head>
		<meta charset="utf-8" />
		<title>One Page Web App</title>

	</head>
	<body>
		<section id="content">
			<h1>Really Useful Dev List App</h1>
			<input type="text" id="name"></input>
			<input type="radio" name="role" id="isUx">UX</input>
			<input type="radio" name="role" id="isDev">Dev</input>
			<button id='add'>Add List item</button>
			<ul></ul>
		</section>

		<script src="js/libs/require.js" data-main="js/index.main">
	</body>
</html>

This is the same html as my Backbone post but with a require script tag instead of an ordinary one.

Right, that’s all the essentially unchanged stuff out the way. Now let’s look at the MOSTLY unchanged stuff. After that we will have run out of stuff.

filename: js/models/DeveloperModel.js

define([
	'underscore',
	'backbone'
], function(_, Backbone){
	var Developer = Backbone.Model.extend({
		defaults: {
			name: 'A Dev'
		}
	});

	return Developer;
});

This is the Model from our earlier Backbone app. It is now a file in its own right wrapped in a define block. It has its dependencies, Backbone and Underscore defined and then establishes a function that creates the concept of a Developer Model and returns it. Note, it is not returning “A developer” it is returning the Developer Model, which can be instantiated as needed.

filename: js/collections/DeveloperCollection

define([
	'underscore',
	'backbone',
	'developerModel'
], function(_, Backbone, Developer){
	var DeveloperCollection = Backbone.Collection.extend({
		model: Developer
	});

	return DeveloperCollection;
});

This is our collection. Again, it returns the idea of a collection of developers, not an actual collection of developers. It may well be possible to remove the dependency on the Developer model by passing it into any calls to the DeveloperModel. I’ll be exploring this and if it turns out to be a good idea and possible, I’ll talk about it.

Finally, our View. For the sake of avoiding this post becoming any more massive than it already is, I’ve snipped out all the logic inside the View, if you want to see it check out my Backbone post. Doing my bit to save your monitor’s ink reservoir.

define([
	'jquery',
	'underscore',
	'backbone',
	'developerCollection',
], function($, _, Backbone, DeveloperCollection){
	var DevelopersListView = Backbone.View.extend({
		...
	});

	return DevelopersListView;
});

On a sidenote, when I wrote this I gave the path names in RequireConfig camel-cased names, starting on lowercase letters but decided to follow the convention of having anything imported into a file start with a capital letter. This was annoying. Don’t do that. Although I am fond of the capital letters for imported objects though. I recommend that.

That’s it, we now have a pointless little Backbone and Require app.

Tagged , , , , ,

Setting up Require.js

So last week I went into why we’re using Require.js, yesterday I did the core concepts of Require. Today I’m going to cover how to use it in a project. It will be almost laughably short. I am by no means an advanced user at this point, I have read a lot about Require and done some small demo projects. I haven’t yet used it to do anything one could describe as complex. This means what follows is Require 101, nothing more.

Getting started with Require

You may be used to loading all your JavaScript with a chain of script tags in your html. You may bundle it all up into one file and use a single script tag. Either way, with require it is different.


<script type="text/javascript" src="path/to/require.js" data-main="ponies.js"></script>

Obviously, ponies.js could be called anything. In fact, I really wouldn’t recommend calling it ponies. If you’re going to make a one-page app then you could do worse than just calling it main.js. We’re planning to have a multi-page application and so calling it main would just get confusing. Instead we’re planning to go for the naming convention of pagename.main.js for our Main files.

So, that’s it for JavaScript imports. Let’s take a look inside main.js

require.config({
	paths: {
		//libraries
		jquery: 'libs/jquery',
		underscore: 'libs/underscore',
		backbone: 'libs/backbone',

		//scripts
		developerModel: 'models/DeveloperModel',
		developerCollection: 'collections/DeveloperCollection',
		developerListView: 'views/DevelopersListView',
		developerItemView: 'views/DeveloperItemView'
	},
	shim: {
		jquery: {
			exports: "$"
		},
		underscore: {
			exports: "_"
		},
		backbone: {
			deps: ['underscore', 'jquery'],
			exports: "Backbone"
		}
	}
});

require(['developerListView'], function($, _, Backbone, DeveloperListView){
	var myView = new DeveloperListView();
});

This file can comfortably be divided into two parts, the config and the function. The config can be split out from the file so that it is reusable between main files. This is also valuable for the optimiser and testing in the future.

Splitting it out looks a bit strange because you use a require call to load in Require’s config. That wrinkles my brain, but it works and looks like this:

require(['requireConfig'], function(){
	require(['developerListView'], function($, _, Backbone, DeveloperListView){
		var myView = new DeveloperListView();
	});
});

The thing to note here is that without the require config, it’s not possible to define paths by name so you’ve got to use the full path to your config file here.

This function is the start point for your page’s JavaScript, so from here you kick everything you want to run off. Require will do all the clever business of loading in your dependencies, so you just need to list ’em and use ’em.

Now let’s take a look at the config file we pulled out.

require.config({
	paths: {
		//libraries
		jquery: 'libs/jquery',
		underscore: 'libs/underscore',
		backbone: 'libs/backbone',

		//scripts
		developerModel: 'models/DeveloperModel',
		developerCollection: 'collections/DeveloperCollection',
		developerListView: 'views/DevelopersListView',
		developerItemView: 'views/DeveloperItemView'
	},
	shim: {
		jquery: {
			exports: "$"
		},
		underscore: {
			exports: "_"
		},
		backbone: {
			deps: ['underscore', 'jquery'],
			exports: "Backbone"
		}
	}
});

There are two things going on here. The first part is setting up paths to use throughout my app. Essentially I am creating variables to hold the filepaths I am using. This isn’t necessary, but it makes it easier to write and maintain because I can change my file structure and change the references in one place. Plus, I don’t need to remember where everything is. I hate remembering things.

The second thing is the shim. This is a fix for libraries that are not compliant with the AMD API. Here we are defining global versions of these libraries so that they can act in a way that they are used to, however in the app proper we will still be using local versions so that the whole thing remains coherent and managable. This is just a way to make these libraries behave themselves. I’ve since come to a better understanding of what Shim does thanks to this post from Require.js developer James Burke. A require Module tells Require itself what its dependencies are when it is defined, Shim is a way to tell require what the dependencies of a file are if the file itself doesn’t decalre its dependencies to require. It does not do anything that affects the world outside of require, most notably, shimming something does not cause it to be downloaded.

And that’s it, Require is set up. Just use the main function to run everything you want to on your page. Easy as microwavable pie.

Tagged , , , ,

Using Require.js

So, last week I covered why we’re using Require.js. Today, let’s look at how to use it. This time I’m just going to go into the two functions that are the heart of Require, then next time I’ll go for how to actually put it into your app.

Require()

require(["some", "dependencies"], function(){Console.log("A function")})
The require function takes two parameters. An array of strings, referencing all of the functions dependencies and a function which is run.

What this does is informs the app that in order to run that function, it must have these dependencies loaded. So it will make sure it has them all available before starting to run the function. The array of strings, which must always be an array even if it’s an array of one, can contain either full file paths or references defined by Require.

References defined by Require, what do you mean? I hear you cry, melodramatically. There are two things this can mean, one is names for file paths that can be defined by your Require config. We’ll cover that tomorrow. The other is functions defined with the define function.

Define()

define("myModule", ["some", "dependencies"], function(){Console.log("A function")})

Define is used to define modules that you intend to call again later. The first parameter is optional and is a single String that is your module’s name, to make it easier to call again later. After that, it looks just like a require function.

So, when do you use which? If you want to run a function but make explicit its dependencies, then use require. If you want to create a module that will be called by another function, then use define.

Tomorrow, putting this into practice.

Tagged , , , ,
Advertisements