使用Jasmine异步测试postMessage不起作用

Ala*_*don 8 javascript unit-testing postmessage jasmine angularjs

我正在尝试使用Jasmine 2.0为AngularJS应用程序中的某些逻辑编写单元测试,但逻辑在一个事件监听器中.从控制器:

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

并从测试文件:

  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();
    });
  });
Run Code Online (Sandbox Code Playgroud)

但是测试失败了,间谍从未被击中.放入控制台调试语句的额外信息:

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

我的测试缺少什么?

Mic*_*nov 6

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

beforeEach(function(done) {  
    spyOn(someObject, 'submit').and.callFake(function () {
      done();
    });
});
Run Code Online (Sandbox Code Playgroud)

因此,当你的间谍执行时,异步操作被认为是完整的.

这可以表达得更短:

beforeEach(function(done) {  
    spyOn(someObject, 'submit').and.callFake(done);
});
Run Code Online (Sandbox Code Playgroud)

这是完整的代码:

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

});
Run Code Online (Sandbox Code Playgroud)

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

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