michael@0: /* This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: 'use strict'; michael@0: michael@0: const { LoaderWithHookedConsole } = require("sdk/test/loader"); michael@0: michael@0: // Exposing private methods as public in order to test michael@0: const EventEmitter = require('sdk/deprecated/events').EventEmitter.compose({ michael@0: listeners: function(type) this._listeners(type), michael@0: emit: function() this._emit.apply(this, arguments), michael@0: emitOnObject: function() this._emitOnObject.apply(this, arguments), michael@0: removeAllListeners: function(type) this._removeAllListeners(type) michael@0: }); michael@0: michael@0: exports['test:add listeners'] = function(assert) { michael@0: let e = new EventEmitter(); michael@0: michael@0: let events_new_listener_emited = []; michael@0: let times_hello_emited = 0; michael@0: michael@0: e.on("newListener", function (event, listener) { michael@0: events_new_listener_emited.push(event) michael@0: }) michael@0: michael@0: e.on("hello", function (a, b) { michael@0: times_hello_emited += 1 michael@0: assert.equal("a", a) michael@0: assert.equal("b", b) michael@0: assert.equal(this, e, '`this` pseudo-variable is bound to instance'); michael@0: }) michael@0: michael@0: e.emit("hello", "a", "b") michael@0: }; michael@0: michael@0: exports['test:removeListener'] = function(assert) { michael@0: let count = 0; michael@0: michael@0: function listener1 () { michael@0: count++; michael@0: } michael@0: function listener2 () { michael@0: count++; michael@0: } michael@0: michael@0: // test adding and removing listener michael@0: let e1 = new EventEmitter(); michael@0: assert.equal(0, e1.listeners('hello').length); michael@0: e1.on("hello", listener1); michael@0: assert.equal(1, e1.listeners('hello').length); michael@0: assert.equal(listener1, e1.listeners('hello')[0]); michael@0: e1.removeListener("hello", listener1); michael@0: assert.equal(0, e1.listeners('hello').length); michael@0: e1.emit("hello", ""); michael@0: assert.equal(0, count); michael@0: michael@0: // test adding one listener and removing another which was not added michael@0: let e2 = new EventEmitter(); michael@0: assert.equal(0, e2.listeners('hello').length); michael@0: e2.on("hello", listener1); michael@0: assert.equal(1, e2.listeners('hello').length); michael@0: e2.removeListener("hello", listener2); michael@0: assert.equal(1, e2.listeners('hello').length); michael@0: assert.equal(listener1, e2.listeners('hello')[0]); michael@0: e2.emit("hello", ""); michael@0: assert.equal(1, count); michael@0: michael@0: // test adding 2 listeners, and removing one michael@0: let e3 = new EventEmitter(); michael@0: assert.equal(0, e3.listeners('hello').length); michael@0: e3.on("hello", listener1); michael@0: assert.equal(1, e3.listeners('hello').length); michael@0: e3.on("hello", listener2); michael@0: assert.equal(2, e3.listeners('hello').length); michael@0: e3.removeListener("hello", listener1); michael@0: assert.equal(1, e3.listeners('hello').length); michael@0: assert.equal(listener2, e3.listeners('hello')[0]); michael@0: e3.emit("hello", ""); michael@0: assert.equal(2, count); michael@0: }; michael@0: michael@0: exports['test:removeAllListeners'] = function(assert) { michael@0: let count = 0; michael@0: michael@0: function listener1 () { michael@0: count++; michael@0: } michael@0: function listener2 () { michael@0: count++; michael@0: } michael@0: michael@0: // test adding a listener and removing all of that type michael@0: let e1 = new EventEmitter(); michael@0: e1.on("hello", listener1); michael@0: assert.equal(1, e1.listeners('hello').length); michael@0: e1.removeAllListeners("hello"); michael@0: assert.equal(0, e1.listeners('hello').length); michael@0: e1.emit("hello", ""); michael@0: assert.equal(0, count); michael@0: michael@0: // test adding a listener and removing all of another type michael@0: let e2 = new EventEmitter(); michael@0: e2.on("hello", listener1); michael@0: assert.equal(1, e2.listeners('hello').length); michael@0: e2.removeAllListeners('goodbye'); michael@0: assert.equal(1, e2.listeners('hello').length); michael@0: e2.emit("hello", ""); michael@0: assert.equal(1, count); michael@0: michael@0: // test adding 1+ listeners and removing all of that type michael@0: let e3 = new EventEmitter(); michael@0: e3.on("hello", listener1); michael@0: assert.equal(1, e3.listeners('hello').length); michael@0: e3.on("hello", listener2); michael@0: assert.equal(2, e3.listeners('hello').length); michael@0: e3.removeAllListeners("hello"); michael@0: assert.equal(0, e3.listeners('hello').length); michael@0: e3.emit("hello", ""); michael@0: assert.equal(1, count); michael@0: michael@0: // test adding 2 listeners for 2 types and removing all listeners michael@0: let e4 = new EventEmitter(); michael@0: e4.on("hello", listener1); michael@0: assert.equal(1, e4.listeners('hello').length); michael@0: e4.on('goodbye', listener2); michael@0: assert.equal(1, e4.listeners('goodbye').length); michael@0: e4.emit("goodbye", ""); michael@0: e4.removeAllListeners(); michael@0: assert.equal(0, e4.listeners('hello').length); michael@0: assert.equal(0, e4.listeners('goodbye').length); michael@0: e4.emit("hello", ""); michael@0: e4.emit("goodbye", ""); michael@0: assert.equal(2, count); michael@0: }; michael@0: michael@0: exports['test: modify in emit'] = function(assert) { michael@0: let callbacks_called = [ ]; michael@0: let e = new EventEmitter(); michael@0: michael@0: function callback1() { michael@0: callbacks_called.push("callback1"); michael@0: e.on("foo", callback2); michael@0: e.on("foo", callback3); michael@0: e.removeListener("foo", callback1); michael@0: } michael@0: function callback2() { michael@0: callbacks_called.push("callback2"); michael@0: e.removeListener("foo", callback2); michael@0: } michael@0: function callback3() { michael@0: callbacks_called.push("callback3"); michael@0: e.removeListener("foo", callback3); michael@0: } michael@0: michael@0: e.on("foo", callback1); michael@0: assert.equal(1, e.listeners("foo").length); michael@0: michael@0: e.emit("foo"); michael@0: assert.equal(2, e.listeners("foo").length); michael@0: assert.equal(1, callbacks_called.length); michael@0: assert.equal('callback1', callbacks_called[0]); michael@0: michael@0: e.emit("foo"); michael@0: assert.equal(0, e.listeners("foo").length); michael@0: assert.equal(3, callbacks_called.length); michael@0: assert.equal('callback1', callbacks_called[0]); michael@0: assert.equal('callback2', callbacks_called[1]); michael@0: assert.equal('callback3', callbacks_called[2]); michael@0: michael@0: e.emit("foo"); michael@0: assert.equal(0, e.listeners("foo").length); michael@0: assert.equal(3, callbacks_called.length); michael@0: assert.equal('callback1', callbacks_called[0]); michael@0: assert.equal('callback2', callbacks_called[1]); michael@0: assert.equal('callback3', callbacks_called[2]); michael@0: michael@0: e.on("foo", callback1); michael@0: e.on("foo", callback2); michael@0: assert.equal(2, e.listeners("foo").length); michael@0: e.removeAllListeners("foo"); michael@0: assert.equal(0, e.listeners("foo").length); michael@0: michael@0: // Verify that removing callbacks while in emit allows emits to propagate to michael@0: // all listeners michael@0: callbacks_called = [ ]; michael@0: michael@0: e.on("foo", callback2); michael@0: e.on("foo", callback3); michael@0: assert.equal(2, e.listeners("foo").length); michael@0: e.emit("foo"); michael@0: assert.equal(2, callbacks_called.length); michael@0: assert.equal('callback2', callbacks_called[0]); michael@0: assert.equal('callback3', callbacks_called[1]); michael@0: assert.equal(0, e.listeners("foo").length); michael@0: }; michael@0: michael@0: exports['test:adding same listener'] = function(assert) { michael@0: function foo() {} michael@0: let e = new EventEmitter(); michael@0: e.on("foo", foo); michael@0: e.on("foo", foo); michael@0: assert.equal( michael@0: 1, michael@0: e.listeners("foo").length, michael@0: "listener reregistration is ignored" michael@0: ); michael@0: } michael@0: michael@0: exports['test:errors are reported if listener throws'] = function(assert) { michael@0: let e = new EventEmitter(), michael@0: reported = false; michael@0: e.on('error', function(e) reported = true) michael@0: e.on('boom', function() { throw new Error('Boom!') }); michael@0: e.emit('boom', 3); michael@0: assert.ok(reported, 'error should be reported through event'); michael@0: }; michael@0: michael@0: exports['test:emitOnObject'] = function(assert) { michael@0: let e = new EventEmitter(); michael@0: michael@0: e.on("foo", function() { michael@0: assert.equal(this, e, "`this` should be emitter"); michael@0: }); michael@0: e.emitOnObject(e, "foo"); michael@0: michael@0: e.on("bar", function() { michael@0: assert.equal(this, obj, "`this` should be other object"); michael@0: }); michael@0: let obj = {}; michael@0: e.emitOnObject(obj, "bar"); michael@0: }; michael@0: michael@0: exports['test:once'] = function(assert) { michael@0: let e = new EventEmitter(); michael@0: let called = false; michael@0: michael@0: e.once('foo', function(value) { michael@0: assert.ok(!called, "listener called only once"); michael@0: assert.equal(value, "bar", "correct argument was passed"); michael@0: }); michael@0: michael@0: e.emit('foo', 'bar'); michael@0: e.emit('foo', 'baz'); michael@0: }; michael@0: michael@0: exports["test:removing once"] = function(assert) { michael@0: let e = require("sdk/deprecated/events").EventEmitterTrait.create(); michael@0: e.once("foo", function() { assert.pass("listener was called"); }); michael@0: e.once("error", function() { assert.fail("error event was emitted"); }); michael@0: e._emit("foo", "bug-656684"); michael@0: }; michael@0: michael@0: // Bug 726967: Ensure that `emit` doesn't do an infinite loop when `error` michael@0: // listener throws an exception michael@0: exports['test:emitLoop'] = function(assert) { michael@0: // Override the console for this test so it doesn't log the exception to the michael@0: // test output michael@0: let { loader } = LoaderWithHookedConsole(module); michael@0: michael@0: let EventEmitter = loader.require('sdk/deprecated/events').EventEmitter.compose({ michael@0: listeners: function(type) this._listeners(type), michael@0: emit: function() this._emit.apply(this, arguments), michael@0: emitOnObject: function() this._emitOnObject.apply(this, arguments), michael@0: removeAllListeners: function(type) this._removeAllListeners(type) michael@0: }); michael@0: michael@0: let e = new EventEmitter(); michael@0: michael@0: e.on("foo", function() { michael@0: throw new Error("foo"); michael@0: }); michael@0: michael@0: e.on("error", function() { michael@0: throw new Error("error"); michael@0: }); michael@0: e.emit("foo"); michael@0: michael@0: assert.pass("emit didn't looped"); michael@0: }; michael@0: michael@0: require('sdk/test').run(exports);