【问题标题】:angularjs + jasmine : testing focus in a serviceangularjs + jasmine:在服务中测试焦点
【发布时间】:2016-06-03 14:48:44
【问题描述】:

第一次学习 jasmine,我在尝试测试 Angular 服务中的 focus() 功能时遇到了这个错误。 这是服务:

myApp.service('MyService', function($timeout, $window) {
  var service = {
    focusElem: focusElem
  };
  return service;

  function focusElem(id) {
    console.log('id of element is = ', id);
    if (id) {

      $timeout(function() {
        var element = $window.document.getElementById(id);
        console.log('element is = ', element);
        if (element) {
          element.focus();
        }
      });
    }
  };

});

这是我的规范文件

describe('myApp', function() {
  var element, dummyElement;
  beforeEach(function() {
    // Initialize myApp injector
    module('myApp');

    // Inject instance of service under test    
    inject(function($injector) {
      MyServiceObj = $injector.get('MyService');
    });

    element = angular.element('<input id="firstName" name="firstName"/>');
    dummyElement = document.createElement('input');
    dummyElement.setAttribute('id', 'lastName');

  });

  it('should have focus if the focus Service is used on an element', function() {
    console.info('------------------');
    spyOn(element[0], 'focus');
    spyOn(dummyElement, 'focus');
    MyServiceObj.focusElem(dummyElement.getAttribute('id'));
    expect(dummyElement.focus).toHaveBeenCalled();
  });
});

我的错误:

myApp should have focus if the focus Service is used on an element
Expected spy focus to have been called.
Error: Expected spy focus to have been called.

【问题讨论】:

标签: angularjs unit-testing jasmine


【解决方案1】:

如果您使用的是ngMock,许多服务都已更改,因此可以在测试代码中以同步方式控制它们,从而让您更好地控制流程。

其中一个受影响的服务是$timeout

在你的服务中传递给$timeout的函数不会在你的测试中执行,除非你告诉它。

告诉它执行使用 $timeout.flush() 像这样:

spyOn(element[0], 'focus');

spyOn(dummyElement, 'focus');

MyServiceObj.focusElem(dummyElement.getAttribute('id'));

$timeout.flush();

expect(dummyElement.focus).toHaveBeenCalled();

请注意,您需要引用$timeout 服务:

var element, dummyElement, $timeout;

beforeEach(function() {

  module('myApp');

  inject(function($injector, _$timeout_) {

    MyServiceObj = $injector.get('MyService');

    $timeout = _$timeout_;
  });

下一个问题是由于您的服务中的以下行:

var element = $window.document.getElementById(id);

您在测试中创建的元素永远不会附加到 DOM,因此服务不会找到它们。

最简单的解决方案是将元素附加到 DOM。在这种情况下,您必须在测试后手动删除它们,因为 Jasmine 对您的整个测试套件使用相同的 DOM。

例如:

it('should have focus if the focus Service is used on an element', function() {

  var body = angular.element(document.body);

  body.append(element);
  body.append(dummyElement);

  spyOn(element[0], 'focus');

  spyOn(dummyElement, 'focus');

  MyServiceObj.focusElem(dummyElement.getAttribute('id'));

  $timeout.flush();

  expect(dummyElement.focus).toHaveBeenCalled();

  element.remove();
  dummyElement.remove();
});

演示: http://plnkr.co/edit/F8xqfYYQGa15rwuPPbN2?p=preview

现在,在单元测试期间向 DOM 附加和删除元素并不总是一件好事,而且可能会变得混乱。

还有其他方法可以处理它,例如通过监视getElementById 并控制返回值或通过模拟整个文档。我不会在这里讨论它,因为我相信这里已经有它的例子了。

【讨论】:

    猜你喜欢
    • 2014-09-04
    • 2012-10-12
    • 2014-06-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-22
    • 1970-01-01
    • 2013-03-13
    相关资源
    最近更新 更多