Ensure destroying instance reinstates options + tests

This commit is contained in:
Josh Johnson 2017-12-18 12:06:38 +00:00
parent beeeeb87ad
commit 9777287b92
16 changed files with 178 additions and 75 deletions

View file

@ -15,7 +15,6 @@ import { clearAll } from './actions/misc';
import {
isScrolledIntoView,
getAdjacentEl,
wrap,
getType,
isType,
isElement,
@ -220,6 +219,10 @@ class Choices {
this.passedElement.reveal();
this.containerOuter.unwrap(this.passedElement.element);
if (this.isSelectElement) {
this.passedElement.setOptions(this.presetChoices);
}
// Clear data store
this.clearStore();
@ -388,25 +391,11 @@ class Choices {
}
if (this.isTextElement) {
// Simplify store data to just values
const itemsFiltered = this.store.getItemsReducedToValues(items);
const itemsFilteredString = itemsFiltered.join(this.config.delimiter);
// Update the value of the hidden input
this.passedElement.setValue(itemsFilteredString);
this.passedElement.setValue(items);
} else {
const selectedOptionsFragment = document.createDocumentFragment();
const addOptionToFragment = (item) => {
// Create a standard select option
const option = this._getTemplate('option', item);
// Append it to fragment
selectedOptionsFragment.appendChild(option);
};
// Add each list item to list
items.forEach(item => addOptionToFragment(item));
// Update the options of the hidden input
this.passedElement.setOptions(selectedOptionsFragment);
this.passedElement.setOptions(items);
}
const addItemToFragment = (item) => {

View file

@ -152,17 +152,16 @@ export default class Container {
}
wrap(element) {
this.wrappedElement = element;
wrap(this.wrappedElement, this.element);
wrap(element, this.element);
}
unwrap() {
// Move passed element back to original position
unwrap(element) {
// Move passed element outside this element
this.element.parentNode.insertBefore(
this.wrappedElement,
element,
this.element,
);
// Remove container
// Remove this element
this.element.parentNode.removeChild(this.element);
}

View file

@ -16,7 +16,14 @@ describe('components/container', () => {
};
element = document.createElement('div');
element.id = 'container';
instance = new Container(choicesInstance, element, DEFAULT_CLASSNAMES);
document.body.appendChild(element);
instance = new Container(choicesInstance, document.getElementById('container'), DEFAULT_CLASSNAMES);
});
afterEach(() => {
document.body.innerHTML = '';
element = null;
instance = null;
});
describe('constructor', () => {
@ -351,21 +358,15 @@ describe('components/container', () => {
instance.wrap(document.querySelector('div#wrap-test'));
expect(instance.element.querySelector('div#wrap-test')).to.equal(elementToWrap);
});
it('assigns reference to element to instance', () => {
expect(instance.wrappedElement).to.equal(undefined);
instance.wrap(document.querySelector('div#wrap-test'));
expect(instance.wrappedElement).to.equal(elementToWrap);
});
});
describe('unwrap', () => {
let elementToWrap;
let elementToUnwrap;
beforeEach(() => {
elementToWrap = document.createElement('div');
elementToWrap.id = 'unwrap-test';
document.body.appendChild(elementToWrap);
elementToUnwrap = document.createElement('div');
elementToUnwrap.id = 'unwrap-test';
document.body.appendChild(elementToUnwrap);
instance.wrap(document.getElementById('unwrap-test'));
});
@ -375,16 +376,16 @@ describe('components/container', () => {
it('moves wrapped element outside of element', () => {
expect(instance.element.querySelector('div#unwrap-test')).to.be.instanceof(HTMLElement);
instance.unwrap(elementToWrap);
instance.unwrap(elementToUnwrap);
expect(instance.element.querySelector('div#unwrap-test')).to.equal(null);
expect(document.querySelector('div#unwrap-test')).to.be.instanceof(HTMLElement);
});
// it('removes element from DOM', () => {
// expect(document.getElementById('container')).to.not.equal(null);
// instance.unwrap(elementToWrap);
// expect(document.getElementById('container')).to.equal(null);
// });
it('removes element from DOM', () => {
expect(document.getElementById('container')).to.not.equal(null);
instance.unwrap(elementToUnwrap);
expect(document.getElementById('container')).to.equal(null);
});
});
describe('addLoadingState', () => {

View file

@ -20,6 +20,11 @@ describe('components/dropdown', () => {
instance = new Dropdown(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
});
afterEach(() => {
document.body.innerHTML = '';
instance = null;
});
describe('constructor', () => {
it('assigns choices instance to instance', () => {
expect(instance.parentInstance).to.eql(choicesInstance);

View file

@ -18,6 +18,11 @@ describe('components/input', () => {
instance = new Input(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
});
afterEach(() => {
document.body.innerHTML = '';
instance = null;
});
describe('constructor', () => {
it('assigns choices instance to class', () => {
expect(instance.parentInstance).to.eql(choicesInstance);

View file

@ -17,6 +17,11 @@ describe('components/list', () => {
instance = new List(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
});
afterEach(() => {
document.body.innerHTML = '';
instance = null;
});
describe('constructor', () => {
it('assigns choices instance to class', () => {
expect(instance.parentInstance).to.eql(choicesInstance);

View file

@ -18,6 +18,11 @@ describe('components/wrappedElement', () => {
instance = new WrappedElement(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
});
afterEach(() => {
document.body.innerHTML = '';
instance = null;
});
describe('getElement', () => {
it('returns DOM reference of element', () => {
expect(instance.getElement()).to.eql(choicesElement);

View file

@ -1,4 +1,5 @@
import WrappedElement from './wrapped-element';
import { reduceToValues } from './../lib/utils';
export default class WrappedInput extends WrappedElement {
constructor(instance, element, classNames) {
@ -28,8 +29,11 @@ export default class WrappedInput extends WrappedElement {
super.enable();
}
setValue(value) {
this.element.setAttribute('value', value);
this.element.value = value;
setValue(items) {
const itemsFiltered = reduceToValues(items);
const itemsFilteredString = itemsFiltered.join(this.parentInstance.config.delimiter);
this.element.setAttribute('value', itemsFilteredString);
this.element.value = itemsFilteredString;
}
}

View file

@ -16,4 +16,32 @@ describe('components/wrappedInput', () => {
choicesElement = document.createElement('input');
instance = new WrappedInput(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
});
afterEach(() => {
document.body.innerHTML = '';
instance = null;
});
describe('setValue', () => {
const data = [
{
id: 'ID 1',
value: 'Value 1',
},
{
id: 'ID 2',
value: 'Value 2',
},
{
id: 'ID 3',
value: 'Value 3',
},
];
it('sets delimited value of element based on passed data', () => {
expect(instance.element.value).to.equal('');
instance.setValue(data);
expect(instance.element.value).to.equal('Value 1,Value 2,Value 3');
});
});
});

View file

@ -1,4 +1,5 @@
import WrappedElement from './wrapped-element';
import templates from './../templates';
export default class WrappedSelect extends WrappedElement {
constructor(instance, element, classNames) {
@ -28,11 +29,6 @@ export default class WrappedSelect extends WrappedElement {
super.enable();
}
setOptions(options) {
this.element.innerHTML = '';
this.element.appendChild(options);
}
getPlaceholderOption() {
return this.element.querySelector('option[placeholder]');
}
@ -44,4 +40,24 @@ export default class WrappedSelect extends WrappedElement {
getOptionGroups() {
return Array.from(this.element.getElementsByTagName('OPTGROUP'));
}
setOptions(options) {
const fragment = document.createDocumentFragment();
const addOptionToFragment = (data) => {
// Create a standard select option
const template = templates.option(data);
// Append it to fragment
fragment.appendChild(template);
};
// Add each list item to list
options.forEach(optionData => addOptionToFragment(optionData));
this.appendDocFragment(fragment);
}
appendDocFragment(fragment) {
this.element.innerHTML = '';
this.element.appendChild(fragment);
}
}

View file

@ -16,4 +16,9 @@ describe('components/wrappedSelect', () => {
choicesElement = document.createElement('select');
instance = new WrappedSelect(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
});
afterEach(() => {
document.body.innerHTML = '';
instance = null;
});
});

View file

@ -593,4 +593,13 @@ export const getWindowHeight = () => {
html.scrollHeight,
html.offsetHeight,
);
};
};
export const reduceToValues = (items, key = 'value') => {
const values = items.reduce((prev, current) => {
prev.push(current[key]);
return prev;
}, []);
return values;
}

View file

@ -0,0 +1,56 @@
import { expect } from 'chai';
import { reduceToValues } from './utils';
describe('utils', () => {
describe('reduceToValues', () => {
const items = [
{
id: 1,
choiceId: 1,
groupId: -1,
value: 'Item one',
label: 'Item one',
active: false,
highlighted: false,
customProperties: null,
placeholder: false,
keyCode: null,
},
{
id: 2,
choiceId: 2,
groupId: -1,
value: 'Item two',
label: 'Item two',
active: true,
highlighted: false,
customProperties: null,
placeholder: false,
keyCode: null,
},
{
id: 3,
choiceId: 3,
groupId: -1,
value: 'Item three',
label: 'Item three',
active: true,
highlighted: true,
customProperties: null,
placeholder: false,
keyCode: null,
},
];
it('returns an array of item values', () => {
const expectedResponse = [
items[0].value,
items[1].value,
items[2].value,
];
const actualResponse = reduceToValues(items);
expect(actualResponse).to.eql(expectedResponse);
});
});
});

View file

@ -68,19 +68,6 @@ export default class Store {
return values;
}
/**
* Get items from store reduced to just their values
* @return {Array} Item objects
*/
getItemsReducedToValues(items) {
const values = items.reduce((prev, current) => {
prev.push(current.value);
return prev;
}, []);
return values;
}
/**
* Get choices from store
* @return {Array} Option objects

View file

@ -177,17 +177,6 @@ describe('reducers/store', () => {
});
});
describe('getItemsReducedToValues', () => {
it('returns an array of item values', () => {
const expectedResponse = state.items.reduce((items, item) => {
items.push(item.value);
return items;
}, []);
const actualResponse = instance.getItemsReducedToValues(state.items);
expect(actualResponse).to.eql(expectedResponse);
});
});
describe('getChoices', () => {
it('returns choices', () => {
const expectedResponse = state.choices;

View file

@ -226,9 +226,9 @@ export const TEMPLATES = {
</div>
`);
},
option(globalClasses, data) {
option(data) {
return strToEl(`
<option value="${data.value}" selected>${data.label}</option>
<option value="${data.value}" ${data.selected ? 'selected' : ''} ${data.disabled ? 'disabled' : ''}>${data.label}</option>
`);
},
};