From 09cffecc693136222c323dec87b2eddf85822308 Mon Sep 17 00:00:00 2001 From: Josh Johnson Date: Tue, 7 Nov 2017 12:00:10 +0000 Subject: [PATCH] Add further public method unit tests --- src/scripts/src/choices.js | 95 ++++---- src/scripts/src/choices.test.js | 392 +++++++++++++++++++++++++++++++- 2 files changed, 427 insertions(+), 60 deletions(-) diff --git a/src/scripts/src/choices.js b/src/scripts/src/choices.js index 4f8e05b..bbd9daa 100644 --- a/src/scripts/src/choices.js +++ b/src/scripts/src/choices.js @@ -230,6 +230,47 @@ class Choices { this.initialised = false; } + /** + * Enable interaction with Choices + * @return {Object} Class instance + */ + enable() { + if (!this.initialised) { + return this; + } + + this.passedElement.enable(); + + if (this.containerOuter.isDisabled) { + this._addEventListeners(); + this.input.enable(); + this.containerOuter.enable(); + } + + return this; + } + + /** + * Disable interaction with Choices + * @return {Object} Class instance + * @public + */ + disable() { + if (!this.initialised) { + return this; + } + + this.passedElement.disable(); + + if (!this.containerOuter.isDisabled) { + this._removeEventListeners(); + this.input.disable(); + this.containerOuter.disable(); + } + + return this; + } + /** * Render group choices into a DOM fragment and append to choice list * @param {Array} groups Groups to add to list @@ -504,9 +545,7 @@ class Choices { const groupId = item.groupId; const group = groupId >= 0 ? this.store.getGroupById(groupId) : null; - this.store.dispatch( - highlightItem(id, true), - ); + this.store.dispatch(highlightItem(id, true)); if (runEvent) { const eventResponse = { @@ -701,16 +740,17 @@ class Choices { */ getValue(valueOnly = false) { const items = this.store.getItemsFilteredByActive(); - const selectedItems = []; - items.forEach((item) => { + const values = items.reduce((selectedItems, item) => { const itemValue = valueOnly ? item.value : item; if (this.isTextElement || item.active) { selectedItems.push(itemValue); } - }); - return this.isSelectOneElement ? selectedItems[0] : selectedItems; + return selectedItems; + }, []); + + return this.isSelectOneElement ? values[0] : values; } /** @@ -898,47 +938,6 @@ class Choices { return this; } - /** - * Enable interaction with Choices - * @return {Object} Class instance - */ - enable() { - if (!this.initialised) { - return this; - } - - this.passedElement.enable(); - - if (this.containerOuter.isDisabled) { - this._addEventListeners(); - this.input.enable(); - this.containerOuter.enable(); - } - - return this; - } - - /** - * Disable interaction with Choices - * @return {Object} Class instance - * @public - */ - disable() { - if (!this.initialised) { - return this; - } - - this.passedElement.disable(); - - if (!this.containerOuter.isDisabled) { - this._removeEventListeners(); - this.input.disable(); - this.containerOuter.disable(); - } - - return this; - } - /** * Populate options via ajax callback * @param {Function} fn Function that actually makes an AJAX request diff --git a/src/scripts/src/choices.test.js b/src/scripts/src/choices.test.js index 9a7e1cd..6185496 100644 --- a/src/scripts/src/choices.test.js +++ b/src/scripts/src/choices.test.js @@ -1,9 +1,10 @@ import { expect } from 'chai'; -import { spy } from 'sinon'; +import { spy, stub } from 'sinon'; import Choices from './choices'; +import { EVENTS } from './constants'; -describe('choices', () => { +describe.only('choices', () => { let instance; let passedElement; @@ -22,7 +23,7 @@ describe('choices', () => { }); }); - describe('already initalised', () => { + describe('already initialised', () => { beforeEach(() => { instance.initialised = true; instance.init(); @@ -33,7 +34,7 @@ describe('choices', () => { }); }); - describe('not already initalised', () => { + describe('not already initialised', () => { let createTemplatesSpy; let createInputSpy; let storeSubscribeSpy; @@ -51,6 +52,14 @@ describe('choices', () => { instance.init(); }); + afterEach(() => { + createTemplatesSpy.restore(); + createInputSpy.restore(); + storeSubscribeSpy.restore(); + renderSpy.restore(); + addEventListenersSpy.restore(); + }); + it('sets initialise flag', () => { expect(instance.initialised).to.equal(true); }); @@ -63,8 +72,9 @@ describe('choices', () => { expect(createInputSpy.called).to.equal(true); }); - it('subscribes to store', () => { + it('subscribes to store with render method', () => { expect(storeSubscribeSpy.called).to.equal(true); + expect(storeSubscribeSpy.lastCall.args[0]).to.equal(instance.render); }); it('fires initial render', () => { @@ -91,7 +101,7 @@ describe('choices', () => { instance = new Choices(passedElement); }); - describe('not already initalised', () => { + describe('not already initialised', () => { beforeEach(() => { instance.initialised = false; instance.destroy(); @@ -102,7 +112,7 @@ describe('choices', () => { }); }); - describe('already initalised', () => { + describe('already initialised', () => { let removeEventListenersSpy; let passedElementRevealSpy; let containerOuterRevertSpy; @@ -118,6 +128,12 @@ describe('choices', () => { instance.destroy(); }); + afterEach(() => { + removeEventListenersSpy.restore(); + passedElementRevealSpy.restore(); + containerOuterRevertSpy.restore(); + clearStoreSpy.restore(); + }); it('removes event listeners', () => { expect(removeEventListenersSpy.called).to.equal(true); @@ -129,6 +145,7 @@ describe('choices', () => { it('reverts outer container', () => { expect(containerOuterRevertSpy.called).to.equal(true); + expect(containerOuterRevertSpy.lastCall.args[0]).to.equal(instance.passedElement.element); }); it('clears store', () => { @@ -145,6 +162,361 @@ describe('choices', () => { }); }); + describe('enable', () => { + let passedElementEnableSpy; + let addEventListenersSpy; + let containerOuterEnableSpy; + let inputEnableSpy; + + beforeEach(() => { + addEventListenersSpy = spy(instance, '_addEventListeners'); + passedElementEnableSpy = spy(instance.passedElement, 'enable'); + containerOuterEnableSpy = spy(instance.containerOuter, 'enable'); + inputEnableSpy = spy(instance.input, 'enable'); + }); + + + afterEach(() => { + addEventListenersSpy.restore(); + passedElementEnableSpy.restore(); + containerOuterEnableSpy.restore(); + inputEnableSpy.restore(); + }); + + describe('not already initialised', () => { + let response; + + beforeEach(() => { + instance.initialised = false; + response = instance.enable(); + }); + + it('returns instance', () => { + expect(response).to.equal(instance); + }); + + it('returns early', () => { + expect(passedElementEnableSpy.called).to.equal(false); + expect(addEventListenersSpy.called).to.equal(false); + expect(inputEnableSpy.called).to.equal(false); + expect(containerOuterEnableSpy.called).to.equal(false); + }); + }); + + describe('already initialised', () => { + let response; + + describe('containerOuter enabled', () => { + beforeEach(() => { + instance.initialised = true; + response = instance.enable(); + }); + + it('returns instance', () => { + expect(response).to.equal(instance); + }); + + it('enables passedElement', () => { + expect(passedElementEnableSpy.called).to.equal(true); + }); + }); + + describe('containerOuter disabled', () => { + beforeEach(() => { + instance.initialised = true; + instance.containerOuter.isDisabled = true; + instance.enable(); + }); + + it('adds event listeners', () => { + expect(addEventListenersSpy.called).to.equal(true); + }); + + it('enables input', () => { + expect(inputEnableSpy.called).to.equal(true); + }); + + it('enables containerOuter', () => { + expect(containerOuterEnableSpy.called).to.equal(true); + }); + }); + }); + }); + + describe('disable', () => { + let removeEventListenersSpy; + let passedElementDisableSpy; + let containerOuterDisableSpy; + let inputDisableSpy; + + beforeEach(() => { + removeEventListenersSpy = spy(instance, '_removeEventListeners'); + passedElementDisableSpy = spy(instance.passedElement, 'disable'); + containerOuterDisableSpy = spy(instance.containerOuter, 'disable'); + inputDisableSpy = spy(instance.input, 'disable'); + }); + + + afterEach(() => { + removeEventListenersSpy.restore(); + passedElementDisableSpy.restore(); + containerOuterDisableSpy.restore(); + inputDisableSpy.restore(); + }); + + describe('not already initialised', () => { + let response; + + beforeEach(() => { + instance.initialised = false; + response = instance.disable(); + }); + + it('returns instance', () => { + expect(response).to.equal(instance); + }); + + it('returns early', () => { + expect(removeEventListenersSpy.called).to.equal(false); + expect(passedElementDisableSpy.called).to.equal(false); + expect(containerOuterDisableSpy.called).to.equal(false); + expect(inputDisableSpy.called).to.equal(false); + }); + }); + + describe('already initialised', () => { + let response; + + describe('containerOuter disabled', () => { + beforeEach(() => { + instance.initialised = true; + instance.containerOuter.isDisabled = true; + response = instance.disable(); + }); + + it('returns instance', () => { + expect(response).to.equal(instance); + }); + + it('disables passedElement', () => { + expect(passedElementDisableSpy.called).to.equal(true); + }); + }); + + describe('containerOuter enabled', () => { + beforeEach(() => { + instance.initialised = true; + instance.containerOuter.isDisabled = false; + instance.disable(); + }); + + it('removes event listeners', () => { + expect(removeEventListenersSpy.called).to.equal(true); + }); + + it('disables input', () => { + expect(inputDisableSpy.called).to.equal(true); + }); + + it('enables containerOuter', () => { + expect(containerOuterDisableSpy.called).to.equal(true); + }); + }); + }); + }); + + describe('showDropdown', () => { + let containerOuterOpenSpy; + let dropdownShowSpy; + let inputActivateSpy; + let passedElementTriggerEventStub; + + beforeEach(() => { + containerOuterOpenSpy = spy(instance.containerOuter, 'open'); + dropdownShowSpy = spy(instance.dropdown, 'show'); + inputActivateSpy = spy(instance.input, 'activate'); + passedElementTriggerEventStub = stub(); + + instance.passedElement.triggerEvent = passedElementTriggerEventStub; + }); + + afterEach(() => { + containerOuterOpenSpy.restore(); + dropdownShowSpy.restore(); + inputActivateSpy.restore(); + instance.passedElement.triggerEvent.reset(); + }); + + describe('dropdown active', () => { + let response; + + beforeEach(() => { + instance.dropdown.isActive = true; + response = instance.showDropdown(); + }); + + it('returns this', () => { + expect(response).to.eql(instance); + }); + + it('returns early', () => { + expect(containerOuterOpenSpy.called).to.equal(false); + expect(dropdownShowSpy.called).to.equal(false); + expect(inputActivateSpy.called).to.equal(false); + expect(passedElementTriggerEventStub.called).to.equal(false); + }); + }); + + describe('dropdown inactive', () => { + let response; + beforeEach(() => { + instance.dropdown.isActive = false; + response = instance.showDropdown(); + }); + + it('returns this', () => { + expect(response).to.eql(instance); + }); + + it('opens containerOuter', () => { + expect(containerOuterOpenSpy.called).to.equal(true); + }); + + it('shows dropdown with blurInput flag', () => { + expect(dropdownShowSpy.called).to.equal(true); + }); + + it('activates input', () => { + expect(inputActivateSpy.called).to.equal(true); + }); + + it('triggers event on passedElement', () => { + expect(passedElementTriggerEventStub.called).to.equal(true); + expect(passedElementTriggerEventStub.lastCall.args[0]).to.eql(EVENTS.showDropdown); + expect(passedElementTriggerEventStub.lastCall.args[1]).to.eql({}); + }); + }); + }); + + describe('hideDropdown', () => { + let containerOuterCloseSpy; + let dropdownHideSpy; + let inputDeactivateSpy; + let passedElementTriggerEventStub; + + beforeEach(() => { + containerOuterCloseSpy = spy(instance.containerOuter, 'close'); + dropdownHideSpy = spy(instance.dropdown, 'hide'); + inputDeactivateSpy = spy(instance.input, 'deactivate'); + passedElementTriggerEventStub = stub(); + + instance.passedElement.triggerEvent = passedElementTriggerEventStub; + }); + + afterEach(() => { + containerOuterCloseSpy.restore(); + dropdownHideSpy.restore(); + inputDeactivateSpy.restore(); + instance.passedElement.triggerEvent.reset(); + }); + + describe('dropdown inactive', () => { + let response; + + beforeEach(() => { + instance.dropdown.isActive = false; + response = instance.hideDropdown(); + }); + + it('returns this', () => { + expect(response).to.eql(instance); + }); + + it('returns early', () => { + expect(containerOuterCloseSpy.called).to.equal(false); + expect(dropdownHideSpy.called).to.equal(false); + expect(inputDeactivateSpy.called).to.equal(false); + expect(passedElementTriggerEventStub.called).to.equal(false); + }); + }); + + describe('dropdown active', () => { + let response; + beforeEach(() => { + instance.dropdown.isActive = true; + response = instance.hideDropdown(); + }); + + it('returns this', () => { + expect(response).to.eql(instance); + }); + + it('closes containerOuter', () => { + expect(containerOuterCloseSpy.called).to.equal(true); + }); + + it('hides dropdown with blurInput flag', () => { + expect(dropdownHideSpy.called).to.equal(true); + }); + + it('deactivates input', () => { + expect(inputDeactivateSpy.called).to.equal(true); + }); + + it('triggers event on passedElement', () => { + expect(passedElementTriggerEventStub.called).to.equal(true); + expect(passedElementTriggerEventStub.lastCall.args[0]).to.eql(EVENTS.hideDropdown); + expect(passedElementTriggerEventStub.lastCall.args[1]).to.eql({}); + }); + }); + }); + + describe('toggleDropdown', () => { + let response; + let hideDropdownSpy; + let showDropdownSpy; + + beforeEach(() => { + hideDropdownSpy = spy(instance, 'hideDropdown'); + showDropdownSpy = spy(instance, 'showDropdown'); + }); + + afterEach(() => { + hideDropdownSpy.restore(); + showDropdownSpy.restore(); + }); + + describe('dropdown active', () => { + beforeEach(() => { + instance.dropdown.isActive = true; + response = instance.toggleDropdown(); + }); + + it('hides dropdown', () => { + expect(hideDropdownSpy.called).to.equal(true); + }); + + it('returns instance', () => { + expect(response).to.eql(instance); + }); + }); + + describe('dropdown inactive', () => { + beforeEach(() => { + instance.dropdown.isActive = false; + response = instance.toggleDropdown(); + }); + + it('shows dropdown', () => { + expect(showDropdownSpy.called).to.equal(true); + }); + + it('returns instance', () => { + expect(response).to.eql(instance); + }); + }); + }); + describe('renderGroups', () => {}); describe('renderChoices', () => {}); describe('renderItems', () => {}); @@ -156,19 +528,15 @@ describe('choices', () => { describe('removeItemsByValue', () => {}); describe('removeActiveItems', () => {}); describe('removeHighlightedItems', () => {}); - describe('showDropdown', () => {}); - describe('hideDropdown', () => {}); - describe('toggleDropdown', () => {}); describe('getValue', () => {}); describe('setValue', () => {}); describe('setValueByChoice', () => {}); describe('setChoices', () => {}); describe('clearStore', () => {}); describe('clearInput', () => {}); - describe('disable', () => {}); }); - describe('private methods', () => { + describe.skip('private methods', () => { describe('_triggerChange', () => {}); describe('_selectPlaceholderChoice', () => {}); describe('_handleButtonAction', () => {});