Jasmine / Karma / RequireJS Template

VNGRS
VNGRS
Apr 21, 2015 · 4 min read

I was playing around with Jasmine for a project. All basic setup and defining tests are as easy as Mocha and are relatively easy compared to QUnit. I needed a structure that could load dependencies, write specs with Jasmine, run specs in the development environment (also found out that I can use different JavaScript engines to run my specs simultaneously), and run specs in a continuous integration environment.

So I’ve created this template to provide a boilerplate. Which was needed in my opinion because there are a lot of not working, not documented or simply bad examples out there.

Template is here https://github.com/vngrs/jasmine-requirejs-template

Setting Up the Base Project

mkdir test-project && cd test-project npm init npm install karma bower grunt --save-dev

Then Karma will create our base Jasmine — Karma setup.

./node_modules/karma/bin/karma init

PhantomJS (Choose only PhantomJS *(headless browser with JavaScriptCore, Ecma 5.1) if you’re planning to prepare this setup for a continuous integration environment)*

src/\*.js (you may use 'src/\*\*/\*.js' to recursively match files) spec/*.spec.js

no (again for CI purposes)

./node_modules/bower/bin/bower init # default answers should do.

And bower installs our assets.

./node_modules/bower/bin/bower install requirejs jquery mustache --save

Note the -save argument. This will make bower write installed modules to bower.json also.

Providing An Entry point

<pre class="wp-block-preformatted"><!-- /index.html -->
<html>
<head>
<title>jasmine-requirejs-template</title>
<script data-main="src/app.config.js" src="bower_components/requirejs/require.js"></script>
</head>
.
.
.
</pre>

Notice the data-main attribute. Requirejs is going to read this attribute and load the specified file after loading itself.

Requirejs Bootup File

I’m going to use a separate file to configure Requirejs and load it with nested require functions.

// src/app.config.js

// Using a common setup file for specs and sources
(function(){
require(['src/requirejs.config'], function(){
require(['moduleA'],function(a){
a.execute_a_cool_function();
});
});
})();
// src/requirejs.config.js

// This is a common config file for all our requirejs setups, we're going to
// use same file while running our specs in browser or in karma.
require.config({
paths: {
// assets installed with bower
jquery: 'bower_components/jquery/dist/jquery',
Mustache: 'bower_components/mustache/mustache',
// our modules
moduleA: 'src/moduleA',
moduleB: 'src/moduleB'
},
shim: {
Mustache: { exports: 'Mustache' }
}
});

Important variables in requirejs config baseUrl

This is for loader paths, you may either use blank or define as src/ and move everything under the src folder.

paths

If you’re defining paths for modules, this is the place. Defining jQuery for example;

'jquery': 'bower_components/jquery/dist/jquery'

shim

shim: Configure the dependencies, exports, and custom initialization for older, traditional “browser globals” scripts that do not use define() to declare the dependencies and set a module value.

For example, to use Mustache properly;

{
paths: {
'Mustache': 'bower_components/mustache/mustache',
},
shim: {
'Mustache': { exports: 'Mustache' }
}
}

Defining Modules and Dependencies

// src/moduleA.js
define(['dependency1','dependency2','etc..'], function(dep1, dep2){
});
// src/moduleB.js

define(['moduleA'], function(a){
function do_something(){}
function do_something_else(){}

// It's impossible to run specs on private methods, so you need to
// change your interface and export your private methods. But it's
// possible to remove these unwanted lines with grunt tasks while
// generating production ready assets.

return {
do_something: do_something,
do_something_else: do_something_else
}
});

Running the Local Development Server

./node_modules/grunt-cli/bin/grunt

Sample Spec Definition

This html file will load the Jasmine libraries and load our specs with Requirejs.

<pre class="wp-block-preformatted"><!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<link rel="stylesheet" type="text/css" href="bower_components/jasmine/lib/jasmine-core/jasmine.css">
<script type="text/javascript" src="bower_components/jasmine/lib/jasmine-core/jasmine.js"></script>
<script type="text/javascript" src="bower_components/jasmine/lib/jasmine-core/jasmine-html.js"></script>
<script type="text/javascript" src="bower_components/jasmine/lib/jasmine-core/boot.js"></script>
<!-- notice data-main attribute, specs/main is another requirejs boot file -->
<script type="text/javascript" data-main="specs/main" src="bower_components/requirejs/require.js"></script>
</head>
<body>
</body>
</html>
</pre>

We will use the same nested require approach to use the existing Requirejs config

// specs/main.js

(function () {
"use strict";

require.config({ baseUrl: '' });
// using same config file
require(['../src/requirejs.config'], function (){
require(["specs/moduleA.spec"], function () {
window.onload(); // Sadly this is a necessary trick to run jasmine specs.
});
});
})();

http://localhost:3000/run_specs.html opening this url in browser will give you test results.

Running Specs in CI

// /test-main.js(function () {
"use strict";
require(['/base/src/requirejs.config.js'],function(){
require.config({ baseUrl: '/base' });
var allTestFiles = [];
Object.keys(window.__karma__.files).forEach(function(file) {
if (file.match(/(.+)\.spec\.js$/)) {
allTestFiles.push(file);
}
});
require(allTestFiles, window.__karma__.start);
});
})();
# This will start and run your tests once, useful in CI environments
./node_modules/karma/bin/karma start
# This will start karma server and browsers
./node_modules/karma/bin/karma start --no-single-run &
# This will run your tests
./node_modules/karma/bin/karma run

Rıfat Çağrı Ekin

Originally published on April 21, 2015.

VNGRS

Globally Providing Digital Solutions Around Software Products

VNGRS

VNGRS provides digital solutions around software products to organizations in an ever-changing and unforeseeable environment while enabling them to figure out undiscovered digitalization needs, giving them a tailor-made digital solution that would boost their business.

VNGRS

Written by

VNGRS

Cloud Native Software Solutions

VNGRS

VNGRS provides digital solutions around software products to organizations in an ever-changing and unforeseeable environment while enabling them to figure out undiscovered digitalization needs, giving them a tailor-made digital solution that would boost their business.