Javascript jasmine测试中函数内未定义的$scope变量

Javascript jasmine测试中函数内未定义的$scope变量,javascript,angularjs,unit-testing,karma-jasmine,Javascript,Angularjs,Unit Testing,Karma Jasmine,我最近开始学习angular应用程序的单元测试。而且已经面临问题了。我不能从内部执行的函数中获取范围变量。这是我的工厂代码 angular.module('app').factory('AuthenticationService', AuthenticationService); AuthenticationService.$inject = ['$http']; function AuthenticationService($http) { var service = {};

我最近开始学习angular应用程序的单元测试。而且已经面临问题了。我不能从内部执行的函数中获取
范围
变量。这是我的工厂代码

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);
        });
    }
我的控制器文件的一部分。我只想测试
登录
功能

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)
我将得到错误
预期未定义为false。


为什么我看不到变量

我自己在Jasmine有点不爽,但我猜这是因为你需要从你的
login()
中得到承诺才能回到Jasmine


考虑一下如何使用,甚至。

我自己在Jasmine也有点不妥,但我猜这是因为你需要从你的
登录()中得到承诺才能返回Jasmine


研究使用,甚至。

经过更多的挖掘过程和实验,我找到了解决办法。 这就是我所做的

(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);
    });

  });
});

})();

因为在我的工厂里,几乎每个方法都需要
数据
回调
,所以我创建了mockHttp函数,它接受这些参数和延迟承诺。在
it
模块中,我只需调用need函数,用我准备好的答案解决promise,并检查我的期望。一切正常。多亏了你的瞄准,在经过更多的挖掘过程和实验后,我找到了解决办法。 这就是我所做的

(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);
    });

  });
});

})();

因为在我的工厂里,几乎每个方法都需要
数据
回调
,所以我创建了mockHttp函数,它接受这些参数和延迟承诺。在
it
模块中,我只需调用need函数,用我准备好的答案解决promise,并检查我的期望。一切正常。多亏了您的瞄准方式,才创造了一个完美的外观。它似乎没有进入登录功能(打开控制台并刷新预览)@JamieBarker,那么为什么会发生这种情况呢?我该怎么做才能进去?下决心还是承诺?你能解释一下吗。它似乎没有进入登录功能(打开控制台并刷新预览)@JamieBarker,那么为什么会发生这种情况呢?我该怎么做才能进去?下决心还是承诺?你能解释一下吗?