可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I would like to unit test the following AngularJs service:
.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); } }; }]);
I have tried with the following suite:
However, it fails with the following error message:
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!
I am not sure what is going wrong and why. Can anyone please help?
I just want to ensure the $window.location.href is equal to '/bignibou/signin'.
edit 1:
I managed to get it to work as follows (thanks to "dskh"):
beforeEach(module('config', function($provide){ $provide.value('$window', {location:{href:'dummy'}}); }));
回答1:
You can inject stub dependencies when you load in your module:
angular.mock.module('curriculumModule', function($provide){ $provide.value('$window', {location:{href:'dummy'}}); });
回答2:
To get this to work for me I had to make a minor adjustment. It would error out and say:
TypeError: 'undefined' is not an object (evaluating '$window.navigator.userAgent')
So I added the navigator.userAgent object to get it to work for me.
$provide.value('$window', { location:{ href:'dummy' }, navigator:{ userAgent:{} } });
回答3:
I faced the same problem, and went a step further in my solution. I didn't just want a mock, I wanted to replace $window.location.href with a Jasmine spy for the better ability to track changes made to it. So, I learned from apsiller's example for spying on getters/setters and after creating my mock, I was able to spy on the property I wanted.
First, here's a suite that shows how I mocked $window, with a test to demonstrate that the spy works as expected:
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/"); }); });
As you can see above, the spy is generated by calling the below function: (it works for both get and 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; }
Lastly, here's a fiddle demonstrating this in action. I've tested this against Angular 1.4, and Jasmine 2.3 and 2.4.