Escribir una prueba para una directiva que hace una recarga completa de página en Karma
-
21-12-2019 - |
Pregunta
Me gustaría probar la unidad una directiva que redirige a un usuario a la URL de inicio de sesión social en el respaldo.
Dado que el karma no admite las recargas de página completa, me gustaría alterar el comportamiento de la ubicación. Objeto JavaScript para generar el parámetro que recibe a un elemento HTML con una cierta identificación, y tengo dificultades para hacereso.
Directiva:
__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;
});
}
}
});
Prueba con un intento de burlarse de la ubicación. Objeto de FEF (Sí, sé que no es una función):
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();
});
});
Solución 2
La solución es envolver la redirección a la API en una función de servicio, y para burlarse de él dentro de la prueba para guardar la URL de redireccionamiento en una variable de servicio, y luego exponerla a través de un método de Getter a la prueba en lugar de redirigir aeso.
Se puede hacer una burla desde el cuerpo de prueba:
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);
});
Pero elijo separar este Mock Intro su propio modelo para mejorar la estructura y la modularidad
'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);
});
}
}
});
y finalmente la prueba:
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);
});
});
Otros consejos
Use $window.location.href
en lugar de location.href
.
luego simulando $window.location
con un objeto vacío, hará el trabajo.
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');
})
})