On Github pascalpp / testing-with-karma-webpack
Our test runner
Our module bundler / compiler
Our testing framework
Testing the individual parts of a feature, separately from each other. This is the focus of this talk.
Testing collections of units working together.Testing whole UI flows, including multiple screens.
main/
  client/
    src/
      index.js
    test/
      tests.js
      tests/
    package.json
    bower.json
    webpack.config.js
    karma.conf.js
    config/
cd client npm install bower install npm install -g karma-cli webpack
karma start
karma start --single-run
KARMA_BROWSERS=Chrome,Safari karma start
NODE_ENV=production karma start
A few thoughts…
Instead, listen for changes in those objects inside your module
Avoid using AboutMe.on, when, trigger, request, execute
describe('module/foo/foo_view', function() {
    // define vars used throughout your suite
    var FooView
    var foo_view
    var node
    var region
    // don't perform any logic directly in your describes
    // use before and after
    before(function() {
        require('mocks/globals') // sets up a mock globals json glob
        FooView = require('module/foo/foo_view')
        node = $('<div />').appendTo('body')
        region = new Marionette.Region({ el: node })
    })
    after(function() {
        region.destroy()
        node.remove()
    })
    // create a fresh foo_view for each test
    beforeEach(function() {
        foo_view = new FooView()
        region.show(foo_view)
    })
    // describe each part of your view or object
    // write pending tests first
    // using it('should do something') with no callback
    // implement the test callback later
    describe('#ui', function() {
        describe('#headline', function() {
            it('should exist')
        })
        describe('#button', function() {
            it('should exist')
        })
    })
    describe('#someMethod', function() {
        it('should do something')
        it('should not do something')
    })
})
expect and should
var chai = require('chai')
var expect = chai.expect
chai.should()
describe('#ui', function() {
    describe('#headline', function() {
        it('should exist', function() {
            expect(foo_view.ui.headline).to.exist
        })
    })
    describe('#button', function() {
        it('should exist', function() {
            foo_view.ui.button.should.exist
        })
    })
})
Replace a function with sinon.stub
sinon.stub(SomeObject, 'someMethod')
Attach a rider with sinon.spy, allows the original function to run
sinon.spy(SomeObject, 'someMethod')
Don't forget to restore when you’re done
SomeObject.someMethod.restore()
var sinon = require('sinon');
describe('MyObject', function() {
    describe('#myMethod', function() {
        beforeEach(function() {
            sinon.stub(OtherObject, 'otherMethod')
        })
        afterEach(function() {
            Object.otherMethod.restore()
        })
        it('should call OtherObject.otherMethod', function() {
            MyObject.myMethod()
            OtherObject.otherMethod.calledOnce.should.be.true
        })
    })
})
Haven’t used this myself yet, but:
require('jquery.ajaxmock')
$.ajaxMock.register('/n/3/internal/url_exists', {
    responseText: '{ exists: true }',
    statusCode: 200,
    status: 'OK',
    type: 'POST', // optional, default: 'GET'
    delay: 1000 // optional
})
Write your test in a location similar to the src file being tested
/client/src/module/mymodule/mymodule.js /client/test/tests/module/mymodule.test.js
Require your test in client/test/tests.js
require('./tests/module/mymodule.test.js')
Comment out other tests to see if your test runs independently
Don’t commit with other tests disabled!
require('module/compliment_modal/compliment_modal');
var MyView = Marionette.LayoutView.extend({
    someMethod: function() {
        AboutMe.trigger('user:compliment:ui');
    }
});
var MyView = Marionette.LayoutView.extend({
    someMethod: function() {
        require.ensure([], function() {
            require('module/compliment_modal/compliment_modal');
            AboutMe.trigger('user:compliment:ui');
        })
    }
});
Now we can test our view without loading compliment_modaland all of its dependencies.
globals (required by lib/log, which is required all over the place)
require('mocks/globals')
other dom json (required by lib/analytics, for example)
var insertDomJson = require('mocks/insert_dom_json')
insertDomJson({}, 'json analytics')
Sometimes you just can’t test a unit outside the app context. Too many dependencies to untangle, maybe now isn’t the time to untangle them.
before(function() {
    var MockAboutMe = require('mocks/aboutme')
    var app = MockAboutMe.setup()
    app.start()
})
after(function() {
    MockAboutMe.teardown()
})