使用 karma 在 Angular 中获取 e.currentTarget 的测试事件

test event that grabs e.currentTarget in Angular using karma

我已经尝试完成这项工作好几个小时了。我想测试基于 target = e.currentTargetinput.val() 进行 api 调用的 $scope.function,但我现在处于死点。

问题是,如何模拟e.currentTarget才能让测试通过?

如果这不是正确的方法,您有什么建议?

我希望真的有办法。我使用的很多函数都有“if e.currentTarget = xxx”行为。

这是我的控制器,工作正常

angular.module('myapp')
    .controller('myctrl', function($scope, $http) {
      var offset = 0;
      //search function
      var generalSearch = function(target) {
        $('.somediv').hide();
        if (target.hasClass('someclass') && $scope.paginationNext == true) {
          dostuff
        }
        if (target.hasClass('someclass') && $scope.paginationPrev == true) {
          dostuff
        }
        var getArtist = function (type='somevalue') {
          var query = $('#somediv').val();e
          var url = "someurl?query=" + query + '&offset='+ offset +'&limit=20&type='+ type;
          if (query !== '' && query !== null) {
            $http.get(url, {cache:true})
              .then(function(res) {
                $scope.somevar = res.data;
                if ($scope.result.length > 0) {
                  $('#somediv').hide();
                  $('.somediv').show(); //shows results
                }else {
                  $('#somediv').show();
                  $('.somep').text('').append("<i class='fa fa-frown-o' aria-hidden='true'></i> We couldn't find any artist nor album with that name");
                  setTimeout(
                    function() {
                      $('.somep').text('Your result will appear here');
                    }, 5000);
                }
                if (res.data.next !== null || res.data.albums.next !== null) {
                  $scope.paginationNext = true;
                }else {
                  $scope.paginationNext = false;
                }
                if (res.data.previous !== null || res.data.albums.previous !== null) {
                  $scope.paginationPrev = true;
                }else {
                  $scope.paginationPrev = false;
                }
            }, function(error) {
              //if the user search more than once, and there's no results, this will show the magnify again
              $('#somediv').show(); 
            });
          }else {
            $('.somep').text('').append("ERROR: We can't find what you want if you don't tell us what it is");
            setTimeout(
              function() {
                $('.somep').text('Your result will appear here');
              }, 5000);
          }     
        }
        getArtist();
      }
      $scope.startSearch = function Search(e) {    
        var target = $(e.currentTarget);
        generalSearch(target);
      }

这是我的测试,我想我可以使用带有模板和触发器的 httpBackend 来模拟 e.current 目标,但总是得到 TypeError: Cannot read property 'currentTarget' of undefined

describe('movie app tests', function () {
  var $controller;
  var $httpBackend;
  var $scope;
    var el, $compile, simpleHtml;
    
  beforeEach(module('spotify'));
  beforeEach(inject(function($rootScope, _$controller_, _$httpBackend_, $templateCache, _$compile_) {
    $controller = _$controller_;
    $scope = $rootScope.$new();
    $httpBackend = _$httpBackend_;
    $templateCache.put('./views/search/search.html', [
      '<section class="searcher-container visiond-20" id="searcher">',
      ' <form class="visiond-18 visiond-lg-8">',
      '     <fieldset class="searcher-wrapper">',
      '         <input type="text" id="artist" value="lamb of god">',
      '         <button ng-click="startSearch($event)" type="submit" class="searcher-button visiond-13 visiond-lg-5" id="searchButton">search</button> ',
      '     </fieldset>',
      ' </form>',
      '</section>'
    ].join(''));
    $compile = _$compile_;
  }));
  describe('http tests (original example)', function() {
    it('should load user defined movies on search', function () {
      $controller('ctrlSearch', { $scope: $scope });
        simpleHtml = '<div ng-search id="searcher-container"></div>';
        el = $compile(angular.element(simpleHtml))($scope);
        $scope.$digest();
      var input = el.find('#artist');
      $scope.$apply(function() {
        angular.element(input).val('lamb of god');
      });
      el.find('.searcher-button').click();
      //$scope.startSearch();
      //$httpBackend.flush();
      //expect($scope.movies).toEqual(testData.query.starwars);
    });
  });
});

由于您使用 2 到 3 个元素作为条件,我想我可以采用另一种方法,例如测试 startSearch 是否已启动,然后分别测试其他功能...

我不确定你的 "if e.currentTarget = xxx" 方法是否正确,但我为它写了一个简单的工作测试:

angular.module('spotify', [])
  .controller('SearchController', function($scope) {

    $scope.startSearch = function(e) {
     $scope.currentTarget = e.currentTarget;
    }
  });

describe('SearchController', function() {

  var $scope, $compile;

  beforeEach(module('spotify'));

  beforeEach(inject(function($rootScope, _$compile_) {
    $compile = _$compile_;
    $scope = $rootScope.$new();
  }));

  it('should start search', function() {   
    var html = [
      '<div ng-controller="SearchController">',
      ' <button ng-click="startSearch($event)" class="test-class">search</button>',
      '</div>'].join('');
    var elm = $compile(angular.element(html))($scope);
    var button = elm.find("button");
    $(button).click();

    expect(elm.scope().currentTarget).toBeDefined();
    expect(elm.scope().currentTarget.className).toBe('test-class');
  });
});

Run JSFiddle

一键编译简单控制器html,点击即可。为了触发点击,我尝试使用您的代码中类似于 el.find('.searcher-button').click(); 的内容,但它导致 click 未定义错误。使用 jQuery 对此有所帮助。

请注意,您需要在断言中使用 elm.scope() 而不是 $scopeelm.scope() returns 在 ngController 指令元素与 $scope 链接期间创建的子作用域。您可以在 $compile docs.

中了解更多信息