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: michael@0: 'use strict'; michael@0: michael@0: const { on, once, off, emit, count } = require('sdk/event/core'); michael@0: const { LoaderWithHookedConsole } = require("sdk/test/loader"); michael@0: michael@0: exports['test add a listener'] = function(assert) { michael@0: let events = [ { name: 'event#1' }, 'event#2' ]; michael@0: let target = { name: 'target' }; michael@0: michael@0: on(target, 'message', function(message) { michael@0: assert.equal(this, target, 'this is a target object'); michael@0: assert.equal(message, events.shift(), 'message is emitted event'); michael@0: }); michael@0: emit(target, 'message', events[0]); michael@0: emit(target, 'message', events[0]); michael@0: }; michael@0: michael@0: exports['test that listener is unique per type'] = function(assert) { michael@0: let actual = [] michael@0: let target = {} michael@0: function listener() { actual.push(1) } michael@0: on(target, 'message', listener); michael@0: on(target, 'message', listener); michael@0: on(target, 'message', listener); michael@0: on(target, 'foo', listener); michael@0: on(target, 'foo', listener); michael@0: michael@0: emit(target, 'message'); michael@0: assert.deepEqual([ 1 ], actual, 'only one message listener added'); michael@0: emit(target, 'foo'); michael@0: assert.deepEqual([ 1, 1 ], actual, 'same listener added for other event'); michael@0: }; michael@0: michael@0: exports['test event type matters'] = function(assert) { michael@0: let target = { name: 'target' } michael@0: on(target, 'message', function() { michael@0: assert.fail('no event is expected'); michael@0: }); michael@0: on(target, 'done', function() { michael@0: assert.pass('event is emitted'); michael@0: }); michael@0: emit(target, 'foo') michael@0: emit(target, 'done'); michael@0: }; michael@0: michael@0: exports['test all arguments are pasesd'] = function(assert) { michael@0: let foo = { name: 'foo' }, bar = 'bar'; michael@0: let target = { name: 'target' }; michael@0: on(target, 'message', function(a, b) { michael@0: assert.equal(a, foo, 'first argument passed'); michael@0: assert.equal(b, bar, 'second argument passed'); michael@0: }); michael@0: emit(target, 'message', foo, bar); michael@0: }; michael@0: michael@0: exports['test no side-effects in emit'] = function(assert) { michael@0: let target = { name: 'target' }; michael@0: on(target, 'message', function() { michael@0: assert.pass('first listener is called'); michael@0: on(target, 'message', function() { michael@0: assert.fail('second listener is called'); michael@0: }); michael@0: }); michael@0: emit(target, 'message'); michael@0: }; michael@0: michael@0: exports['test can remove next listener'] = function(assert) { michael@0: let target = { name: 'target' }; michael@0: function fail() assert.fail('Listener should be removed'); michael@0: michael@0: on(target, 'data', function() { michael@0: assert.pass('first litener called'); michael@0: off(target, 'data', fail); michael@0: }); michael@0: on(target, 'data', fail); michael@0: michael@0: emit(target, 'data', 'hello'); michael@0: }; michael@0: michael@0: exports['test order of propagation'] = function(assert) { michael@0: let actual = []; michael@0: let target = { name: 'target' }; michael@0: on(target, 'message', function() { actual.push(1); }); michael@0: on(target, 'message', function() { actual.push(2); }); michael@0: on(target, 'message', function() { actual.push(3); }); michael@0: emit(target, 'message'); michael@0: assert.deepEqual([ 1, 2, 3 ], actual, 'called in order they were added'); michael@0: }; michael@0: michael@0: exports['test remove a listener'] = function(assert) { michael@0: let target = { name: 'target' }; michael@0: let actual = []; michael@0: on(target, 'message', function listener() { michael@0: actual.push(1); michael@0: on(target, 'message', function() { michael@0: off(target, 'message', listener); michael@0: actual.push(2); michael@0: }) michael@0: }); michael@0: michael@0: emit(target, 'message'); michael@0: assert.deepEqual([ 1 ], actual, 'first listener called'); michael@0: emit(target, 'message'); michael@0: assert.deepEqual([ 1, 1, 2 ], actual, 'second listener called'); michael@0: michael@0: emit(target, 'message'); michael@0: assert.deepEqual([ 1, 1, 2, 2, 2 ], actual, 'first listener removed'); michael@0: }; michael@0: michael@0: exports['test remove all listeners for type'] = function(assert) { michael@0: let actual = []; michael@0: let target = { name: 'target' } michael@0: on(target, 'message', function() { actual.push(1); }); michael@0: on(target, 'message', function() { actual.push(2); }); michael@0: on(target, 'message', function() { actual.push(3); }); michael@0: on(target, 'bar', function() { actual.push('b') }); michael@0: off(target, 'message'); michael@0: michael@0: emit(target, 'message'); michael@0: emit(target, 'bar'); michael@0: michael@0: assert.deepEqual([ 'b' ], actual, 'all message listeners were removed'); michael@0: }; michael@0: michael@0: exports['test remove all listeners'] = function(assert) { michael@0: let actual = []; michael@0: let target = { name: 'target' } michael@0: on(target, 'message', function() { actual.push(1); }); michael@0: on(target, 'message', function() { actual.push(2); }); michael@0: on(target, 'message', function() { actual.push(3); }); michael@0: on(target, 'bar', function() { actual.push('b') }); michael@0: off(target); michael@0: michael@0: emit(target, 'message'); michael@0: emit(target, 'bar'); michael@0: michael@0: assert.deepEqual([], actual, 'all listeners events were removed'); michael@0: }; michael@0: michael@0: exports['test falsy arguments are fine'] = function(assert) { michael@0: let type, listener, actual = []; michael@0: let target = { name: 'target' } michael@0: on(target, 'bar', function() { actual.push(0) }); michael@0: michael@0: off(target, 'bar', listener); michael@0: emit(target, 'bar'); michael@0: assert.deepEqual([ 0 ], actual, '3rd bad ard will keep listeners'); michael@0: michael@0: off(target, type); michael@0: emit(target, 'bar'); michael@0: assert.deepEqual([ 0, 0 ], actual, '2nd bad arg will keep listener'); michael@0: michael@0: off(target, type, listener); michael@0: emit(target, 'bar'); michael@0: assert.deepEqual([ 0, 0, 0 ], actual, '2nd&3rd bad args will keep listener'); michael@0: }; michael@0: michael@0: exports['test error handling'] = function(assert) { michael@0: let target = Object.create(null); michael@0: let error = Error('boom!'); michael@0: michael@0: on(target, 'message', function() { throw error; }) michael@0: on(target, 'error', function(boom) { michael@0: assert.equal(boom, error, 'thrown exception causes error event'); michael@0: }); michael@0: emit(target, 'message'); michael@0: }; michael@0: michael@0: exports['test unhandled exceptions'] = function(assert) { michael@0: let exceptions = []; michael@0: let { loader, messages } = LoaderWithHookedConsole(module); michael@0: michael@0: let { emit, on } = loader.require('sdk/event/core'); michael@0: let target = {}; michael@0: let boom = Error('Boom!'); michael@0: let drax = Error('Draax!!'); michael@0: michael@0: on(target, 'message', function() { throw boom; }); michael@0: michael@0: emit(target, 'message'); michael@0: assert.equal(messages.length, 1, 'Got the first exception'); michael@0: assert.equal(messages[0].type, 'exception', 'The console message is exception'); michael@0: assert.ok(~String(messages[0].msg).indexOf('Boom!'), michael@0: 'unhandled exception is logged'); michael@0: michael@0: on(target, 'error', function() { throw drax; }); michael@0: emit(target, 'message'); michael@0: assert.equal(messages.length, 2, 'Got the second exception'); michael@0: assert.equal(messages[1].type, 'exception', 'The console message is exception'); michael@0: assert.ok(~String(messages[1].msg).indexOf('Draax!'), michael@0: 'error in error handler is logged'); michael@0: }; michael@0: michael@0: exports['test unhandled errors'] = function(assert) { michael@0: let exceptions = []; michael@0: let { loader, messages } = LoaderWithHookedConsole(module); michael@0: michael@0: let { emit, on } = loader.require('sdk/event/core'); michael@0: let target = {}; michael@0: let boom = Error('Boom!'); michael@0: michael@0: emit(target, 'error', boom); michael@0: assert.equal(messages.length, 1, 'Error was logged'); michael@0: assert.equal(messages[0].type, 'exception', 'The console message is exception'); michael@0: assert.ok(~String(messages[0].msg).indexOf('Boom!'), michael@0: 'unhandled exception is logged'); michael@0: }; michael@0: michael@0: michael@0: exports['test count'] = function(assert) { michael@0: let target = {}; michael@0: michael@0: assert.equal(count(target, 'foo'), 0, 'no listeners for "foo" events'); michael@0: on(target, 'foo', function() {}); michael@0: assert.equal(count(target, 'foo'), 1, 'listener registered'); michael@0: on(target, 'foo', function() {}, 2, 'another listener registered'); michael@0: off(target) michael@0: assert.equal(count(target, 'foo'), 0, 'listeners unregistered'); michael@0: }; michael@0: michael@0: exports['test listen to all events'] = function(assert) { michael@0: let actual = []; michael@0: let target = {}; michael@0: michael@0: on(target, 'foo', message => actual.push(message)); michael@0: on(target, '*', (type, ...message) => { michael@0: actual.push([type].concat(message)); michael@0: }); michael@0: michael@0: emit(target, 'foo', 'hello'); michael@0: assert.equal(actual[0], 'hello', michael@0: 'non-wildcard listeners still work'); michael@0: assert.deepEqual(actual[1], ['foo', 'hello'], michael@0: 'wildcard listener called'); michael@0: michael@0: emit(target, 'bar', 'goodbye'); michael@0: assert.deepEqual(actual[2], ['bar', 'goodbye'], michael@0: 'wildcard listener called for unbound event name'); michael@0: }; michael@0: michael@0: require('test').run(exports);