如何对包含DOM / jquery选择器的Angular 1控制器进行单元测试?

时间:2016-07-14 18:07:50

标签: javascript jquery angularjs unit-testing jasmine

使用jasmine时,我似乎无法测试其中包含jquery选择器或document.getElementById的函数。这里有更好的策略吗?我通常不会将选择器放在角度代码中,但这是一种解决方法。

在我正在测试的功能中:

this.scope.login = () => {

 ($('#login-form')[0] as HTMLFormElement).submit(); 
 // or even 
 document.getElementById('login-form').submit(); // this is a workaround for browser auto-complete, I normally would not have selectors in angular code.
}

我得到了

  

TypeError:undefined不是对象(评估'$('#login-form')[0] .submit')

我试过“通过间谍模拟”,使用spyOn尝试模拟jquery选择器函数并返回一个假元素......但似乎不起作用,或者我做得不对。

我的规范加载模板(记录正常)。元素也被定义,似乎是一个有效的角度编译元素。

describe('Nav Controller Spec', function() {

beforeEach(function() {
  angular.mock.module('App');

  inject(function(_$controller_, $rootScope, _userModel_, _$q_, _$httpBackend_, $templateCache, _$compile_) {

    scope = $rootScope.$new();
    $q = _$q_;
    $compile = _$compile_;
    $httpBackend = _$httpBackend_;
    deferred = _$q_.defer();

    html = $templateCache.get('main/components/login/login.tpl.html');
    var el = angular.element( html );
    element = $compile( el )(scope); //element is valid and works

    controller = _$controller_;
    userModel = _userModel_;

    scope.userModel = userModel;

    // tried this... still get error
    spyOn($.fn, 'val').and.returnValue('<form></form>');

    //if i change to 'init' or 'find', i get 'undefined is not a constructor'
    spyOn($.fn, 'init').and.returnValue('<form></form>');

    ctrl = controller('loginController', { $scope: scope, $element: element });

    $rootScope.$digest();
  });

});

it('should login and change the status', function(){
   spyOn(  ctrl.scope.userModel, 'login' ).and.callThrough();
   ctrl.scope.formType = 'login';
   ctrl.scope.login(); //fails
   expect( ctrl.scope.userModel.login ).toHaveBeenCalled();
});

作为最后的手段,我在控制器中使用document.getElementById('login-form')尝试了以下操作。但是,我得到TypeError: undefined is not a constructor (evaluating 'document.getElementById('login-form').submit()')

  var mockElement = {
    id:"login-form",
    parentNode:true
  };
  var document_getElementById = document.getElementById;
  var spy = spyOn(document, "getElementById").and.callFake(function(id){
    if(id===mockElement.id){
      return mockElement;
    }
    return document_getElementById(id);
  });

1 个答案:

答案 0 :(得分:2)

实际上,这是有效的。您将需要使用document.getElementById来存根/间谍,因为这是jquery在引擎盖下使用的内容。我只是忘记了submit函数的存根。我没有意识到这一点,因为茉莉花的包装错误是如此毫无意义。

      var mockElement = {
        id:"login-form",
        parentNode:true,
         submit:function(){
           return 'cheese';
         }
      };
      var document_getElementById = document.getElementById;
      var spy = spyOn(document, "getElementById").and.callFake(function(id){
        if(id===mockElement.id){
          return mockElement;
        }
        return document_getElementById(id);
      });