在jasmine测试中函数内的undefined $ scope变量

时间:2016-01-27 10:12:59

标签: javascript angularjs unit-testing karma-jasmine

我最近开始学习角度应用的单元测试。并且已经遇到了问题。我不能从执行的函数内部取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.

为什么我看不到变量?

2 个答案:

答案 0 :(得分:0)

我自己在Jasmine做了一个菜鸟,但是我猜它是因为你需要从login()获得承诺才能回到Jasmine。

使用$q.defer(),甚至是$httpBackend

答案 1 :(得分: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);
    });

  });
});

})();

因为在我的工厂中几乎每个方法都需要datacallback我创建了mockHttp函数,它接受那些参数和延迟的promise。在it块中,我只需调用需要函数,用我准备好的答案解析诺言并模拟我的期望。一切正常。感谢您瞄准目标