茉莉花测试中函数内部未定义的 $scope 变量

undefined $scope variable inside function in jasmine test

我最近开始学习 angular 应用程序的单元测试。并且已经面临问题。我不能从执行函数内部获取 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.

为什么我看不到变量?

我自己对 Jasmine 有点菜鸟,但我猜这是因为你需要在 Jasmine 中得到 login() 到 return 的承诺。

考虑使用 $q.defer(), or even $httpBackend

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

(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 函数,它接受这些参数和延迟承诺。在 it 块中,我只是简单地调用 need 函数,用我准备好的模拟答案解决承诺并检查我的期望。一切正常。感谢您以何种方式瞄准