34

I am trying to create a simple unit test that tests my show function.

I get the following error:

TypeError: Object #<Object> has no method 'show'

It seems like $rootScope isn't the scope of the controller?

Here's my controller:

function OpponentsCtrl($scope, $location) {
    $scope.show = function(url) {
        $location.path(url);
    }
}
OpponentsCtrl.$inject = ['$scope', '$location'];

Here's my controller unit test:

describe('OpponentsCtrl', function() {
    beforeEach(module(function($provide) {
        $provide.factory('OpponentsCtrl', function($location){
            // whatever it does...
        });
    }));

    it('should change location when setting it via show function', inject(function($location, $rootScope, OpponentsCtrl) {
        $location.path('/new/path');
        $rootScope.$apply();
        expect($location.path()).toBe('/new/path');

        $rootScope.show('/test');
        expect($location.path()).toBe('/test');
    }));
});
1
  • 1
    "Unit test" is two words, just wanted to point it out. Glad you found a solution. Commented Dec 2, 2012 at 4:20

3 Answers 3

65

This is how my test ended up working.

describe('OpponentsCtrl', function() {
    var scope, rootScope, ctrl, location;

    beforeEach(inject(function($location, $rootScope, $controller) {
        location = $location;
        rootScope = $rootScope;
        scope = $rootScope.$new();
        ctrl = $controller(OpponentsCtrl, {$scope: scope});
    }));

    it('should change location when setting it via show function', function() {
        location.path('/new/path');
        rootScope.$apply();
        expect(location.path()).toBe('/new/path');

        // test whatever the service should do...
        scope.show('/test');
        expect(location.path()).toBe('/test');

    });
});
Sign up to request clarification or add additional context in comments.

4 Comments

By the way, you can feel free to accept your own answer. It looks like, to date, it has helped 20 people :-).
don't you have to mock $httpBackend? i get "Error: Unexpected request: GET No more request expected". I need to mock it.
I second mgilson -- accept this one as the correct answer. After a thorough search, this is what made it work for me! Lots of thanks!
You really should accept as the correct answer, it helped me a lot.
20

Why don't you simply use a spyOn function?

describe('OpponentsCtrl', function() {

    var location;

    beforeEach(module(function($provide) {
        $provide.factory('OpponentsCtrl', function($location){
            location = $location;
        });
    }));

    it('should change location when setting it via show function', inject(function() {    
        spyOn(location, 'path');    
        expect(location.path).toHaveBeenCalledWith('/new/path');
    }));
});

Hope this helps!

2 Comments

Why do you have the inject in the test if you aren't using it? I assume this is just left over from when you did?
@Katana24, I have removed the inject. Please peer review the changes if you like.
3

I prefer to mock location and services as then it's a unit (not integration) test:

'use strict';
describe('flightController', function () {
  var scope;
  var searchService;
  var location;

  beforeEach(module('app'));
  beforeEach(inject(function ($controller, $rootScope) {
    scope = $rootScope.$new();
    mockSearchService();
    mockLocation();
    createController($controller);
  }));

  it('changes location to month page', function () {
    searchService.flightToUrl.and.returnValue('Spain/Ukraine/December/1');
    scope.showMonth();
    expect(location.url).toHaveBeenCalledWith('search/month/Spain/Ukraine/December/1');
  });

  function mockSearchService() {
    searchService = jasmine.createSpyObj('searchService', ['flightToUrl']);
  }

  function mockLocation() {
    location = jasmine.createSpyObj('location', ['url']);
  }

  function createController($controller) {
    $controller('flightController', {
      $scope: scope,
      searchService: searchService,
      $location: location
    });
  }
});

Cheers

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.