【问题标题】:Testing postMessage with Jasmine async doesn't work使用 Jasmine 异步测试 postMessage 不起作用
【发布时间】:2015-06-11 18:12:20
【问题描述】:

我正在尝试使用 Jasmine 2.0 为 AngularJS 应用程序中的某些逻辑编写单元测试,但该逻辑位于事件侦听器中。从控制器:

  window.addEventListener('message', function(e) {
    if (e.data === "sendMessage()") {
      $scope.submit();
    }
  }, false);

从测试文件中:

  describe("post message", function() {
    beforeEach(function(done) {
      var controller = createController(controllerParams);
      spyOn($scope, 'submit');
      window.postMessage('sendMessage()', '*');
      done();
    });

    it('should submit on a sent message', function (done) {
      expect($scope.submit).toHaveBeenCalled();
      done();
    });
  });

但测试失败了,间谍从未被击中。来自控制台调试语句的额外信息:

  • 控制器中的window.addEventListener 被调用。
  • beforeEachit 块都被调用。
  • 控制器中的上述消息处理程序在测试期间未被调用。
  • 此测试中发送的消息最终会被消息处理程序多次接收,但直到测试结束。

我的测试在这里遗漏了什么?

【问题讨论】:

  • 难道你不应该在 another 窗口上调用 postMessage 而不是接收事件的窗口吗? (比如说,创建一个弹出窗口,就像在 developer.mozilla.org/en-US/docs/Web/API/Window/… 上所做的那样)
  • 尝试将其更改为来自窗口弹出窗口的帖子消息,而不是来自窗口的帖子消息,但所有改变的是,它不会太晚收到消息,而是不会在全部。
  • @AlanGordon:你已经找到解决方案了吗?我有同样的问题;-)

标签: javascript angularjs unit-testing jasmine postmessage


【解决方案1】:

发生这种情况是因为在您的 beforeEach 块中您调用 window.postMessage()(这是异步的,您不知道它何时会执行),然后您在它之后调用 done(),因为它将是同步代码。但是window.postMessage() 是异步的,基本上你需要在异步操作完成时调用done()。可以这样做:

beforeEach(function(done) {  
    spyOn(someObject, 'submit').and.callFake(function () {
      done();
    });
});

所以当你的 spy 执行时,异步操作就被认为完成了。

这可以表达得更短:

beforeEach(function(done) {  
    spyOn(someObject, 'submit').and.callFake(done);
});

这里是完整的代码:

var someObject = {
  submit: function () {
    console.log('Submit');
  }
};

window.addEventListener('message', function(e) {
  if (e.data === "sendMessage()") {
    someObject.submit();
  }
}, false);

// Test

describe('window.postMessage', function () {

  beforeEach(function(done) {  
    spyOn(someObject, 'submit').and.callFake(function () {
      done();
    });
    window.postMessage('sendMessage()', '*');
  });

  it('should submit on a sent message', function () {
    expect(someObject.submit).toHaveBeenCalled();
  });

});

查看工作中的 JS Bin:http://jsbin.com/xikewogagu/1/edit?html,js,console,output

我在这个示例中没有使用 Angular,因为它可以用纯 JS 重现。

【讨论】:

  • 就是这样!感谢您的帮助。
  • 任何人都知道为什么只有当 spy 和 postMessage 在 beforeEach 中时这才有效?如果我们将其包裹在 it("...", (done) => {}) 中将无法工作....
  • 我想我明白了。将expect(...).toHaveBeenCalled() 放入and.fakeCall 回调中就可以了。不确定是否正确。
猜你喜欢
  • 1970-01-01
  • 2013-06-28
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-12-09
相关资源
最近更新 更多