Google Groups

Re: unit testing with angularjs


Pierre-Yves Gérardy Dec 12, 2012 6:38 AM
Posted in group: SocketStream
On Wednesday, December 12, 2012 4:37:52 AM UTC+1, Davis Ford wrote:
Each release of angular also releases angular-mock.js, so sure, you can use angular-mock.  But, if you want to use angular.mock.module and angular.mock.inject, support for mocha wasn't introduced until release 1.1.1.
What I meant was: use angular-mocj 1.1.1 with angular 1.0.x... But actually, module and inject aren't supported, even in that version. I managed to get it to work, though, at least in sync mode. Here's my setup:

In app.js, I create a separate app for the tests:

if (MODE == 'development') {
  ss.client.define('tests', {
    view: 'tests.html',
    css:  ['mocha.css'],
    code: ['libs', 'app', 'tests'],
    tmpl: '*'
  });

  ss.http.route('/tests', function(req, res){
    res.serveClient('tests');
  });
}

With this config, all files and folders in code/app are available for the tests, and the code/tests/entry.js overrides code/app/entry.js

tests:
+- entry.js
+- libs:
|  +- 128.expect.js
|  +- 256.mocha.js
|  +- 320.mocha.setup.bdd.js
|  +- 384.angular-mocks.js
+- specs:
   +- test.js
 
The angular/jQuery libs are loaded in code/libs, before code/tests/libs is loaded.

mocha.setup.bdd.js contains one line: mocha.setup('bdd'); This must be done before loading angular-mocks.

The view is pretty simple. Specifically:

[classic SS header.]
<body>
   <div id="mocha"></div>
</body>

For the controller, I inject the app rather than requiring it (a trick I've read on this list before):

code/app/controllers.js:
module.exports = funcfion(ngModule) {
    ngModule.controller(...)
}

It allows me to inject as many angular modules as I want during testing. 

code/app/entry.js
foo = angular.module('foo');
require('./controller')(foo);

code/tests/specs/test.js
var bar;
beforeEach(function(){
    bar = module('bar'+counter())
    require('../controllers')(bar)
})

code/tests/entry.js
$(function(){
  require('./specs/test')
  mocha.run();
})

At last, in order to get mock.module and .inject to work, you must change isSpecRunning in angular-mock.js, line 1624:

function isSpecRunning() {
    return currentSpec && currentSpec.queue && currentSpec.queue.running
        || currentSpec; // for Mocha.
}

I don't know how reliable the latter is, but it works for sync tests.


I'm also hitting this bug: https://github.com/angular/angular.js/issues/1674 which is something quirky between angular and jquery.  Works fine in 1.0.2,but post 1.0.3 it is a problem.

Anyway, I've spent a lot of time on this the last 2 days -- trying to devise the best testing strategy.  IMHO - both angular and browserify via socketstream are doing the same thing client-side..which is modularizing code.

So, the simplest thing is to just stop fighting it: use angular...carve out your client side code with vanilla self-executing functions that respect the global namespace and don't require('foo') files client side with angular code, b/c it is a nightmare to test (at least today).

This way, you can use standard tools -- and not have to rely on things like packing all the assets into a single minified / uglified js file that is a nightmare to debug, and which you have to rebuild each time you make a client code change.

I want to enable: 

a) edit client code || edit test code
b) save
c) auto-run tests on change - growl reporting pass/fail

That's just my personal preference...but none of this stuff is documented anywhere, so I just had to plow through it the hard way to figure out the best way forward for a real project that wants testing.  If I had more time, I'd carve out a blog post re: learnings here, but am short on time.  Happy to discuss it further if anyone wants to.


On Tue, Dec 11, 2012 at 6:57 PM, Pierre-Yves Gérardy <pyg...@gmail.com> wrote:
Isn't it possible to use the latest version of angular-mock with AngularJS 1.03? I've yet to test it, but the commit log looks innocuous: https://github.com/angular/angular.js/commits/master/src/ngMock

--