2016-01-27 3 views
1

Недавно я начал изучать модульный тест для угловых приложений. И уже столкнулись с проблемой. Я не могу взять переменную scope изнутри выполненной функции. Вот мой заводской код

angular.module('app').factory('AuthenticationService', AuthenticationService); 
    AuthenticationService.$inject = ['$http']; 
    function AuthenticationService($http) { 
    var service = {}; 

    service.login = login; 
    return service; 

    function login(data, callback) { 
     $http({ 
     method: 'POST', 
     url: CONFIG.getUrl('auth/login'), 
     data: data 
     }).then(function (response) { 
      callback(response); 
     }, function (error) { 
      callback(error); 
     }); 
    } 

Часть моего файла контроллера. Я только еще тусклый, чтобы проверить login функцию

function AuthCtrl($scope, $location, AuthenticationService) { 
    var vm = this; 
    vm.login = login; 

    vm.dataLogin = { 
     user_id: '', 
     password: '', 
    }; 
    function login() { 
     vm.dataLoading = true; 
     AuthenticationService.login(vm.dataLogin, function (response) { 

      if (response.status == 200) { 
      if (response.data.error_code == 'auth.credentials.invalid') { 
       vm.invalidCredentials = true; 
      } else { 
       vm.invalidCredentials = false; 
       if (response.data.session_state == 'otp_required') { 
       vm.userNumber = response.data.user_phone; 
       $localStorage['session_token'] = response.data.session_token; 
       vm.needForm = 'someForm'; 
       } else { 
       AuthenticationService.setCredentials(response.data); 
       $state.go('dashboard'); 
       } 
       vm.dataLoading = false; 
      } 
      } 
     }); 
     } 
    } 
}); 

И мои spec.js

describe('AuthCtrl, ', function() { 
    var $scope, ctrl; 
    var authSrvMock; 


    var mockJson = { 
     user_id: '001', 
     session_token: 'some_token' 
    }; 

    var mockLoginData = { 
     user_id: '0000102', 
     password: '123456' 
    }; 

    var mockResponseData = { 
     data: { 
     "session_expires": 1453822506, 
     "session_state": "otp_required", 
     "session_token": "tokennnn", 
     "status": "success", 
     "user_id": "0000102", 
     "user_phone": "+7 (XXX) XXX-XX-89" 
     }, 
     status: 200 
    }; 

    beforeEach(function() { 

     authSrvMock = jasmine.createSpyObj('AuthenticationService', ['login', 'logout']); 
     module('app'); 

     inject(function ($rootScope, $controller, $q) { 
     $scope = $rootScope.$new(); 
     authSrvMock.login.and.returnValue(mockResponseData); 
     ctrl = $controller('AuthCtrl', { 
      $scope: $scope, 
      AuthenticationService: authSrvMock 
     }); 
     }); 
    }); 

    it('should call login function and pass to dashboard', function() { 
     ctrl.login(); 
     expect(authSrvMock.login).toHaveBeenCalled(); 
     // until this everything works here just fine 
    }); 

    }); 

Но после того, как я хочу, чтобы проверить vm.invalidCredentials, если я буду писать

expect(ctrl.invalidCredentials).toBe(false) 

Я получаю погрешность Expected undefined to be false.

Почему я не вижу переменных?

+0

Создал [плунжер проблемы] (https://plnkr.co/edit/tTBcGd4UuBv12GIbj5DD?p=preview). Казалось бы, он не попадает в функцию входа в систему (открывайте консоль и обновляйте предварительный просмотр) –

+0

@JamieBarker Итак, почему это происходит? Что мне делать, чтобы войти? Разрешить обещание или? Не могли бы вы объяснить PLS? – David

ответ

0

После некоторого процесса копания и экспериментов я нашел решение. Вот что я сделал

(function() { 

'use strict'; 

describe('AuthCtrl', function() { 
    var controller, scope, myService, q, deferred, ctrl; 

    var mockResponseData = { 
    response1: { 
     //... 
    }, 
    response2: { 
     //... 
    }, 
    response3: { 
     //... 
    } 

    }; 

    beforeEach(module('app')); 

    beforeEach(inject(function ($controller, $rootScope, $q, $httpBackend, AuthenticationService) { 

    function mockHttp(data, callback) { 
     deferred = $q.defer(); 
     deferred.promise.then(function (response) { 
      callback(response); 
     }, function (error) { 
      callback(error); 
     }); 
    } 

    controller = $controller; 
    scope = $rootScope.$new(); 
    myService = AuthenticationService; 
    q = $q; 

    myService.login = mockHttp; 

    })); 

    describe('when returning promises', function() { 
    beforeEach(function() { 
     ctrl = controller('AuthCtrl', { 
     $scope: scope, 
     myService: myService 
     }); 
     ctrl.initController(); 
    }); 

    it('shows another form to validate login process', function() { 
     ctrl.login(); 
     deferred.resolve(mockResponseData.response1); 
     scope.$digest(); 
     expect(ctrl.invalidCredentials).toBe(false); 
     expect(ctrl.needForm).toEqual('2sAuth'); 
     expect(ctrl.dataLoading).toBe(false); 
    }); 

    }); 
}); 

})(); 

Поскольку в моей фабрике почти каждый метод требует data и callback я создал функции mockHttp который принимает эти аргументы и отсроченное обещание. В блоке it я просто вызываю функцию необходимости, разрешаю обещание с моими подготовленными ответами и проверяю мои ожидания. Все работает. Спасибо за то, что он нацелен на то, чтобы выглядеть так:

0

Немного о себе в Жасмине, но я думаю, это потому, что вам нужно получить обещание от вашего login(), чтобы вернуться в Жасмин.

Изучите использование $q.defer() или даже $httpBackend.