From 4666e33845870719487e55744c4491c1124810a1 Mon Sep 17 00:00:00 2001 From: Josh Johnson Date: Sun, 8 Oct 2017 15:52:54 +0100 Subject: [PATCH] Export default state with reducer --- package.json | 2 +- src/scripts/src/choices.spec.js | 1182 --------------------------- src/scripts/src/reducers/choices.js | 8 +- src/scripts/src/reducers/groups.js | 8 +- src/scripts/src/reducers/items.js | 8 +- 5 files changed, 13 insertions(+), 1195 deletions(-) delete mode 100644 src/scripts/src/choices.spec.js diff --git a/package.json b/package.json index 2d10100..0809698 100644 --- a/package.json +++ b/package.json @@ -7,7 +7,7 @@ "scripts": { "start": "node server.js", "lint": "eslint assets/**/*.js", - "test": "nyc mocha --require ./config/test.js --compilers babel-core/register \"./src/**/**/**/**/*.spec.js\"", + "test": "nyc mocha --require ./config/test.js --compilers babel-core/register \"./src/**/**/**/**/*.test.js\"", "test:watch": "npm run test -- --watch", "css:watch": "nodemon -e scss -x \"npm run css:build\"", "css:build": "npm run css:sass -s && npm run css:prefix -s && npm run css:min -s", diff --git a/src/scripts/src/choices.spec.js b/src/scripts/src/choices.spec.js deleted file mode 100644 index 37bf1d5..0000000 --- a/src/scripts/src/choices.spec.js +++ /dev/null @@ -1,1182 +0,0 @@ -import 'whatwg-fetch'; -import 'es6-promise'; -import 'core-js/fn/object/assign'; -import 'custom-event-autopolyfill'; -import { expect } from 'chai'; -import sinon from 'sinon'; - -import Choices from './choices'; -import itemReducer from './reducers/items'; -import choiceReducer from './reducers/choices'; -import { - addItem as addItemAction, - addChoice as addChoiceAction, -} from './actions/actions'; -import Dropdown from './components/dropdown'; -import Container from './components/container'; -import Input from './components/input'; -import List from './components/list'; - -describe('Choices', () => { - describe('should initialize Choices', () => { - let input; - let instance; - - beforeEach(() => { - input = document.createElement('input'); - input.type = 'text'; - input.className = 'js-choices'; - - document.body.appendChild(input); - instance = new Choices(input); - }); - - afterEach(() => { - instance.destroy(); - }); - - it('should be defined', () => { - expect(instance).not.be.undefined; - }); - - it('should have initialised', () => { - expect(instance.initialised).to.be.true; - }); - - it('should not re-initialise if passed element again', () => { - const reinitialise = new Choices(instance.passedElement); - sinon.spy(reinitialise, '_createTemplates'); - expect(reinitialise._createTemplates.callCount).to.equal(0); - }); - - it('should have a blank state', () => { - expect(instance.currentState.items.length).to.equal(0); - expect(instance.currentState.groups.length).to.equal(0); - expect(instance.currentState.choices.length).to.equal(0); - }); - - it('should have config options', () => { - expect(instance.config.silent).to.be.a('boolean'); - expect(instance.config.items).to.be.an('array'); - expect(instance.config.choices).to.be.an('array'); - expect(instance.config.renderChoiceLimit).to.be.a('number'); - expect(instance.config.maxItemCount).to.be.a('number'); - expect(instance.config.addItems).to.be.a('boolean'); - expect(instance.config.removeItems).to.be.a('boolean'); - expect(instance.config.removeItemButton).to.be.a('boolean'); - expect(instance.config.editItems).to.be.a('boolean'); - expect(instance.config.duplicateItems).to.be.a('boolean'); - expect(instance.config.delimiter).to.be.a('string'); - expect(instance.config.paste).to.be.a('boolean'); - expect(instance.config.searchEnabled).to.be.a('boolean'); - expect(instance.config.searchChoices).to.be.a('boolean'); - expect(instance.config.searchFloor).to.be.a('number'); - expect(instance.config.searchResultLimit).to.be.a('number'); - // expect(instance.config.searchFields).to.equal(jasmine.any(Array) || jasmine.any(String)); - expect(instance.config.position).to.be.a('string'); - expect(instance.config.regexFilter).to.be.null; - expect(instance.config.sortFilter).to.be.a('function'); - expect(instance.config.shouldSort).to.be.a('boolean'); - expect(instance.config.shouldSortItems).to.be.a('boolean'); - expect(instance.config.placeholder).to.be.a('boolean'); - expect(instance.config.placeholderValue).to.be.null; - expect(instance.config.prependValue).to.be.null; - expect(instance.config.appendValue).to.be.null; - expect(instance.config.renderSelectedChoices).to.be.a('string'); - expect(instance.config.loadingText).to.be.a('string'); - expect(instance.config.noResultsText).to.be.a('string'); - expect(instance.config.noChoicesText).to.be.a('string'); - expect(instance.config.itemSelectText).to.be.a('string'); - expect(instance.config.classNames).to.be.an('object'); - expect(instance.config.callbackOnInit).to.be.null; - expect(instance.config.callbackOnCreateTemplates).to.be.null; - }); - - it('should expose public methods', () => { - expect(instance.init).to.be.a('function'); - expect(instance.destroy).to.be.a('function'); - expect(instance.render).to.be.a('function'); - expect(instance.renderGroups).to.be.a('function'); - expect(instance.renderItems).to.be.a('function'); - expect(instance.renderChoices).to.be.a('function'); - expect(instance.highlightItem).to.be.a('function'); - expect(instance.unhighlightItem).to.be.a('function'); - expect(instance.highlightAll).to.be.a('function'); - expect(instance.unhighlightAll).to.be.a('function'); - expect(instance.removeItemsByValue).to.be.a('function'); - expect(instance.removeActiveItems).to.be.a('function'); - expect(instance.removeHighlightedItems).to.be.a('function'); - expect(instance.showDropdown).to.be.a('function'); - expect(instance.hideDropdown).to.be.a('function'); - expect(instance.toggleDropdown).to.be.a('function'); - expect(instance.getValue).to.be.a('function'); - expect(instance.setValue).to.be.a('function'); - expect(instance.setValueByChoice).to.be.a('function'); - expect(instance.setChoices).to.be.a('function'); - expect(instance.disable).to.be.a('function'); - expect(instance.enable).to.be.a('function'); - expect(instance.ajax).to.be.a('function'); - expect(instance.clearStore).to.be.a('function'); - expect(instance.clearInput).to.be.a('function'); - }); - - it('should hide passed input', () => { - expect(instance.passedElement.style.display).to.equal('none'); - }); - - it('should create an outer container', () => { - expect(instance.containerOuter).to.be.an.instanceof(Container); - }); - - it('should create an inner container', () => { - expect(instance.containerInner).to.be.an.instanceof(Container); - }); - - it('should create a choice list', () => { - expect(instance.choiceList).to.be.an.instanceof(List); - }); - - it('should create an item list', () => { - expect(instance.itemList).to.be.an.instanceof(List); - }); - - it('should create an input', () => { - expect(instance.input).to.be.an.instanceof(Input); - }); - - it('should create a dropdown', () => { - expect(instance.dropdown).to.be.an.instanceof(Dropdown); - }); - - it('should backup and recover original styles', () => { - const origStyle = 'background-color: #ccc; margin: 5px padding: 10px;'; - - instance.destroy(); - input.setAttribute('style', origStyle); - instance = new Choices(input); - - let style = input.getAttribute('data-choice-orig-style'); - expect(style).to.equal(origStyle); - - instance.destroy(); - style = input.getAttribute('data-choice-orig-style'); - expect(style).to.be.null; - - style = input.getAttribute('style'); - expect(style).to.equal(origStyle); - }); - }); - - describe('should accept text inputs', () => { - let input; - let instance; - - beforeEach(() => { - input = document.createElement('input'); - input.type = 'text'; - input.className = 'js-choices'; - input.placeholder = 'Placeholder text'; - - document.body.appendChild(input); - }); - - afterEach(() => { - instance.destroy(); - }); - - it('should accept a user inputted value', () => { - instance = new Choices(input); - - instance.input.element.focus(); - instance.input.element.value = 'test'; - - instance._onKeyDown({ - target: instance.input.element, - keyCode: 13, - ctrlKey: false, - }); - - expect(instance.currentState.items[0].value).to.include(instance.input.element.value); - }); - - it('should copy the passed placeholder to the cloned input', () => { - instance = new Choices(input); - - expect(instance.input.element.placeholder).to.equal(input.placeholder); - }); - - it('should not allow duplicates if duplicateItems is false', () => { - instance = new Choices(input, { - duplicateItems: false, - items: ['test 1'], - }); - - instance.input.element.focus(); - instance.input.element.value = 'test 1'; - - instance._onKeyDown({ - target: instance.input.element, - keyCode: 13, - ctrlKey: false, - }); - - expect(instance.currentState.items[instance.currentState.items.length - 1].value).to.equal(instance.input.element.value); - }); - - it('should filter input if regexFilter is passed', () => { - instance = new Choices(input, { - regexFilter: /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/, - }); - - instance.input.element.focus(); - instance.input.element.value = 'josh@joshuajohnson.co.uk'; - - instance._onKeyDown({ - target: instance.input.element, - keyCode: 13, - ctrlKey: false, - }); - - instance.input.element.focus(); - instance.input.element.value = 'not an email address'; - - instance._onKeyDown({ - target: instance.input.element, - keyCode: 13, - ctrlKey: false, - }); - - const lastItem = instance.currentState.items[instance.currentState.items.length - 1]; - - expect(lastItem.value).to.equal('josh@joshuajohnson.co.uk'); - expect(lastItem.value).not.to.equal('not an email address'); - }); - - it('should prepend and append values if passed', () => { - instance = new Choices(input, { - prependValue: 'item-', - appendValue: '-value', - }); - - instance.input.element.focus(); - instance.input.element.value = 'test'; - - instance._onKeyDown({ - target: instance.input.element, - keyCode: 13, - ctrlKey: false, - }); - - const lastItem = instance.currentState.items[instance.currentState.items.length - 1]; - - expect(lastItem.value).not.to.equal('test'); - expect(lastItem.value).to.equal('item-test-value'); - }); - }); - - describe('should accept single select inputs', () => { - let input; - let instance; - - beforeEach(() => { - input = document.createElement('select'); - input.className = 'js-choices'; - input.placeholder = 'Placeholder text'; - - for (let i = 1; i < 4; i++) { - const option = document.createElement('option'); - - option.value = `Value ${i}`; - option.innerHTML = `Label ${i}`; - - input.appendChild(option); - } - - document.body.appendChild(input); - }); - - afterEach(() => { - instance.destroy(); - }); - - it('should open the choice list on focusing', () => { - instance = new Choices(input); - instance.input.element.focus(); - expect(instance.dropdown.element.classList.contains(instance.config.classNames.activeState)).to.be.true; - }); - - it('should select the first choice', () => { - instance = new Choices(input); - expect(instance.currentState.items[0].value).to.include('Value 1'); - }); - - it('should highlight the choices on keydown', () => { - instance = new Choices(input, { - renderChoiceLimit: -1, - }); - instance.input.element.focus(); - - for (let i = 0; i < 2; i++) { - // Key down to third choice - instance._onKeyDown({ - target: instance.input.element, - keyCode: 40, - ctrlKey: false, - preventDefault: () => {}, - }); - } - - expect(instance.highlightPosition).to.equal(2); - }); - - it('should select choice on enter key press', () => { - instance = new Choices(input); - instance.input.element.focus(); - - // Key down to second choice - instance._onKeyDown({ - target: instance.input.element, - keyCode: 40, - ctrlKey: false, - preventDefault: () => {}, - }); - - // Key down to select choice - instance._onKeyDown({ - target: instance.input.element, - keyCode: 13, - ctrlKey: false, - preventDefault: () => {}, - }); - - expect(instance.currentState.items.length).to.equal(2); - }); - - it('should trigger add/change event on selection', () => { - instance = new Choices(input); - - const onChangeStub = sinon.stub(); - const addSpyStub = sinon.stub(); - const passedElement = instance.passedElement; - - passedElement.addEventListener('change', onChangeStub); - passedElement.addEventListener('addItem', addSpyStub); - - instance.input.element.focus(); - - // Key down to second choice - instance._onKeyDown({ - target: instance.input.element, - keyCode: 40, - ctrlKey: false, - preventDefault: () => {}, - }); - - // Key down to select choice - instance._onKeyDown({ - target: instance.input.element, - keyCode: 13, - ctrlKey: false, - preventDefault: () => {}, - }); - - const returnValue = onChangeStub.lastCall.args[0].detail.value; - expect(returnValue).to.be.a('string'); - expect(onChangeStub.callCount).to.equal(1); - expect(addSpyStub.callCount).to.equal(1); - }); - - it('should open the dropdown on click', () => { - instance = new Choices(input); - const container = instance.containerOuter.element; - instance._onClick({ - target: container, - ctrlKey: false, - preventDefault: () => {}, - }); - - expect(document.activeElement === instance.input.element && container.classList.contains('is-open')).to.be.true; - }); - - it('should close the dropdown on double click', () => { - instance = new Choices(input); - const container = instance.containerOuter.element; - const openState = instance.config.classNames.openState; - - instance._onClick({ - target: container, - ctrlKey: false, - preventDefault: () => {}, - }); - - instance._onClick({ - target: container, - ctrlKey: false, - preventDefault: () => {}, - }); - - expect(document.activeElement === instance.input.element && container.classList.contains(openState)).to.be.false; - }); - - it('should trigger showDropdown on dropdown opening', () => { - instance = new Choices(input); - const container = instance.containerOuter.element; - - const showDropdownStub = sinon.spy(); - const passedElement = instance.passedElement; - - passedElement.addEventListener('showDropdown', showDropdownStub); - - instance.input.focus(); - - instance._onClick({ - target: container, - ctrlKey: false, - preventDefault: () => {}, - }); - - expect(showDropdownStub.callCount).to.equal(1); - }); - - it('should trigger hideDropdown on dropdown closing', () => { - instance = new Choices(input); - - const container = instance.containerOuter.element; - const hideDropdownStub = sinon.stub(); - const passedElement = instance.passedElement; - - passedElement.addEventListener('hideDropdown', hideDropdownStub); - - instance.input.element.focus(); - - instance._onClick({ - target: container, - ctrlKey: false, - preventDefault: () => {}, - }); - - instance._onClick({ - target: container, - ctrlKey: false, - preventDefault: () => {}, - }); - - expect(hideDropdownStub.callCount).to.equal(1); - }); - - it('should filter choices when searching', () => { - instance = new Choices(input); - - const onSearchStub = sinon.spy(); - const passedElement = instance.passedElement; - - passedElement.addEventListener('search', onSearchStub); - - instance.input.element.focus(); - instance.input.element.value = '3 '; - - // Key down to search - instance._onKeyUp({ - target: instance.input.element, - keyCode: 13, - ctrlKey: false, - }); - - const mostAccurateResult = instance.currentState.choices.find(choice => choice.active); - - expect(instance.isSearching && mostAccurateResult.value === 'Value 3').to.be.true; - expect(onSearchStub.callCount).to.equal(1); - }); - - it('shouldn\'t filter choices when searching', () => { - instance = new Choices(input, { - searchChoices: false, - }); - - instance.setValue(['Javascript', 'HTML', 'Jasmine']); - - const onSearchStub = sinon.spy(); - const passedElement = instance.passedElement; - - passedElement.addEventListener('search', onSearchStub); - - instance.input.element.focus(); - instance.input.element.value = 'Javascript'; - - // Key down to search - instance._onKeyUp({ - target: instance.input.element, - keyCode: 13, - ctrlKey: false, - }); - - const activeOptions = instance.currentState.choices.filter(choice => choice.active); - - expect(activeOptions.length).to.equal(instance.currentState.choices.length); - expect(onSearchStub.callCount).to.equal(1); - }); - - it('shouldn\'t sort choices if shouldSort is false', () => { - instance = new Choices(input, { - shouldSort: false, - choices: [ - { - value: 'Value 5', - label: 'Label Five', - }, { - value: 'Value 6', - label: 'Label Six', - }, { - value: 'Value 7', - label: 'Label Seven', - }, - ], - }); - - expect(instance.currentState.choices[0].value).to.equal('Value 5'); - }); - - it('should sort choices if shouldSort is true', () => { - instance = new Choices(input, { - shouldSort: true, - choices: [ - { - value: 'Value 5', - label: 'Label Five', - }, { - value: 'Value 6', - label: 'Label Six', - }, { - value: 'Value 7', - label: 'Label Seven', - }, - ], - }); - - expect(instance.currentState.choices[0].value).to.equal('Value 1'); - }); - }); - - describe('should accept multiple select inputs', () => { - let input; - let instance; - - beforeEach(() => { - input = document.createElement('select'); - input.className = 'js-choices'; - input.setAttribute('multiple', ''); - - for (let i = 1; i < 4; i++) { - const option = document.createElement('option'); - - option.value = `Value ${i}`; - option.innerHTML = `Value ${i}`; - - if (i % 2) { - option.selected = true; - } - - input.appendChild(option); - } - - document.body.appendChild(input); - - instance = new Choices(input, { - placeholderValue: 'Placeholder text', - choices: [ - { - value: 'One', - label: 'Label One', - selected: true, - disabled: false, - }, { - value: 'Two', - label: 'Label Two', - disabled: true, - }, { - value: 'Three', - label: 'Label Three', - }, - ], - }); - }); - - afterEach(() => { - instance.destroy(); - }); - - it('should add any pre-defined values', () => { - expect(instance.currentState.items.length).to.be.above(1); - }); - - it('should add options defined in the config + pre-defined options', () => { - expect(instance.currentState.choices.length).to.equal(6); - }); - - it('should add a placeholder defined in the config to the search input', () => { - expect(instance.input.element.placeholder).to.equal('Placeholder text'); - }); - }); - - describe('should handle public methods on select input types', () => { - let input; - let instance; - - beforeEach(() => { - input = document.createElement('select'); - input.className = 'js-choices'; - input.multiple = true; - input.placeholder = 'Placeholder text'; - - for (let i = 1; i < 10; i++) { - const option = document.createElement('option'); - - option.value = `Value ${i}`; - option.innerHTML = `Value ${i}`; - - if (i % 2) { - option.selected = true; - } - - input.appendChild(option); - } - - document.body.appendChild(input); - instance = new Choices(input); - }); - - afterEach(() => { - instance.destroy(); - }); - - it('should handle highlightItem()', () => { - const items = instance.currentState.items; - const randomItem = items[Math.floor(Math.random() * items.length)]; - - instance.highlightItem(randomItem); - - expect(randomItem.highlighted).to.be.true; - }); - - it('should handle unhighlightItem()', () => { - const items = instance.currentState.items; - const randomItem = items[Math.floor(Math.random() * items.length)]; - - instance.unhighlightItem(randomItem); - - expect(randomItem.highlighted).to.be.false; - }); - - it('should handle highlightAll()', () => { - const items = instance.currentState.items; - - instance.highlightAll(); - - const unhighlightedItems = items.some(item => item.highlighted === false); - - expect(unhighlightedItems).to.be.false; - }); - - it('should handle unhighlightAll()', () => { - const items = instance.currentState.items; - - instance.unhighlightAll(); - - const highlightedItems = items.some(item => item.highlighted === true); - - expect(highlightedItems).to.be.false; - }); - - it('should handle removeHighlightedItems()', () => { - const items = instance.currentState.items; - instance.highlightAll(); - instance.removeHighlightedItems(); - - const activeItems = items.some(item => item.active === true); - - expect(activeItems).to.be.false; - }); - - it('should handle showDropdown()', () => { - instance.showDropdown(); - - const hasOpenState = instance.containerOuter.element.classList.contains(instance.config.classNames.openState); - const hasAttr = instance.containerOuter.element.getAttribute('aria-expanded') === 'true'; - const hasActiveState = instance.dropdown.element.classList.contains(instance.config.classNames.activeState); - - expect(hasOpenState && hasAttr && hasActiveState).to.be.true; - }); - - it('should handle hideDropdown()', () => { - instance.showDropdown(); - instance.hideDropdown(); - - const hasOpenState = instance.containerOuter.element.classList.contains(instance.config.classNames.openState); - const hasAttr = instance.containerOuter.element.getAttribute('aria-expanded') === 'true'; - const hasActiveState = instance.dropdown.element.classList.contains(instance.config.classNames.activeState); - - - expect(hasOpenState && hasAttr && hasActiveState).to.be.false; - }); - - it('should handle toggleDropdown()', () => { - sinon.spy(instance, 'hideDropdown'); - instance.showDropdown(); - instance.toggleDropdown(); - expect(instance.hideDropdown.callCount).to.equal(1); - }); - - it('should handle getValue()', () => { - const valueObjects = instance.getValue(); - const valueStrings = instance.getValue(true); - - expect(valueStrings[0]).to.be.a('string'); - expect(valueObjects[0]).to.be.an('object'); - expect(valueObjects).to.be.an('array'); - expect(valueObjects.length).to.equal(5); - }); - - it('should handle setValue()', () => { - instance.setValue(['Set value 1', 'Set value 2', 'Set value 3']); - const valueStrings = instance.getValue(true); - - expect(valueStrings[valueStrings.length - 1]).to.equal('Set value 3'); - expect(valueStrings[valueStrings.length - 2]).to.equal('Set value 2'); - expect(valueStrings[valueStrings.length - 3]).to.equal('Set value 1'); - }); - - it('should handle setValueByChoice()', () => { - const choices = instance.store.getChoicesFilteredByActive(); - const randomChoice = choices[Math.floor(Math.random() * choices.length)]; - - instance.highlightAll(); - instance.removeHighlightedItems(); - instance.setValueByChoice(randomChoice.value); - - const value = instance.getValue(true); - - expect(value[0]).to.equal(randomChoice.value); - }); - - it('should handle setChoices()', () => { - instance.setChoices([{ - label: 'Group one', - id: 1, - disabled: false, - choices: [ - { - value: 'Child One', - label: 'Child One', - selected: true, - }, { - value: 'Child Two', - label: 'Child Two', - disabled: true, - }, { - value: 'Child Three', - label: 'Child Three', - }, - ], - }, { - label: 'Group two', - id: 2, - disabled: false, - choices: [ - { - value: 'Child Four', - label: 'Child Four', - disabled: true, - }, { - value: 'Child Five', - label: 'Child Five', - }, { - value: 'Child Six', - label: 'Child Six', - }, - ], - }], 'value', 'label'); - - - const groups = instance.currentState.groups; - const choices = instance.currentState.choices; - - expect(groups[groups.length - 1].value).to.equal('Group two'); - expect(groups[groups.length - 2].value).to.equal('Group one'); - expect(choices[choices.length - 1].value).to.equal('Child Six'); - expect(choices[choices.length - 2].value).to.equal('Child Five'); - }); - - it('should handle setChoices() with blank values', () => { - instance.setChoices([{ - label: 'Choice one', - value: 'one', - }, { - label: 'Choice two', - value: '', - }], 'value', 'label', true); - - - const choices = instance.currentState.choices; - expect(choices[0].value).to.equal('one'); - expect(choices[1].value).to.equal(''); - }); - - it('should handle clearStore()', () => { - instance.clearStore(); - - expect(instance.currentState.items).to.have.lengthOf(0); - expect(instance.currentState.choices).to.have.lengthOf(0); - expect(instance.currentState.groups).to.have.lengthOf(0); - }); - - it('should handle disable()', () => { - instance.disable(); - - expect(instance.input.element.disabled).to.be.true; - expect(instance.containerOuter.element.classList.contains(instance.config.classNames.disabledState)).to.be.true; - expect(instance.containerOuter.element.getAttribute('aria-disabled')).to.equal('true'); - }); - - it('should handle enable()', () => { - instance.enable(); - - expect(instance.input.element.disabled).to.be.false; - expect(instance.containerOuter.element.classList.contains(instance.config.classNames.disabledState)).to.be.false; - expect(instance.containerOuter.element.hasAttribute('aria-disabled')).to.be.false; - }); - - it('should handle ajax()', () => { - const dummyFn = sinon.spy(); - - instance.ajax(dummyFn); - - expect(dummyFn.callCount).to.equal(1); - }); - }); - - describe('should handle public methods on select-one input types', () => { - let input; - let instance; - - beforeEach(() => { - input = document.createElement('select'); - input.className = 'js-choices'; - input.placeholder = 'Placeholder text'; - - for (let i = 1; i < 10; i++) { - const option = document.createElement('option'); - - option.value = `Value ${i}`; - option.innerHTML = `Value ${i}`; - - if (i % 2) { - option.selected = true; - } - - input.appendChild(option); - } - - document.body.appendChild(input); - instance = new Choices(input); - }); - - afterEach(() => { - instance.destroy(); - }); - - it('should handle disable()', () => { - instance.disable(); - - expect(instance.containerOuter.element.getAttribute('tabindex')).to.equal('-1'); - }); - - it('should handle enable()', () => { - instance.enable(); - - expect(instance.containerOuter.element.getAttribute('tabindex')).to.equal('0'); - }); - }); - - describe('should handle public methods on text input types', () => { - let input; - let instance; - - beforeEach(() => { - input = document.createElement('input'); - input.type = 'text'; - input.className = 'js-choices'; - input.value = 'Value 1, Value 2, Value 3, Value 4'; - - document.body.appendChild(input); - instance = new Choices(input); - }); - - afterEach(() => { - instance.destroy(); - }); - - it('should handle clearInput()', () => { - instance.clearInput(); - expect(instance.input.element.value).to.equal(''); - }); - - it('should handle removeItemsByValue()', () => { - const items = instance.currentState.items; - const randomItem = items[Math.floor(Math.random() * items.length)]; - - instance.removeItemsByValue(randomItem.value); - expect(randomItem.active).to.be.false; - }); - }); - - describe('should react to config options', () => { - let input; - let instance; - - beforeEach(() => { - input = document.createElement('select'); - input.className = 'js-choices'; - input.setAttribute('multiple', ''); - - for (let i = 1; i < 4; i++) { - const option = document.createElement('option'); - - option.value = `Value ${i}`; - option.innerHTML = `Value ${i}`; - - if (i % 2) { - option.selected = true; - } - - input.appendChild(option); - } - - document.body.appendChild(input); - }); - - afterEach(() => { - instance.destroy(); - }); - - it('should flip the dropdown', () => { - instance = new Choices(input, { - position: 'top', - }); - - const container = instance.containerOuter.element; - instance.input.element.focus(); - expect(container.classList.contains(instance.config.classNames.flippedState)).to.be.true; - }); - - it('shouldn\'t flip the dropdown', () => { - instance = new Choices(input, { - position: 'bottom', - }); - - const container = instance.containerOuter.element; - instance.input.element.focus(); - expect(container.classList.contains(instance.config.classNames.flippedState)).to.be.false; - }); - - it('should render selected choices', () => { - instance = new Choices(input, { - renderSelectedChoices: 'always', - renderChoiceLimit: -1, - }); - - const renderedChoices = instance.choiceList.element.querySelectorAll('.choices__item'); - expect(renderedChoices.length).to.equal(3); - }); - - it('shouldn\'t render selected choices', () => { - instance = new Choices(input, { - renderSelectedChoices: 'auto', - renderChoiceLimit: -1, - }); - - const renderedChoices = instance.choiceList.element.querySelectorAll('.choices__item'); - expect(renderedChoices.length).to.equal(1); - }); - - it('shouldn\'t render choices up to a render limit', () => { - // Remove existing choices (to make test simpler) - while (input.firstChild) { - input.removeChild(input.firstChild); - } - - instance = new Choices(input, { - choices: [ - { - value: 'Option 1', - selected: false, - }, - { - value: 'Option 2', - selected: false, - }, - { - value: 'Option 3', - selected: false, - }, - { - value: 'Option 4', - selected: false, - }, - { - value: 'Option 5', - selected: false, - }, - ], - renderSelectedChoices: 'auto', - renderChoiceLimit: 4, - }); - - const renderedChoices = instance.choiceList.element.querySelectorAll('.choices__item'); - expect(renderedChoices.length).to.equal(4); - }); - }); - - describe('should allow custom properties provided by the user on items or choices', () => { - it('should allow the user to supply custom properties for an item', () => { - const randomItem = { - id: 8999, - choiceId: 9000, - groupId: 9001, - value: 'value', - label: 'label', - customProperties: { - foo: 'bar', - }, - placeholder: false, - keyCode: null, - }; - - const expectedState = [{ - id: randomItem.id, - choiceId: randomItem.choiceId, - groupId: randomItem.groupId, - value: randomItem.value, - label: randomItem.label, - active: true, - highlighted: false, - customProperties: randomItem.customProperties, - placeholder: randomItem.placeholder, - keyCode: randomItem.keyCode, - }]; - - const action = addItemAction( - randomItem.value, - randomItem.label, - randomItem.id, - randomItem.choiceId, - randomItem.groupId, - randomItem.customProperties, - randomItem.placeholder, - randomItem.keyCode, - ); - - expect(itemReducer([], action)).to.deep.equal(expectedState); - }); - - it('should allow the user to supply custom properties for a choice', () => { - const randomChoice = { - id: 123, - elementId: 321, - groupId: 213, - value: 'value', - label: 'label', - disabled: false, - customProperties: { - foo: 'bar', - }, - placeholder: false, - keyCode: null, - }; - - const expectedState = [{ - id: randomChoice.id, - elementId: randomChoice.elementId, - groupId: randomChoice.groupId, - value: randomChoice.value, - label: randomChoice.label, - disabled: randomChoice.disabled, - selected: false, - active: true, - score: 9999, - customProperties: randomChoice.customProperties, - placeholder: randomChoice.placeholder, - keyCode: randomChoice.keyCode, - }]; - - const action = addChoiceAction( - randomChoice.value, - randomChoice.label, - randomChoice.id, - randomChoice.groupId, - randomChoice.disabled, - randomChoice.elementId, - randomChoice.customProperties, - randomChoice.placeholder, - randomChoice.keyCode, - ); - - expect(choiceReducer([], action)).to.deep.equal(expectedState); - }); - }); - - describe('should allow custom properties provided by the user on items or choices', () => { - let input; - let instance; - - beforeEach(() => { - input = document.createElement('select'); - input.className = 'js-choices'; - input.setAttribute('multiple', ''); - - document.body.appendChild(input); - }); - - afterEach(() => { - instance.destroy(); - }); - - it('should allow the user to supply custom properties for a choice that will be inherited by the item when the user selects the choice', () => { - const expectedCustomProperties = { - isBestOptionEver: true, - }; - - instance = new Choices(input); - instance.setChoices([{ - value: '42', - label: 'My awesome choice', - selected: false, - disabled: false, - customProperties: expectedCustomProperties, - }], 'value', 'label', true); - - instance.setValueByChoice('42'); - const selectedItems = instance.getValue(); - - expect(selectedItems.length).to.equal(1); - expect(selectedItems[0].customProperties).to.equal(expectedCustomProperties); - }); - - it('should allow the user to supply custom properties when directly creating a selected item', () => { - const expectedCustomProperties = { - isBestOptionEver: true, - }; - - instance = new Choices(input); - - instance.setValue([{ - value: 'bar', - label: 'foo', - customProperties: expectedCustomProperties, - }]); - const selectedItems = instance.getValue(); - - expect(selectedItems.length).to.equal(1); - expect(selectedItems[0].customProperties).to.equal(expectedCustomProperties); - }); - }); -}); diff --git a/src/scripts/src/reducers/choices.js b/src/scripts/src/reducers/choices.js index 5f70540..31d480c 100644 --- a/src/scripts/src/reducers/choices.js +++ b/src/scripts/src/reducers/choices.js @@ -1,4 +1,6 @@ -const choices = (state = [], action) => { +export const defaultState = []; + +export default function choices(state = defaultState, action) { switch (action.type) { case 'ADD_CHOICE': { /* @@ -100,6 +102,4 @@ const choices = (state = [], action) => { return state; } } -}; - -export default choices; +} diff --git a/src/scripts/src/reducers/groups.js b/src/scripts/src/reducers/groups.js index b4edbd5..5e77feb 100644 --- a/src/scripts/src/reducers/groups.js +++ b/src/scripts/src/reducers/groups.js @@ -1,4 +1,6 @@ -const groups = (state = [], action) => { +export const defaultState = []; + +export default function groups(state = defaultState, action) { switch (action.type) { case 'ADD_GROUP': { return [...state, { @@ -17,6 +19,4 @@ const groups = (state = [], action) => { return state; } } -}; - -export default groups; +} diff --git a/src/scripts/src/reducers/items.js b/src/scripts/src/reducers/items.js index bab1352..ce13cb9 100644 --- a/src/scripts/src/reducers/items.js +++ b/src/scripts/src/reducers/items.js @@ -1,4 +1,6 @@ -const items = (state = [], action) => { +export const defaultState = []; + +export default function items(state = defaultState, action) { switch (action.type) { case 'ADD_ITEM': { // Add object to items array @@ -49,6 +51,4 @@ const items = (state = [], action) => { return state; } } -}; - -export default items; +}