Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular JS - Testing a Function With a Page Redirect Using Karma / Jasmine

I have a function in my Angular controller that looks like the following:

$scope.myFunction = function(){
    $scope.myVariable = "something";
    $scope.myOtherVariable = "something else";
    window.location.href = "/path/to/page"; 
}

A simple Jasmine test covers the above function and looks like:

describe('my test', function(){
    it('should pass', function(){
        scope.myFunction();
        expect(scope.myVariable).toBe('something');
        expect(scope.myOtherVariable).toBe('something else');     
    });
});

The above test itself passes, but then Karma throws the following error in the console:

Some of your tests did a full page reload!

The page redirect is causing Karma to raise this warning. What's the best way to get around this?

I thought about giving both anonymous functions in the Jasmine test and Angular names and then using arguements.callee.caller.name inside the original function to determine whether the function is being called by itself or Jasmine. Unfortunately, arguments.callee.caller.name always returns undefined, which I suspect is caused by the way Angular and Jasmine are linked to each other.

like image 509
Lloyd Banks Avatar asked Mar 13 '14 20:03

Lloyd Banks


2 Answers

A long time since this question was asked, but the following approach should be cleaner:

By changing the original function to use Angular's $window service instead of the browser window object, it is possible to write a test that does not require modifying production code or take any runtime parameters into account. This of course requires that $window is a dependency for the controller where the function is found.

Using angular-mocks/ngMock, something like:

var fakeWindow = {
  location: {
    href: ''
  }
}
// instantiate controller with mock window
beforeEach(inject(function($controller) {
  $controller('YourCtrlName', {
    $window: fakeWindow
  });
}));

should allow the test to pass, assuming that the controller doesn't need $window for anything else.

like image 130
orbitbot Avatar answered Sep 30 '22 13:09

orbitbot


You could just create a function that does the navigation such as

$scope.Navigate = function() {
    window.location.href = "/path/to/page";
};

or even better in some service

app.factory('navigator', function() {
    return {
        Navigate: function(path) {
            window.location.href = path;
        }
    };
});

Then in your test you can use a spy on Navigate, to be sure that the navigation was called, but don't actually call the navigation.

like image 21
hassassin Avatar answered Sep 30 '22 11:09

hassassin