Skip to content

Instantly share code, notes, and snippets.

@sukhmeet2390
Last active August 29, 2015 14:21
Show Gist options
  • Save sukhmeet2390/94cf57767b32917b5445 to your computer and use it in GitHub Desktop.
Save sukhmeet2390/94cf57767b32917b5445 to your computer and use it in GitHub Desktop.
Working around with Yeoman , RequireJS, Mocha, Chai, Squire and Sinon

Yeoman is awesome, . RequireJS is super cool. Both don't glue together, atleast not officially.There is no official support for RequireJS from yeoman team.

Here is guide on what i did to work around with things to get it working .

Gluing them together

  • get the dependency

    bower install requirejs --save

  • add script tag for require js in index.html and it should look like this

    <script src="bower_components/sass-bootstrap/js/tab.js"></script> <script src="bower_components/requirejs/require.js"></script>
      <script src="scripts/main.js"></script>
    

Sample main.js with exported deps

require.config({
paths:{
	'jquery':'../../bower_components/jquery/dist/jquery',
    'text':'../../bower_components/text/text',
	'scripts':'../scripts'
  },
 shim:{
	'jquery':{
      deps:[],
      exports:'$'
	}
	}
});
  • Set up grunt file
  1. install dependency
    npm install grunt-requirejs --save

  2. load the task
    grunt.loadNpmTasks('grunt-requirejs')

  3. set up task

    requirejs: { dist: { options: { baseUrl : '<%= config.app %>/scripts/', name : 'main', mainConfigFile : '<%= config.app %>/scripts/main.js', out : '.tmp/concat/scripts/main.js' } } },

  4. add to build task the above configured task

    grunt.registerTask('build', [ 'clean:dist', 'useminPrepare', 'concurrent:dist', 'autoprefixer', 'concat', 'requirejs:dist', ===> New 'cssmin', 'uglify', 'copy:dist', 'rev', 'usemin', 'htmlmin' ]);

Thats it , now running task grunt serve should work like a charm .Build will create a file in /dist/scripts/****.main.js

Setting up tests

Next task is to setup tests configuration . Grunt task for testing from yeoman runs the specs in a different local server .Keep that in mind as app/ folder is not directly accessible. We might need to have some path setting to enable this. But lets take baby steps in here
To get it working with requirejs

  1. add requirejs from bower with data-main to a runner file

    <script data-main="spec/runner" src="bower_components/requirejs/require.js"></script>
  2. remove mocha.run () from the script tag. We will call it after loading our spec file in our runner.js file

Sample runner.js might look something similar to

require.config({
  paths:{
	'jquery':'../bower_components/jquery/dist/jquery',
    'underscore':'../bower_components/underscore/underscore',
	'text':'../bower_components/text/text',
    'scripts': '/app/scripts'
  },
  shim:{
	'jquery':{
      exports:'$'
	},
	'underscore':{
  	exports:'_'
	}
  }
});

var specs = [  // add all the spec files here
	"User.spec",
];
require(specs, function(){
  mocha.run();
});
  1. Set up Gruntfile for testing , since app/ folder is not directly available for testing i had to change a bit to update my testing config to this

    test:{ options:{ open:true, port:9001, middleware:function (connect) { return [ connect.static('.tmp'), connect.static('test'), connect().use('/app', connect.static(config.app)), //connect.static(config.app), // either should work connect().use('/bower_components', connect.static('./bower_components')) ]; } } }

Thats it for setting up with requirejs for testing purpose. But we are not done yet.

Dependency Management

Since we are using requireJS for modularize our code and trying to follow MV* pattern in the code, this will lead to having one module having some dependencies on other modules.
For eg : we need jQuery, underscore , widgets in our module controller.
How to handle this . For doing this we need a dependency injection mechanism.

Squire is a dependency injector to use with Require.js to make mocking dependency easy. How awesome !!!
About its usage, in the spec file get Squire, (we already have the path in configured in require.config)

define(['Squire'], function(Squire) {
	var injector = new Squire();
});

and now mock the dependency it needs.

injector.mock('my_dependency', {
	awesomeFunction: {return 0;}
}

and now when unit testing the file Squire will trick that "Hey ! u need a dependency 'X' , take this mock 'Y' instead and assume this is 'X' "
Now do

injector.require(['testingThisModule'],funciton(module){
	decribe("Testing a module", function(){
		beforeEach(){ ... do something ...}
		afterEach(){ ... do whatever ... }
		it("test function1", function(){
			... module is available here....
			... and dependency is mocked as well ... 
		})
	})
});

Ideally this should get all the working. But this wasn't working for me .
Spending hours figuring it out finally got to use mocha async calls hack to load my file and then keep referencing it . Might not be the right way to do it. But kept me going.
For Async mocha takes an extra param done which can be called when async call is done.

describe("Module", function(){
	before(function(done){
    	injector.require(['scripts/Model/Module'], function(ModuleClass){
          Module = ModuleClass;
	      done();
    	});
      });
	  after(function(){
    	injector.remove();
      });
	it("gets me a random number" , function(){
		....  refer using Module here ....
	});

Though Squire.js is great in itself. But its true capability is in doing dependency injection. For mocking , there is also another good library called Sinon There are a lot of useful calls that sinon provides you with for example faketimers , fakeXHR, fakeServer which I found quite useful.
Hope it helps

Phew

Extra links
Seeting up requireJS with Yeoman
Mocking AMD Modules with Squire
Dependency injection with Squire and Sinon
What is test

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment