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

标签 javascript jquery angularjs unit-testing jasmine

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

在我正在测试的函数中:

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 is not an object (evaluating '$('#login-form')[0].submit')

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

我的规范加载了模板(日志正常)。元素也已定义,并且似乎是有效的 Angular 编译元素。

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

作为最后的手段,我在 Controller 中使用 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);
  });

最佳答案

事实上,这确实有效。您将需要使用 document.getElementById 进行 stub /监视,因为这就是 jquery 在幕后使用的内容。我只是忘了 stub submit 函数。我没有意识到这一点,因为 jasmine 包装的错误毫无意义。

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

关于javascript - 如何对包含 DOM/jquery 选择器的 Angular 1 Controller 进行单元测试?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38381255/

相关文章:

javascript - Ajax 发送多部分/表单数据

javascript - 在 ng-table 上使用 $http GET 加载的 JSON 数据未显示

javascript - 水平显示卡片列表,带有 Angular 和 MaterializeCSS 的 HTML/CSS

javascript - 如何隐藏/禁用 google.maps.places.Autocomplete 关闭按钮?

JavaScript:如何向对象添加新元素?

javascript - 基于点击按钮的动态 URL

jquery - 使用 jquery 将表单插入页面?

javascript - 语法缺失错误

javascript - 表单不断提交使用错误返回

javascript - 动态添加表中的列