VulpesOS/gaia/apps/sharedtest/test/unit/event_dispatcher_test.js
OverSu b38dea0597 Publish Vulpes Preview 15 sources for desktop, Android and Tundra
Share Gaia assets and adapters, keep private profiles and development documents local, and update both public READMEs.
2026-09-30 23:13:03 +02:00

475 lines
15 KiB
JavaScript
Executable file

/*global EventDispatcher,
Set
*/
'use strict';
require('/shared/js/event_dispatcher.js');
suite('EventDispatcher >', function() {
var originalObject = {
property: 3,
method: () => {}
};
var originalRestrictedObject = {
property: 3,
method: () => {}
};
var allowedEvents = ['allowed-event-1', 'allowed-event-2'];
var eventTarget = null,
restrictedEventTarget = null;
suiteSetup(function() {
eventTarget = EventDispatcher.mixin(originalObject);
restrictedEventTarget = EventDispatcher.mixin(
originalRestrictedObject,
allowedEvents
);
});
teardown(function() {
eventTarget.offAll();
});
suite('mixin >', function() {
test('throws if object to mix into is not valid object', function() {
assert.throws(() => EventDispatcher.mixin());
assert.throws(() => EventDispatcher.mixin(null));
assert.throws(() => EventDispatcher.mixin(() => {}));
assert.throws(() => EventDispatcher.mixin(3));
});
test('throws if object to mix into already has dispatcher methods',
function() {
var CustomClass = function() {};
EventDispatcher.mixin(CustomClass.prototype);
assert.throws(() => EventDispatcher.mixin({ on: () => {} }));
assert.throws(() => EventDispatcher.mixin({ on: null }));
assert.throws(() => EventDispatcher.mixin({ off: () => {} }));
assert.throws(() => EventDispatcher.mixin({ off: 'day off' }));
assert.throws(() => EventDispatcher.mixin({ offAll: () => {} }));
assert.throws(() => EventDispatcher.mixin({ emit: () => {} }));
assert.throws(() => EventDispatcher.mixin(new CustomClass()));
assert.throws(() => EventDispatcher.mixin(EventDispatcher.mixin({})));
});
test('throws if invalid array is passed for allowedEvents', function() {
assert.throws(() => EventDispatcher.mixin({}, null));
assert.throws(() => EventDispatcher.mixin({}, 'event'));
assert.throws(() => EventDispatcher.mixin({}, new Set()));
});
test('correctly adds methods to target object', function() {
assert.equal(typeof eventTarget.on, 'function');
assert.equal(typeof eventTarget.off, 'function');
assert.equal(typeof eventTarget.offAll, 'function');
assert.equal(typeof eventTarget.emit, 'function');
assert.strictEqual(eventTarget, originalObject);
assert.strictEqual(eventTarget.method, originalObject.method);
assert.strictEqual(eventTarget.property, originalObject.property);
});
});
suite('on >', function() {
test('throws if event name is not valid string', function() {
assert.throws(() => eventTarget.on());
assert.throws(() => eventTarget.on('', () => {}));
assert.throws(() => eventTarget.on(null, () => {}));
});
test('throws if handler is not function', function() {
assert.throws(() => eventTarget.on('event'));
assert.throws(() => eventTarget.on('event', null));
assert.throws(() => eventTarget.on('event', {}));
});
test('successfully registers handler', function() {
var expectedHandler = sinon.stub(),
unexpectedHandler = sinon.stub();
eventTarget.on('not-expected-event', unexpectedHandler);
eventTarget.on('event', expectedHandler);
eventTarget.emit('event');
sinon.assert.calledOnce(expectedHandler);
eventTarget.emit('event');
sinon.assert.calledTwice(expectedHandler);
sinon.assert.notCalled(unexpectedHandler);
});
test('successfully registers multiple handlers', function() {
var expectedHandler1 = sinon.stub(),
expectedHandler2 = sinon.stub(),
unexpectedHandler = sinon.stub();
eventTarget.on('not-expected-event', unexpectedHandler);
eventTarget.on('event', expectedHandler1);
eventTarget.on('event', expectedHandler2);
eventTarget.emit('event');
sinon.assert.notCalled(unexpectedHandler);
sinon.assert.calledOnce(expectedHandler1);
sinon.assert.calledOnce(expectedHandler2);
sinon.assert.callOrder(expectedHandler1, expectedHandler2);
});
suite('with allowed events >', function() {
test('throws if event name is not allowed', function() {
assert.throws(() => restrictedEventTarget.on('event'));
});
test('successfully registers handler for allowed event', function() {
var expectedHandler = sinon.stub(),
unexpectedHandler = sinon.stub();
restrictedEventTarget.on('allowed-event-2', unexpectedHandler);
restrictedEventTarget.on('allowed-event-1', expectedHandler);
restrictedEventTarget.emit('allowed-event-1');
sinon.assert.calledOnce(expectedHandler);
restrictedEventTarget.emit('allowed-event-1');
sinon.assert.calledTwice(expectedHandler);
sinon.assert.notCalled(unexpectedHandler);
});
});
});
suite('once >', function() {
test('throws if event name is not valid string', function() {
assert.throws(() => eventTarget.once());
assert.throws(() => eventTarget.once('', () => {}));
assert.throws(() => eventTarget.once(null, () => {}));
});
test('throws if handler is not function', function() {
assert.throws(() => eventTarget.once('event'));
assert.throws(() => eventTarget.once('event', null));
assert.throws(() => eventTarget.once('event', {}));
});
test('successfully registers handler', function() {
var expectedHandler = sinon.stub(),
unexpectedHandler = sinon.stub();
eventTarget.once('not-expected-event', unexpectedHandler);
eventTarget.once('event', expectedHandler);
eventTarget.emit('event');
sinon.assert.calledOnce(expectedHandler);
// Should not call handler more than once.
eventTarget.emit('event');
sinon.assert.calledOnce(expectedHandler);
sinon.assert.notCalled(unexpectedHandler);
});
test('successfully registers multiple handlers', function() {
var expectedHandler1 = sinon.stub(),
expectedHandler2 = sinon.stub(),
unexpectedHandler = sinon.stub();
eventTarget.once('not-expected-event', unexpectedHandler);
eventTarget.once('event', expectedHandler1);
eventTarget.once('event', expectedHandler2);
eventTarget.emit('event');
sinon.assert.notCalled(unexpectedHandler);
sinon.assert.calledOnce(expectedHandler1);
sinon.assert.calledOnce(expectedHandler2);
sinon.assert.callOrder(expectedHandler1, expectedHandler2);
});
test('correctly passes parameters', function() {
var handler = sinon.stub();
eventTarget.once('event', handler);
eventTarget.emit('event');
sinon.assert.calledOnce(handler);
sinon.assert.calledWithExactly(handler, undefined);
eventTarget.once('event', handler);
eventTarget.emit('event', { a: 'b' });
sinon.assert.calledTwice(handler);
sinon.assert.calledWithExactly(handler, { a: 'b' });
});
suite('with allowed events >', function() {
test('throws if event name is not allowed', function() {
assert.throws(() => restrictedEventTarget.once('event'));
});
test('successfully registers handler for allowed event', function() {
var expectedHandler = sinon.stub(),
unexpectedHandler = sinon.stub();
restrictedEventTarget.once('allowed-event-2', unexpectedHandler);
restrictedEventTarget.once('allowed-event-1', expectedHandler);
restrictedEventTarget.emit('allowed-event-1');
sinon.assert.calledOnce(expectedHandler);
// Should not call handler more than once.
restrictedEventTarget.emit('allowed-event-1');
sinon.assert.calledOnce(expectedHandler);
sinon.assert.notCalled(unexpectedHandler);
});
});
});
suite('off >', function() {
test('throws if event name is not valid string', function() {
assert.throws(() => eventTarget.off());
assert.throws(() => eventTarget.off('', () => {}));
assert.throws(() => eventTarget.off(null, () => {}));
});
test('throws if handler is not function', function() {
assert.throws(() => eventTarget.off('event'));
assert.throws(() => eventTarget.off('event', null));
assert.throws(() => eventTarget.off('event', {}));
});
test('successfully unregisters handler', function() {
var handler = sinon.stub();
eventTarget.on('event', handler);
eventTarget.emit('event');
sinon.assert.calledOnce(handler);
eventTarget.off('event', handler);
eventTarget.emit('event');
sinon.assert.calledOnce(handler);
});
test('unregisters correct handler', function() {
var handler1 = sinon.stub(),
handler2 = sinon.stub(),
handler3 = sinon.stub();
eventTarget.on('event', handler1);
eventTarget.on('event', handler2);
eventTarget.emit('event');
sinon.assert.calledOnce(handler1);
sinon.assert.calledOnce(handler2);
eventTarget.off('event', handler3);
eventTarget.emit('event');
sinon.assert.calledTwice(handler1);
sinon.assert.calledTwice(handler2);
eventTarget.off('event', handler1);
eventTarget.emit('event');
sinon.assert.calledTwice(handler1);
sinon.assert.calledThrice(handler2);
eventTarget.off('event', handler2);
eventTarget.emit('event');
sinon.assert.calledTwice(handler1);
sinon.assert.calledThrice(handler2);
});
suite('with allowed events >', function() {
test('throws if event name is not allowed', function() {
assert.throws(() => restrictedEventTarget.off('event'));
});
test('successfully unregisters handler for allowed event', function() {
var handler = sinon.stub();
restrictedEventTarget.on('allowed-event-1', handler);
restrictedEventTarget.emit('allowed-event-1');
sinon.assert.calledOnce(handler);
restrictedEventTarget.off('allowed-event-1', handler);
restrictedEventTarget.emit('allowed-event-1');
sinon.assert.calledOnce(handler);
});
});
});
suite('offAll >', function() {
test('throws if event name is not valid string', function() {
assert.throws(() => eventTarget.offAll(''));
assert.throws(() => eventTarget.offAll(null));
});
test('unregisters all handlers for a specific event', function() {
var handler1 = sinon.stub(),
handler2 = sinon.stub();
eventTarget.on('event', handler1);
eventTarget.on('event', handler2);
eventTarget.emit('event');
sinon.assert.calledOnce(handler1);
sinon.assert.calledOnce(handler2);
eventTarget.offAll('other-event');
eventTarget.emit('event');
sinon.assert.calledTwice(handler1);
sinon.assert.calledTwice(handler2);
eventTarget.offAll('event');
eventTarget.emit('event');
sinon.assert.calledTwice(handler1);
sinon.assert.calledTwice(handler2);
});
test('unregisters all handlers for all events', function() {
var handler1 = sinon.stub();
var handler2 = sinon.stub();
var handler3 = sinon.stub();
eventTarget.on('event-1', handler1);
eventTarget.on('event-1', handler2);
eventTarget.on('event-2', handler3);
eventTarget.offAll();
eventTarget.emit('event-1');
eventTarget.emit('event-2');
sinon.assert.notCalled(handler1);
sinon.assert.notCalled(handler2);
sinon.assert.notCalled(handler3);
});
suite('with allowed events >', function() {
test('throws if event name is not allowed', function() {
assert.throws(() => restrictedEventTarget.offAll('event'));
});
test('successfully unregisters all handlers for allowed event',
function() {
var handler1 = sinon.stub(),
handler2 = sinon.stub();
restrictedEventTarget.on('allowed-event-1', handler1);
restrictedEventTarget.on('allowed-event-1', handler2);
restrictedEventTarget.emit('allowed-event-1');
sinon.assert.calledOnce(handler1);
sinon.assert.calledOnce(handler2);
restrictedEventTarget.offAll('allowed-event-2');
restrictedEventTarget.emit('allowed-event-1');
sinon.assert.calledTwice(handler1);
sinon.assert.calledTwice(handler2);
restrictedEventTarget.offAll('allowed-event-1');
restrictedEventTarget.emit('allowed-event-1');
sinon.assert.calledTwice(handler1);
sinon.assert.calledTwice(handler2);
});
});
});
suite('emit >', function() {
test('throws if event name is not valid string', function() {
assert.throws(() => eventTarget.emit());
assert.throws(() => eventTarget.emit('', {}));
assert.throws(() => eventTarget.emit(null, {}));
});
test('execute all handlers in the right order', function() {
var expectedHandler1 = sinon.stub(),
expectedHandler2 = sinon.stub(),
unexpectedHandler = sinon.stub();
eventTarget.on('event', expectedHandler1);
eventTarget.on('event', expectedHandler2);
eventTarget.on('other-event', unexpectedHandler);
eventTarget.emit('event');
sinon.assert.notCalled(unexpectedHandler);
sinon.assert.calledOnce(expectedHandler1);
sinon.assert.calledOnce(expectedHandler2);
sinon.assert.callOrder(expectedHandler1, expectedHandler2);
});
test('passes correct parameters to the handlers', function() {
var handler1 = sinon.stub(),
handler2 = sinon.stub(),
handler3 = sinon.stub();
var parameters1 = {
id: 1
};
var parameters2 = 'hello!';
eventTarget.on('event', handler1);
eventTarget.on('event-1', handler2);
eventTarget.on('other-event', handler3);
eventTarget.emit('event', parameters1);
eventTarget.emit('event-1', parameters2);
eventTarget.emit('other-event');
sinon.assert.calledWith(handler1, parameters1);
sinon.assert.calledWith(handler2, parameters2);
sinon.assert.calledWith(handler3, undefined);
});
test('execute all handlers even if exception occurs', function() {
var handler1 = sinon.stub().throws('Type Error'),
handler2 = sinon.stub();
eventTarget.on('event', handler1);
eventTarget.on('event', handler2);
eventTarget.emit('event');
sinon.assert.calledOnce(handler1);
sinon.assert.calledOnce(handler2);
sinon.assert.callOrder(handler1, handler2);
});
suite('with allowed events >', function() {
test('throws if event name is not allowed', function() {
assert.throws(() => restrictedEventTarget.emit('event'));
});
test('execute all handlers for allowed event in the right order',
function() {
var expectedHandler1 = sinon.stub(),
expectedHandler2 = sinon.stub(),
unexpectedHandler = sinon.stub();
restrictedEventTarget.on('allowed-event-1', expectedHandler1);
restrictedEventTarget.on('allowed-event-1', expectedHandler2);
restrictedEventTarget.on('allowed-event-2', unexpectedHandler);
restrictedEventTarget.emit('allowed-event-1');
sinon.assert.notCalled(unexpectedHandler);
sinon.assert.calledOnce(expectedHandler1);
sinon.assert.calledOnce(expectedHandler2);
sinon.assert.callOrder(expectedHandler1, expectedHandler2);
});
});
});
});