diff --git a/frontend/src/app.spec.js b/frontend/src/app.spec.js index ab7385448..247be9f00 100644 --- a/frontend/src/app.spec.js +++ b/frontend/src/app.spec.js @@ -1,8 +1,15 @@ import { App } from './app'; +import { Utility } from './core/utility'; + +@Utility({ selector: 'util1' }) +class TestUtil1 { } + +@Utility({ selector: 'util2' }) +class TestUtil2 { } const TEST_UTILS = [ - { name: 'util1' }, - { name: 'util2' }, + TestUtil1, + TestUtil2, ]; describe('App', () => { diff --git a/frontend/src/services/util-registry/util-registry.js b/frontend/src/services/util-registry/util-registry.js index 5e71554bc..d96d7a4b3 100644 --- a/frontend/src/services/util-registry/util-registry.js +++ b/frontend/src/services/util-registry/util-registry.js @@ -59,6 +59,8 @@ export class UtilRegistry { console.log('setting up util', { util }); } + let instances = []; + if (util) { const elements = this._findUtilElements(util, scope); @@ -78,10 +80,13 @@ export class UtilRegistry { console.info('Got utility instance for utility "' + util.name + '"', { utilInstance }); } - this._activeUtilInstances.push(utilInstance); + instances.push(utilInstance); } }); } + + this._activeUtilInstances.push(...instances); + return instances; } find(name) { diff --git a/frontend/src/services/util-registry/util-registry.spec.js b/frontend/src/services/util-registry/util-registry.spec.js index 2e4afedf2..5f29f6a3c 100644 --- a/frontend/src/services/util-registry/util-registry.spec.js +++ b/frontend/src/services/util-registry/util-registry.spec.js @@ -1,14 +1,5 @@ -import { UtilRegistry } from "./util-registry"; - -const TEST_UTILS = [{ - name: 'util1', - selector: '#some-id', - setup: () => {}, -}, { - name: 'util2', - selector: '[uw-util]', - setup: () => {}, -}]; +import { UtilRegistry } from './util-registry'; +import { Utility } from '../../core/utility'; describe('UtilRegistry', () => { let utilRegistry; @@ -23,23 +14,26 @@ describe('UtilRegistry', () => { describe('register()', () => { it('should allow to add utilities', () => { - utilRegistry.register(TEST_UTILS[0]); + let foundUtil = utilRegistry.find(TestUtil1.name); + expect(foundUtil).toBeFalsy(); - const foundUtil = utilRegistry.find(TEST_UTILS[0].name); - expect(foundUtil).toEqual(TEST_UTILS[0]); + utilRegistry.register(TestUtil1); + + foundUtil = utilRegistry.find(TestUtil1.name); + expect(foundUtil).toEqual(TestUtil1); }); }); describe('deregister()', () => { it('should remove util', () => { // register util - utilRegistry.register(TEST_UTILS[0]); - let foundUtil = utilRegistry.find('util1'); + utilRegistry.register(TestUtil1); + let foundUtil = utilRegistry.find(TestUtil1.name); expect(foundUtil).toBeTruthy(); // deregister util - utilRegistry.deregister(TEST_UTILS[0].name); - foundUtil = utilRegistry.find('util1'); + utilRegistry.deregister(TestUtil1.name); + foundUtil = utilRegistry.find(TestUtil1.name); expect(foundUtil).toBeFalsy(); }); @@ -49,55 +43,62 @@ describe('UtilRegistry', () => { }); describe('setup()', () => { + it('should catch errors thrown by the utility', () => { - spyOn(TEST_UTILS[0], 'setup').and.throwError('some error'); expect(() => { - utilRegistry.setup(TEST_UTILS[0]); + utilRegistry.setup(ThrowingUtil); }).not.toThrow(); }); - it('should pass the app instance', () => { - const scope = document.createElement('div'); - const utilElement = document.createElement('div'); - utilElement.id = 'some-id'; - scope.appendChild(utilElement); - const fakeApp = { fn: () => {} }; - utilRegistry.setApp(fakeApp); - spyOn(TEST_UTILS[0], 'setup'); - utilRegistry.setup(TEST_UTILS[0], scope); - expect(TEST_UTILS[0].setup).toHaveBeenCalledWith(utilElement, fakeApp); - }); + describe('scope has no matching elements', () => { + it('should not construct an instance', () => { + const scope = document.createElement('div'); + const instances = utilRegistry.setup(TestUtil1, scope); + expect(instances.length).toBe(0); + }); - describe('given no scope', () => { it('should use fallback scope', () => { - spyOn(TEST_UTILS[0], 'setup'); - utilRegistry.setup(TEST_UTILS[0]); - expect(TEST_UTILS[0].setup).not.toHaveBeenCalled(); + const instances = utilRegistry.setup(TestUtil1); + expect(instances.length).toBe(0); }); }); - describe('given a scope', () => { - let scope; - let utilElement1; - let utilElement2; + describe('scope has matching elements', () => { + let testScope; + let testElement1; + let testElement2; beforeEach(() => { - scope = document.createElement('div'); - utilElement1 = document.createElement('div'); - utilElement2 = document.createElement('div'); - utilElement1.setAttribute('uw-util', ''); - utilElement2.setAttribute('uw-util', ''); - scope.appendChild(utilElement1); - scope.appendChild(utilElement2); + testScope = document.createElement('div'); + testElement1 = document.createElement('div'); + testElement2 = document.createElement('div'); + testElement1.classList.add('util1'); + testElement2.classList.add('util1'); + testScope.appendChild(testElement1); + testScope.appendChild(testElement2); }); - it('should call the utilities\' setup function for each matching element', () => { - spyOn(TEST_UTILS[1], 'setup'); - utilRegistry.setup(TEST_UTILS[1], scope); - // 2 matching elements in scope - expect(TEST_UTILS[1].setup.calls.count()).toBe(2); - expect(TEST_UTILS[1].setup.calls.argsFor(0)).toEqual([utilElement1, undefined]); - expect(TEST_UTILS[1].setup.calls.argsFor(1)).toEqual([utilElement2, undefined]); + it('should construct a utility instance', () => { + const setupUtilities = utilRegistry.setup(TestUtil1, testScope); + expect(setupUtilities).toBeTruthy(); + expect(setupUtilities[0]).toBeTruthy(); + }); + + it('should construct an instance for each matching element', () => { + const setupUtilities = utilRegistry.setup(TestUtil1, testScope); + expect(setupUtilities).toBeTruthy(); + expect(setupUtilities[0].element).toBe(testElement1); + expect(setupUtilities[1].element).toBe(testElement2); + }); + + it('should pass the app instance', () => { + const fakeApp = { }; + utilRegistry.setApp(fakeApp); + + const setupUtilities = utilRegistry.setup(TestUtil1, testScope); + expect(setupUtilities).toBeTruthy(); + expect(setupUtilities[0].app).toBe(fakeApp); + expect(setupUtilities[1].app).toBe(fakeApp); }); }); }); @@ -105,22 +106,41 @@ describe('UtilRegistry', () => { describe('setupAll()', () => { it('should setup all the utilities', () => { spyOn(utilRegistry, 'setup'); - utilRegistry.register(TEST_UTILS[0]); - utilRegistry.register(TEST_UTILS[1]); + utilRegistry.register(TestUtil1); + utilRegistry.register(TestUtil2); utilRegistry.setupAll(); expect(utilRegistry.setup.calls.count()).toBe(2); - expect(utilRegistry.setup.calls.argsFor(0)).toEqual([TEST_UTILS[0], undefined]); - expect(utilRegistry.setup.calls.argsFor(1)).toEqual([TEST_UTILS[1], undefined]); + expect(utilRegistry.setup.calls.argsFor(0)).toEqual([TestUtil1, undefined]); + expect(utilRegistry.setup.calls.argsFor(1)).toEqual([TestUtil2, undefined]); }); it('should pass the given scope', () => { spyOn(utilRegistry, 'setup'); - utilRegistry.register(TEST_UTILS[0]); + utilRegistry.register(TestUtil1); const scope = document.createElement('div'); utilRegistry.setupAll(scope); - expect(utilRegistry.setup).toHaveBeenCalledWith(TEST_UTILS[0], scope); + expect(utilRegistry.setup).toHaveBeenCalledWith(TestUtil1, scope); }); }); }); + +// test utilities +@Utility({ selector: '.util1' }) +class TestUtil1 { + constructor(element, app) { + this.element = element; + this.app = app; + } +} + +@Utility({ selector: '#util2' }) +class TestUtil2 { } + +@Utility({ selector: '#throws' }) +class ThrowingUtil { + constructor() { + throw new Error(); + } + }