如何将拒绝/失败的承诺通过茉莉花间谍返回到单位测试中的角度控制器

Nis*_*rma 6 javascript unit-testing angularjs angularjs-controller karma-jasmine

我正在使用茉莉来测试我的角度控制器..then(successCallback, errorCallback) 虽然它在实时功能的基础上工作得很好但是我很困惑如何写一个间谍来返回一个错误,因为它总是被捕获的错误和成功successCallback()

以下是控制器: -

angular.module('myApp')
.controller('LoginCtrl', function ($scope, $location, loginService, SessionService) {
    $scope.errorMessage = '';

    $scope.login = function () {

      var credentials = {
          email: this.email,
          password: this.password
      };

     SessionService.resetSession();
     var request = loginService.login(credentials);

     request.then(function(promise){ //successfull callback
        if (promise['status'] === 200){
             //console.log('login');
            $location.path('/afterloginpath');
        }
      },
     function(errors){  //fail call back
      //  console.log(errors);
        $location.path('/login');
     });
    };
});
Run Code Online (Sandbox Code Playgroud)

我的测试用例: -

'use strict';

describe('Controller: LoginCtrl', function () {

  // load the controller's module
  beforeEach(module('myApp'));

  var LoginCtrl, scope, location, login, loginReturn, session;
  var credentials = {'email': 'email@email.com', 'password': 'admin123'};

  // Initialize the controller and a mock scope
 beforeEach(inject(function ($controller, $rootScope, $location, _loginService_, _SessionService_) {

    scope = $rootScope.$new();
    LoginCtrl = $controller('LoginCtrl', {
      $scope: scope
    });

    location = $location;
    login = _loginService_;
    session = _SessionService_;
    scope.errorMessage = '';
    spyOn(login, "login").andCallFake(
      function(){
        return {
          then: function(response){
            response(loginReturn);
          }
        }
      }
    );

    spyOn(session, "setName").andCallFake(function(){
      return true;
    });
  }));

  it('should go to login when login fail', function () {
    loginReturn = function(){
      return{
        successfullyCallback: {throwError:true},
        failCallback: {status: 400, 'data' : {'errors' : [{"type":"invalid_data","target":"email,password"}]}}
      }
    };

    var wrong_creds = {email: 'wrong@email.com', password: 'wrong_password'};
    scope.email = wrong_creds.email;
    scope.password = wrong_creds.password;

scope.login();

    expect(location.path()).toBe("/login");
    expect(scope.errorMessage).toBe('username or password combination is invalid');
  });

});
Run Code Online (Sandbox Code Playgroud)

iva*_*rni 20

我发现使用模拟服务的实际承诺更容易,因为它删除了很多嵌套函数,并且更容易阅读.

相关的片段($ q需要在beforeEach之前注入):

deferred = $q.defer();
spyOn(login, 'login').andReturn(deferred.promise);

...

deferred.reject({ ... });
Run Code Online (Sandbox Code Playgroud)

在解决或拒绝您需要调用的承诺后scope.$digest(),角度可以处理它.

  • 范围.$ apply()有效,因为它触发范围.$ digest()但是$ apply()意味着用表达式调用,所以我倾向于使用$ digest()代替.请查看https://docs.angularjs.org/api/ng/type/$rootScope.Scope#$apply,了解它们之间的区别. (2认同)
  • Jasmine 2.0语法是:and.returnValue(); (2认同)