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 , , , , , ,

2 thoughts on “Using Blanket with Jasmine and Require

  1. Alex Seville says:

    A simpler way to deal with the requirejs/blanket compatibility is to simple add a script tag for blanket directly under the requirejs script tag.
    In that way blanket remains more independent of your test runner.
    Here’s an example: https://github.com/alex-seville/blanket/blob/master/test/jasmine-requirejs/runner.html

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: