Unit Test AngularJS controller with a resource that uses $routeParams

Note: I'm writing everything in CoffeeScript

I have a controller as follows:

angular.module('myApp').controller 'MyController', ($scope, $routeParams, Batch) ->
    $scope.$on '$routeChangeSuccess', () ->
        Batch.get {batchUuid: $routeParams.batchUuid}, (response) ->
            $scope.batch_id = response.id

The controller pulls in the Batch resource which is defined as follows:

angular.module('myApp').factory 'Batch', ($resource) ->
    $resource '/batches/:batchUuid', {}

I have a route for this as follows:

$routeProvider.when('/batches/:batchUuid',
    { templateUrl: 'batches-processing.html', controller: 'MyController' })

So:

  • You visit the route /batches/22
  • It uses MyController
  • It triggers $routeChangeSuccess
  • It calls get on the Batch resource witch the batchUuid from the route
  • It gets back a json response and assigns an id to $scope.batch_id

Now I want to test this so I have a unit test as follows:

describe 'Controllers', ->
    beforeEach module 'myApp'
        describe 'MyController', ->
            scope = {}
            ctrl= {}

            beforeEach inject ($rootScope, $controller, Batch, $httpBackend) ->
                scope = $rootScope.$new()
                ctrl = $controller('MyController', ($scope: scope))
                #I imagine I need to use either my injected Batch resource or the httpBackend to fake/expect the ajax call here

            it "Gets data from the resource and assigns it to scope", () ->
                #How on earth do I test this

I have seen people using $httpBackend.expect('/endpoint.json').respond({id:1}) etc but I can't do that. My resource URL relies on a batchUuid from the route. How can I simulate/fake/implement a test that will simulate a route change, trigger the $routeChangeSuccess, pass a routeParameter to the resource, do a get on the resource and test the result?

I'm pulling my hair out over this and angular docs don't seem to cover it.

Thanks!

You can make a fake routeParams and inject it into your controller.

I use jasmine's createSpy for my fakes, but that might be a bit overkill. There's an example here that shows how to create and inject the fake routeParams.

This js fiddle shows routeParams being injected:

http://jsfiddle.net/rimian/wgctykea/

it('should take articleId as id if specified', inject(function ($controller) {
  routeParams.articleId = 5;

  ctrl = $controller('MyAppCtrl', {
    $scope: scope,
    $routeParams: routeParams
  });

  expect(scope.id).toEqual(5);
}));