// Copyright 2020 Signal Messenger, LLC // SPDX-License-Identifier: AGPL-3.0-only import { assert } from 'chai'; import * as sinon from 'sinon'; import { EventEmitter } from 'events'; import { ActiveWindowService } from '../../services/ActiveWindowService'; describe('ActiveWindowService', () => { const fakeIpcEvent = {}; beforeEach(function beforeEach() { this.clock = sinon.useFakeTimers({ now: 1000 }); }); afterEach(function afterEach() { this.clock.restore(); }); function createFakeDocument() { return document.createElement('div'); } it('is inactive at the start', () => { const service = new ActiveWindowService(); service.initialize(createFakeDocument(), new EventEmitter()); assert.isFalse(service.isActive()); }); it('becomes active after focusing', () => { const fakeIpc = new EventEmitter(); const service = new ActiveWindowService(); service.initialize(createFakeDocument(), fakeIpc); fakeIpc.emit('set-window-focus', fakeIpcEvent, true); assert.isTrue(service.isActive()); }); it('becomes inactive after 15 seconds without interaction', function test() { const fakeIpc = new EventEmitter(); const service = new ActiveWindowService(); service.initialize(createFakeDocument(), fakeIpc); fakeIpc.emit('set-window-focus', fakeIpcEvent, true); this.clock.tick(5000); assert.isTrue(service.isActive()); this.clock.tick(9999); assert.isTrue(service.isActive()); this.clock.tick(1); assert.isFalse(service.isActive()); }); ['click', 'keydown', 'mousedown', 'mousemove', 'touchstart', 'wheel'].forEach( (eventName: string) => { it(`is inactive even in the face of ${eventName} events if unfocused`, function test() { const fakeDocument = createFakeDocument(); const fakeIpc = new EventEmitter(); const service = new ActiveWindowService(); service.initialize(fakeDocument, fakeIpc); fakeIpc.emit('set-window-focus', fakeIpcEvent, false); fakeDocument.dispatchEvent(new Event(eventName)); assert.isFalse(service.isActive()); }); it(`stays active if focused and receiving ${eventName} events`, function test() { const fakeDocument = createFakeDocument(); const fakeIpc = new EventEmitter(); const service = new ActiveWindowService(); service.initialize(fakeDocument, fakeIpc); fakeIpc.emit('set-window-focus', fakeIpcEvent, true); fakeDocument.dispatchEvent(new Event(eventName)); assert.isTrue(service.isActive()); this.clock.tick(8000); fakeDocument.dispatchEvent(new Event(eventName)); assert.isTrue(service.isActive()); this.clock.tick(8000); fakeDocument.dispatchEvent(new Event(eventName)); assert.isTrue(service.isActive()); }); } ); it('calls callbacks when going from unfocused to focused', () => { const fakeIpc = new EventEmitter(); const service = new ActiveWindowService(); service.initialize(createFakeDocument(), fakeIpc); const callback = sinon.stub(); service.registerForActive(callback); fakeIpc.emit('set-window-focus', fakeIpcEvent, true); sinon.assert.calledOnce(callback); }); it('calls callbacks when receiving a click event after being focused', function test() { const fakeDocument = createFakeDocument(); const fakeIpc = new EventEmitter(); const service = new ActiveWindowService(); service.initialize(fakeDocument, fakeIpc); fakeIpc.emit('set-window-focus', fakeIpcEvent, true); this.clock.tick(20000); const callback = sinon.stub(); service.registerForActive(callback); fakeDocument.dispatchEvent(new Event('click')); sinon.assert.calledOnce(callback); }); it('only calls callbacks every 5 seconds; it is throttled', function test() { const fakeIpc = new EventEmitter(); const service = new ActiveWindowService(); service.initialize(createFakeDocument(), fakeIpc); const callback = sinon.stub(); service.registerForActive(callback); fakeIpc.emit('set-window-focus', fakeIpcEvent, true); fakeIpc.emit('set-window-focus', fakeIpcEvent, false); fakeIpc.emit('set-window-focus', fakeIpcEvent, true); fakeIpc.emit('set-window-focus', fakeIpcEvent, false); fakeIpc.emit('set-window-focus', fakeIpcEvent, true); fakeIpc.emit('set-window-focus', fakeIpcEvent, false); sinon.assert.calledOnce(callback); this.clock.tick(15000); fakeIpc.emit('set-window-focus', fakeIpcEvent, true); sinon.assert.calledTwice(callback); }); it('can remove callbacks', () => { const fakeDocument = createFakeDocument(); const fakeIpc = new EventEmitter(); const service = new ActiveWindowService(); service.initialize(fakeDocument, fakeIpc); const callback = sinon.stub(); service.registerForActive(callback); service.unregisterForActive(callback); fakeIpc.emit('set-window-focus', fakeIpcEvent, true); sinon.assert.notCalled(callback); }); });