2014-02-08 3 views
13

Я хотел бы модульного тестирования следующие AngularJs услуги:

.factory('httpResponseInterceptor', ['$q', '$location', '$window', 'CONTEXT_PATH', function($q, $location, $window, contextPath){ 
    return { 
     response : function (response) { 
      //Will only be called for HTTP up to 300 
      return response; 
     }, 
     responseError: function (rejection) { 
      if(rejection.status === 405 || rejection.status === 401) { 
       $window.location.href = contextPath + '/signin'; 
      } 
      return $q.reject(rejection); 
     } 
    }; 
}]); 

Я попытался с помощью следующего набора:

describe('Controllers', function() { 
    var $scope, ctrl; 
    beforeEach(module('curriculumModule')); 
    beforeEach(module('curriculumControllerModule')); 
    beforeEach(module('curriculumServiceModule')); 
    beforeEach(module(function($provide) { 
     $provide.constant('CONTEXT_PATH', 'bignibou'); // override contextPath here 
    })); 
    describe('CreateCurriculumCtrl', function() { 
     var mockBackend, location, _window; 
     beforeEach(inject(function ($rootScope, $controller, $httpBackend, $location, $window) { 
      mockBackend = $httpBackend; 
      location = $location; 
      _window = $window; 
      $scope = $rootScope.$new(); 
      ctrl = $controller('CreateCurriculumCtrl', { 
       $scope: $scope 
      }); 
     })); 

     it('should redirect to /signin if 401 or 405', function() { 
      mockBackend.whenGET('bignibou/utils/findLanguagesByLanguageStartingWith.json?language=fran').respond([{"description":"Français","id":46,"version":0}]); 
      mockBackend.whenPOST('bignibou/curriculum/new').respond(function(method, url, data, headers){ 
       return [401]; 
      }); 
      $scope.saveCurriculum(); 
      mockBackend.flush(); 
      expect(_window.location.href).toEqual("/bignibou/signin"); 
     }); 


    }); 
}); 

Однако она не со следующим сообщение об ошибке:

PhantomJS 1.9.2 (Linux) Controllers CreateCurriculumCtrl should redirect to /signin if 401 or 405 FAILED 
    Expected 'http://localhost:9876/context.html' to equal '/bignibou/signin'. 
PhantomJS 1.9.2 (Linux) ERROR 
    Some of your tests did a full page reload! 

Я не уверен, что происходит не так и почему. Кто-нибудь может помочь?

Я просто хочу, чтобы $window.location.href был равен .

редактировать 1:

мне удалось заставить его работать следующим образом (благодаря «dskh»):

beforeEach(module('config', function($provide){ 
     $provide.value('$window', {location:{href:'dummy'}}); 
})); 

ответ

17

Вы можете вводить зависимости заглушек при загрузке в модуле:

angular.mock.module('curriculumModule', function($provide){ 
      $provide.value('$window', {location:{href:'dummy'}}); 
     }); 
+0

Спасибо. Что я должен использовать как значение для '$ window' вместо' {} '? – balteo

+1

все, что вы хотите :). Вероятно, вы просто хотите проверить, что $ window.location не определено, поэтому вы можете проверить его позже, когда ваш тест устанавливает его в значение – Dan

+0

. Я также использую этот метод, но он прерывает мои тесты, которые ссылаются на $ location. Как вы обманываете $ window и получаете $ location, чтобы ссылаться на него? –

2

Чтобы заставить это работать на меня, мне пришлось внести незначительную корректировку. Было бы ошибки и сказать:

TypeError: 'undefined' is not an object (evaluating '$window.navigator.userAgent')

Поэтому я добавил объект navigator.userAgent, чтобы заставить его работать на меня.

1

Я столкнулся с той же проблемой и пошел дальше в своем решении. Я не просто хотел насмехаться, я хотел заменить $window.location.href шпионом Jasmine для лучшей способности отслеживать внесенные в него изменения. Итак, я узнал от apsiller's example for spying on getters/setters и после создания моего макета, я смог заглянуть в собственность, которую я хотел.

Во-первых, вот набор, который показывает, как я издевался $window, с тестом, чтобы продемонстрировать, что шпион работает, как ожидалось:

describe("The Thing", function() { 
    var $window; 

    beforeEach(function() { 
     module("app", function ($provide) { 
      $provide.value("$window", { 
       //this creates a copy that we can edit later 
       location: angular.extend({}, window.location) 
      }); 
     }); 

     inject(function (_$window_) { 
      $window = _$window_; 
     }); 
    }); 

    it("should track calls to $window.location.href", function() { 
     var hrefSpy = spyOnProperty($window.location, 'href', 'set'); 

     console.log($window.location.href); 
     $window.location.href = "https://www.google.com/"; 
     console.log($window.location.href); 

     expect(hrefSpy).toHaveBeenCalled(); 
     expect(hrefSpy).toHaveBeenCalledWith("https://www.google.com/"); 
    }); 
}); 

Как вы можете видеть выше, шпион генерируется путем вызова ниже функции (она работает как get и set)

function spyOnProperty(obj, propertyName, accessType) { 
    var desc = Object.getOwnPropertyDescriptor(obj, propertyName); 

    if (desc.hasOwnProperty("value")) { 
     //property is a value, not a getter/setter - convert it 
     var value = desc.value; 

     desc = { 
      get: function() { return value; }, 
      set: function(input) { value = input; } 
     } 
    } 

    var spy = jasmine.createSpy(propertyName, desc[accessType]).and.callThrough(); 

    desc[accessType] = spy; 
    Object.defineProperty(obj, propertyName, desc); 

    return spy; 
} 

Наконец, here's a fiddle demonstrating this in action. Я тестировал это против Angular 1.4 и Jasmine 2.3 и 2.4.

+0

По состоянию на Jasmine 2.6 (возможно, раньше, не уверен) 'spyOnProperty' был объединен с ядром и не должен быть реализован пользователем: https://jasmine.github.io/api/edge/global.html# spyOnProperty –

Смежные вопросы