为一个指令编写测试,该指令在因果报应中进行整页重新加载
Writing a test for a directive that does a full page reload in Karma
我想对一个指令进行单元测试,该指令将用户重定向到后台的社交登录url。
由于Karma不支持全页重载,我想改变location.href JavaScript对象的行为,将它接收到的参数输出到具有特定ID的HTML元素,但我很难做到这一点。
指令:
__app.directive('socialAuth', function(utils, authService, $location){
return{
restrict: 'A',
scope: false,
link: function(scope, elem, attrs){
elem.bind('click', function(){
utils.cleanSocialSearch();
if(attrs.checkbox == 'personal'){
scope.$apply(function(){
scope.model.personalShare[attrs.network] = true;
$location.search('personalShare', '1');
});
}
else if(attrs.checkbox == 'group'){
scope.$apply(function(){
var __index = attrs.checkbox + '_' + attrs.network;
scope.model.personalShare[__index] = true;
$location.search('groupShare', '1');
});
}
var callback = encodeURIComponent(window.location.href);
var loginUrl = utils.getBaseUrl() + '/social/login/' + attrs.network + '?success_url=' + callback;
location.href = loginUrl;
});
}
}
});
尝试模拟location.href对象进行测试(是的,我知道这不是一个函数):
var location = {//an attempt to mock the location href object
href: function(param){
$('#content').html(param);
}
};
'use strict';
describe('socail-auth', function(){//FB
var scope, compiled, linkFn, html, elem, elemPersonal, elemGroups, compile, authService;
html = "<span id='content' data-social-auth data-network='facebook'>";
beforeEach(function(){
module('myApp.directives');
module('myApp.services');
inject(function($compile, $rootScope){
scope = $rootScope.$new();
linkFn = $compile(angular.element(html));
elem = linkFn(scope);
scope.$digest();
elem.scope().$apply()
});
})
it("should redirect user to social login url at the backend", function(){
// console.log(location.href);
elem.click();
console.log($(elem).html());
expect($(elem).html()).toBeDefined();
});
});
使用$window.location.href
而不是location.href
。
然后用一个空对象模拟$window.location
,它就会完成这项工作。
describe('location', function() {
var $window;
beforeEach( module('myApp') );
// You can copy/past this beforeEach
beforeEach( module( function($provide) {
$window = {
// now, $window.location.path will update that empty object
location: {},
// we keep the reference to window.document
document: window.document
};
// We register our new $window instead of the old
$provide.constant( '$window' , $window );
}))
// whatever you want to test
it('should be redirected', function() {
// action which reload the page
$scope.reloadPage();
// we can test if the new path is correct.
expect( $window.location.path ).toBe('/the-url-expected');
})
})
解决方案是将重定向到API的内容包装在服务函数中,并在测试中模拟它以将重定向URL保存在服务变量中,然后通过getter方法将其暴露给测试,而不是重定向到它。
模拟可以在测试主体内完成:
module('myApp.services.mock', function($provide){
var __service = function(){
var __data;
return{
getFn: function(){
return __data;
},
setFn: function: function(data){
__data = data;
}
}
}
$provide.value('someService', __service);
});
但我选择将这个模拟介绍与它自己的模型分开,以增强的结构和模块性
'use strict';
angular.module('myApp.services.mock', ['urlConfig']).
factory('utils', function(API_URL, $location, $rootScope, $window){
var __redirectURL = $window.location.href;
var utilsMock = {
getBaseUrl: function(){
return API_URL;
},
getLocationHref: function(){
return __redirectURL;
},
setLocationHref: function(redirectURL){
$rootScope.$apply(function(){
__redirectURL = redirectURL;
});
},
cleanSocialSearch: function(){
$location.search('auth_success', null);
$location.search('auth_error', null);
$location.search('auth_media', null);
$location.search('personalShare', null);
$location.search('groupShare', null);
}
}
return utilsMock;
});
--
__app.directive('socialAuth', function(utils, $location){
return{
restrict: 'A',
scope: false,
link: function(scope, elem, attrs){
elem.bind('click', function(){
utils.cleanSocialSearch();
if(attrs.checkbox == 'personal'){
scope.$apply(function(){
scope.model.personalShare[attrs.network] = true;
$location.search('personalShare', '1');
});
}
else if(attrs.checkbox == 'group'){
scope.$apply(function(){
var __index = attrs.checkbox + '_' + attrs.network;
scope.model.personalShare[__index] = true;
$location.search('groupShare', '1');
});
}
var callback = encodeURIComponent(utils.getLocationHref());
var loginUrl = utils.getBaseUrl() + '/social/login/' + attrs.network + '?success_url=' + callback;
utils.setLocationHref(loginUrl);
});
}
}
});
最后是测试:
describe('socail-auth', function(){//FB
var scope, compiled, linkFn, utils, html, elem, elemPersonal, elemGroups, compile, authService, utilsMock, _window, BASE_URL, __network;
__network = 'facebook';
html = "<span data-social-auth data-network='" + __network + "'></span>";
beforeEach(function(){
module('urlConfig');
module('myApp.services.mock');
module('myApp.directives');
inject(function($compile, $rootScope, $injector){
scope = $rootScope.$new();
utils = $injector.get('utils');
_window = $injector.get('$window');
BASE_URL = $injector.get('API_URL');
linkFn = $compile(angular.element(html));
elem = linkFn(scope);
// scope.$digest();
elem.scope().$apply()
});
})
it("should redirect user to social login url at the backend", function(){
elem.click();
//scope.$digest();
var loginUrl = BASE_URL + '/social/login/' + __network + '?success_url=' + encodeURIComponent(_window.location.href);
expect(utils.getLocationHref()).toEqual(loginUrl);
});
});
相关文章:
- 数据表 AJAX 筛选器重新加载数据
- 在指令内加载后访问子元素图像
- 在指令之后加载的角度ng-init函数
- angularjs 子指令 DOM 加载速度不够快
- 如何在新加载的页面上执行(下拉)操作
- 根据上一个选项卡的选择器重新加载选项卡
- 获得“中止,因为不接受 0”并使用反应热加载器重新加载整页
- 咕噜咕噜的手表:实时加载重新加载落后 1 步....
- 角度:在另一个模态指令中加载的谷歌地图指令保持空白
- 如何为新加载的元素提供JQuery UI工具提示
- 如何在新加载的页面上使用相同的JavaScript代码(通过重定向)
- AngularJS:有没有办法知道包含在另一个指令中的指令何时加载
- 使用PHP或Javascript检测页面刷新或新加载
- 砌体重新加载&reloadItems不起作用
- Angular.js指令与加载数据的双向绑定
- 如何使javascript计时器重新加载
- 如何获取新加载的图像's width / naturalWidth
- 列出并调用firefox扩展中新加载的选项卡中的js函数
- 旋转器重新加载图像似乎在覆盖层后面
- anglularJs自定义指令未加载