Rename rendering methods + createGroupsFragment test

This commit is contained in:
Josh Johnson 2017-12-20 15:10:01 +00:00
parent a5277a49e7
commit 5048379e68
11 changed files with 326 additions and 86 deletions

View file

@ -48,6 +48,8 @@ global.navigator = {
global.CustomEvent = window.CustomEvent;
global.HTMLElement = window.HTMLElement;
global.HTMLOptionElement = window.HTMLOptionElement;
global.HTMLOptGroupElement = window.HTMLOptGroupElement;
global.DocumentFragment = window.DocumentFragment;
copyProps(window, global);
mockRAF(global);

View file

@ -2085,8 +2085,8 @@ var Choices = function () {
*/
}, {
key: 'renderGroups',
value: function renderGroups(groups, choices, fragment) {
key: 'createGroupsFragment',
value: function createGroupsFragment(groups, choices, fragment) {
var _this = this;
var groupFragment = fragment || document.createDocumentFragment();
@ -2111,7 +2111,7 @@ var Choices = function () {
if (groupChoices.length >= 1) {
var dropdownGroup = _this._getTemplate('choiceGroup', group);
groupFragment.appendChild(dropdownGroup);
_this.renderChoices(groupChoices, groupFragment, true);
_this.createChoicesFragment(groupChoices, groupFragment, true);
}
});
@ -2127,8 +2127,8 @@ var Choices = function () {
*/
}, {
key: 'renderChoices',
value: function renderChoices(choices, fragment) {
key: 'createChoicesFragment',
value: function createChoicesFragment(choices, fragment) {
var _this2 = this;
var withinGroup = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : false;
@ -2207,8 +2207,8 @@ var Choices = function () {
*/
}, {
key: 'renderItems',
value: function renderItems(items) {
key: 'createItemsFragment',
value: function createItemsFragment(items) {
var _this3 = this;
var fragment = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null;
@ -2300,11 +2300,11 @@ var Choices = function () {
return activeChoice.placeholder === true && activeChoice.groupId === -1;
});
if (activePlaceholders.length >= 1) {
choiceListFragment = this.renderChoices(activePlaceholders, choiceListFragment);
choiceListFragment = this.createChoicesFragment(activePlaceholders, choiceListFragment);
}
choiceListFragment = this.renderGroups(activeGroups, activeChoices, choiceListFragment);
choiceListFragment = this.createGroupsFragment(activeGroups, activeChoices, choiceListFragment);
} else if (activeChoices.length >= 1) {
choiceListFragment = this.renderChoices(activeChoices, choiceListFragment);
choiceListFragment = this.createChoicesFragment(activeChoices, choiceListFragment);
}
var _activeItems = this.store.getItemsFilteredByActive();
@ -2350,7 +2350,7 @@ var Choices = function () {
if (activeItems.length) {
// Create a fragment to store our list items
// (so we don't have to update the DOM for each item)
var itemListFragment = this.renderItems(activeItems);
var itemListFragment = this.createItemsFragment(activeItems);
// If we have items to add
if (itemListFragment.childNodes) {

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -282,9 +282,8 @@ class Choices {
* @return {DocumentFragment} Populated options fragment
* @private
*/
renderGroups(groups, choices, fragment) {
createGroupsFragment(groups, choices, fragment) {
const groupFragment = fragment || document.createDocumentFragment();
const filter = this.config.sortFn;
const getGroupChoices = group => choices.filter((choice) => {
if (this.isSelectOneElement) {
return choice.groupId === group.id;
@ -292,18 +291,18 @@ class Choices {
return choice.groupId === group.id && (this.config.renderSelectedChoices === 'always' || !choice.selected);
});
// If sorting is enabled, filter groups
if (this.config.shouldSort) {
groups.sort(filter);
groups.sort(this.config.sortFn);
}
groups.forEach((group) => {
const groupChoices = getGroupChoices(group);
if (groupChoices.length >= 1) {
const dropdownGroup = this._getTemplate('choiceGroup', group);
groupFragment.appendChild(dropdownGroup);
this.renderChoices(groupChoices, groupFragment, true);
this.createChoicesFragment(groupChoices, groupFragment, true);
}
});
@ -317,7 +316,7 @@ class Choices {
* @return {DocumentFragment} Populated choices fragment
* @private
*/
renderChoices(choices, fragment, withinGroup = false) {
createChoicesFragment(choices, fragment, withinGroup = false) {
// Create a fragment to store our list items (so we don't have to update the DOM for each item)
const choicesFragment = fragment || document.createDocumentFragment();
const { renderSelectedChoices, searchResultLimit, renderChoiceLimit } = this.config;
@ -381,7 +380,7 @@ class Choices {
* @return
* @private
*/
renderItems(items, fragment = null) {
createItemsFragment(items, fragment = null) {
// Create fragment to add elements to
const itemListFragment = fragment || document.createDocumentFragment();
@ -452,11 +451,11 @@ class Choices {
activeChoice => activeChoice.placeholder === true && activeChoice.groupId === -1,
);
if (activePlaceholders.length >= 1) {
choiceListFragment = this.renderChoices(activePlaceholders, choiceListFragment);
choiceListFragment = this.createChoicesFragment(activePlaceholders, choiceListFragment);
}
choiceListFragment = this.renderGroups(activeGroups, activeChoices, choiceListFragment);
choiceListFragment = this.createGroupsFragment(activeGroups, activeChoices, choiceListFragment);
} else if (activeChoices.length >= 1) {
choiceListFragment = this.renderChoices(activeChoices, choiceListFragment);
choiceListFragment = this.createChoicesFragment(activeChoices, choiceListFragment);
}
// If we have choices to show
@ -506,7 +505,7 @@ class Choices {
if (activeItems.length) {
// Create a fragment to store our list items
// (so we don't have to update the DOM for each item)
const itemListFragment = this.renderItems(activeItems);
const itemListFragment = this.createItemsFragment(activeItems);
// If we have items to add, append them
if (itemListFragment.childNodes) {

View file

@ -94,9 +94,9 @@ describe('Choices', () => {
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.createGroupsFragment).to.be.a('function');
expect(instance.createItemsFragment).to.be.a('function');
expect(instance.createChoicesFragment).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');

View file

@ -1483,93 +1483,239 @@ describe('choices', () => {
});
});
describe('renderGroups', () => {
let renderChoicesStub;
describe('createGroupsFragment', () => {
let createChoicesFragmentStub;
const choices = [
{
id: 1,
selected: true,
groupId: 1,
},
{
id: 1,
selected: false,
groupId: 2,
value: 'Choice 1',
label: 'Choice 1',
},
{
id: 2,
selected: false,
groupId: 2,
value: 'Choice 2',
label: 'Choice 2',
},
{
id: 3,
selected: false,
groupId: 1,
value: 'Choice 3',
label: 'Choice 3',
},
];
const groups = [
{
id: 1,
value: 'Group 1',
active: true,
disabled: false,
},
{
id: 2,
value: 'Group 2',
active: true,
disabled: false,
},
{
id: 1,
value: 'Group 1',
active: true,
disabled: false,
},
];
beforeEach(() => {
renderChoicesStub = stub();
instance.renderChoices = renderChoicesStub;
createChoicesFragmentStub = stub();
instance.createChoicesFragment = createChoicesFragmentStub;
});
afterEach(() => {
instance.createChoicesFragment.reset();
});
describe('returning a fragment of groups', () => {
describe('passing fragment argument', () => {
it('updates fragment with groups', () => {
const fragment = document.createDocumentFragment();
const childElement = document.createElement('div');
fragment.appendChild(childElement);
output = instance.createGroupsFragment(groups, choices, fragment);
const elementToWrapFragment = document.createElement('div');
elementToWrapFragment.appendChild(output);
expect(output).to.be.instanceOf(DocumentFragment);
expect(elementToWrapFragment.children[0]).to.eql(childElement);
expect(elementToWrapFragment.querySelectorAll('[data-group]').length).to.equal(2);
});
});
describe('not passing fragment argument', () => {
it('returns new groups fragment', () => {
output = instance.createGroupsFragment(groups, choices);
const elementToWrapFragment = document.createElement('div');
elementToWrapFragment.appendChild(output);
});
});
describe('select-one element', () => {
it('renders group choices', () => {
});
});
describe('text/select-multiple element', () => {
describe('renderSelectedChoices set to true', () => {
it('renders group choices', () => {
});
});
describe('renderSelectedChoices set to false', () => {
it('renders group choices that are not already selected', () => {
});
expect(output).to.be.instanceOf(DocumentFragment);
expect(elementToWrapFragment.querySelectorAll('[data-group]').length).to.equal(2);
});
});
describe('sorting groups', () => {
it('returns groups fragment sorted by config.sortFn', () => {
let sortFnStub;
beforeEach(() => {
sortFnStub = stub();
instance.config.sortFn = sortFnStub;
instance.config.shouldSort = true;
});
afterEach(() => {
instance.config.sortFn.reset();
});
it('sorts groups by config.sortFn', () => {
expect(sortFnStub.called).to.equal(false);
instance.createGroupsFragment(groups, choices);
expect(sortFnStub.called).to.equal(true);
});
});
describe('not sorting groups', () => {
let sortFnStub;
beforeEach(() => {
sortFnStub = stub();
instance.config.sortFn = sortFnStub;
instance.config.shouldSort = false;
});
afterEach(() => {
instance.config.sortFn.reset();
});
it('does not sort groups', () => {
instance.createGroupsFragment(groups, choices);
expect(sortFnStub.called).to.equal(false);
});
});
describe('select-one element', () => {
beforeEach(() => {
instance.isSelectOneElement = true;
});
it('calls createChoicesFragment with choices that belong to each group', () => {
expect(createChoicesFragmentStub.called).to.equal(false);
instance.createGroupsFragment(groups, choices);
expect(createChoicesFragmentStub.called).to.equal(true);
expect(createChoicesFragmentStub.firstCall.args[0]).to.eql([
{
id: 1,
selected: true,
groupId: 1,
value: 'Choice 1',
label: 'Choice 1',
},
{
id: 3,
selected: false,
groupId: 1,
value: 'Choice 3',
label: 'Choice 3',
},
]);
expect(createChoicesFragmentStub.secondCall.args[0]).to.eql([
{
id: 2,
selected: false,
groupId: 2,
value: 'Choice 2',
label: 'Choice 2',
},
]);
});
});
describe('text/select-multiple element', () => {
describe('renderSelectedChoices set to "always"', () => {
beforeEach(() => {
instance.isSelectOneElement = false;
instance.config.renderSelectedChoices = 'always';
});
it('calls createChoicesFragment with choices that belong to each group', () => {
expect(createChoicesFragmentStub.called).to.equal(false);
instance.createGroupsFragment(groups, choices);
expect(createChoicesFragmentStub.called).to.equal(true);
expect(createChoicesFragmentStub.firstCall.args[0]).to.eql([
{
id: 1,
selected: true,
groupId: 1,
value: 'Choice 1',
label: 'Choice 1',
},
{
id: 3,
selected: false,
groupId: 1,
value: 'Choice 3',
label: 'Choice 3',
},
]);
expect(createChoicesFragmentStub.secondCall.args[0]).to.eql([
{
id: 2,
selected: false,
groupId: 2,
value: 'Choice 2',
label: 'Choice 2',
},
]);
});
});
describe('renderSelectedChoices not set to "always"', () => {
beforeEach(() => {
instance.isSelectOneElement = false;
instance.config.renderSelectedChoices = false;
});
it('calls createChoicesFragment with choices that belong to each group that are not already selected', () => {
expect(createChoicesFragmentStub.called).to.equal(false);
instance.createGroupsFragment(groups, choices);
expect(createChoicesFragmentStub.called).to.equal(true);
expect(createChoicesFragmentStub.firstCall.args[0]).to.eql([
{
id: 3,
selected: false,
groupId: 1,
value: 'Choice 3',
label: 'Choice 3',
},
]);
expect(createChoicesFragmentStub.secondCall.args[0]).to.eql([
{
id: 2,
selected: false,
groupId: 2,
value: 'Choice 2',
label: 'Choice 2',
},
]);
});
});
});
});
});
describe('renderChoices', () => {
describe('createChoicesFragment', () => {
beforeEach(() => {});
it('returns a fragment of choices', () => {});
});
describe('renderItems', () => {
describe('createItemsFragment', () => {
beforeEach(() => {});
it('returns a fragment of items', () => {});
});

View file

@ -5,7 +5,7 @@ import { DEFAULT_CLASSNAMES, DEFAULT_CONFIG } from '../constants';
describe('components/wrappedElement', () => {
let instance;
let choicesInstance;
let choicesElement;
let element;
beforeEach(() => {
choicesInstance = {
@ -14,8 +14,8 @@ describe('components/wrappedElement', () => {
},
};
choicesElement = document.createElement('select');
instance = new WrappedElement(choicesInstance, choicesElement, DEFAULT_CLASSNAMES);
element = document.createElement('select');
instance = new WrappedElement(choicesInstance, element, DEFAULT_CLASSNAMES);
});
afterEach(() => {
@ -23,9 +23,27 @@ describe('components/wrappedElement', () => {
instance = null;
});
describe('constructor', () => {
it('assigns choices instance to class', () => {
expect(instance.parentInstance).to.eql(choicesInstance);
});
it('assigns choices element to class', () => {
expect(instance.element).to.eql(element);
});
it('assigns classnames to class', () => {
expect(instance.classNames).to.eql(DEFAULT_CLASSNAMES);
});
it('sets isDisabled flag to false', () => {
expect(instance.isDisabled).to.eql(false);
});
});
describe('getElement', () => {
it('returns DOM reference of element', () => {
expect(instance.getElement()).to.eql(choicesElement);
expect(instance.getElement()).to.eql(element);
});
});

View file

@ -7,7 +7,7 @@ import { DEFAULT_CLASSNAMES, DEFAULT_CONFIG } from '../constants';
describe('components/wrappedInput', () => {
let instance;
let choicesInstance;
let inputElement;
let element;
beforeEach(() => {
choicesInstance = {
@ -15,8 +15,8 @@ describe('components/wrappedInput', () => {
...DEFAULT_CONFIG,
},
};
inputElement = document.createElement('input');
instance = new WrappedInput(choicesInstance, inputElement, DEFAULT_CLASSNAMES);
element = document.createElement('input');
instance = new WrappedInput(choicesInstance, element, DEFAULT_CLASSNAMES);
});
afterEach(() => {
@ -24,6 +24,20 @@ describe('components/wrappedInput', () => {
instance = null;
});
describe('constructor', () => {
it('assigns choices instance to class', () => {
expect(instance.parentInstance).to.eql(choicesInstance);
});
it('assigns choices element to class', () => {
expect(instance.element).to.eql(element);
});
it('assigns classnames to class', () => {
expect(instance.classNames).to.eql(DEFAULT_CLASSNAMES);
});
});
describe('inherited methods', () => {
['getElement', 'conceal', 'reveal', 'enable', 'disable'].forEach((method) => {
describe(method, () => {

View file

@ -7,7 +7,7 @@ import { DEFAULT_CLASSNAMES, DEFAULT_CONFIG } from '../constants';
describe('components/wrappedSelect', () => {
let instance;
let choicesInstance;
let selectElement;
let element;
beforeEach(() => {
choicesInstance = {
@ -16,8 +16,8 @@ describe('components/wrappedSelect', () => {
},
};
selectElement = document.createElement('select');
selectElement.id = 'target';
element = document.createElement('select');
element.id = 'target';
for (let i = 1; i <= 4; i++) {
const option = document.createElement('option');
@ -28,9 +28,9 @@ describe('components/wrappedSelect', () => {
option.setAttribute('placeholder', '');
}
selectElement.appendChild(option);
element.appendChild(option);
}
document.body.appendChild(selectElement);
document.body.appendChild(element);
instance = new WrappedSelect(choicesInstance, document.getElementById('target'), DEFAULT_CLASSNAMES);
});
@ -40,6 +40,20 @@ describe('components/wrappedSelect', () => {
instance = null;
});
describe('constructor', () => {
it('assigns choices instance to class', () => {
expect(instance.parentInstance).to.eql(choicesInstance);
});
it('assigns choices element to class', () => {
expect(instance.element).to.eql(element);
});
it('assigns classnames to class', () => {
expect(instance.classNames).to.eql(DEFAULT_CLASSNAMES);
});
});
describe('inherited methods', () => {
['getElement', 'conceal', 'reveal', 'enable', 'disable'].forEach((method) => {
beforeEach(() => {
@ -77,15 +91,62 @@ describe('components/wrappedSelect', () => {
});
});
// describe('getOptionGroups', () => {
// it('returns all option groups', () => {
describe('getOptionGroups', () => {
it('returns an array of all option groups', () => {
for (let i = 1; i <= 3; i++) {
const group = document.createElement('optgroup');
instance.element.appendChild(group);
}
// });
// });
const output = instance.getOptionGroups();
expect(output.length).to.equal(3);
output.forEach((option) => {
expect(option).to.be.instanceOf(HTMLOptGroupElement);
});
});
});
// describe('setOptions', () => {
describe('setOptions', () => {
let appendDocFragmentStub;
const options = [
{
value: '1',
label: 'Test 1',
selected: false,
disabled: true,
},
{
value: '2',
label: 'Test 2',
selected: true,
disabled: false,
},
];
// });
beforeEach(() => {
appendDocFragmentStub = stub();
instance.appendDocFragment = appendDocFragmentStub;
});
afterEach(() => {
instance.appendDocFragment.reset();
});
it('creates an option element for each passed object, adds it to a fragment and calls appendDocFragment with created fragment', () => {
expect(appendDocFragmentStub.called).to.equal(false);
instance.setOptions(options);
expect(appendDocFragmentStub.called).to.equal(true);
const fragment = appendDocFragmentStub.firstCall.args[0];
const selectElement = document.createElement('select');
selectElement.appendChild(fragment);
expect(fragment).to.be.instanceOf(DocumentFragment);
expect(selectElement.options.length).to.equal(2);
expect(selectElement.options[0].value).to.equal(options[0].value);
expect(selectElement.options[1].value).to.equal(options[1].value);
});
});
describe('appendDocFragment', () => {
it('empties contents of element', () => {

6
types/index.d.ts vendored
View file

@ -911,13 +911,13 @@ export default class Choices {
ajax(fn: (values: any) => any): this;
/** Render group choices into a DOM fragment and append to choice list */
private renderGroups(groups: any[], choices: any[], fragment: DocumentFragment): DocumentFragment;
private createGroupsFragment(groups: any[], choices: any[], fragment: DocumentFragment): DocumentFragment;
/** Render choices into a DOM fragment and append to choice list */
private renderChoices(choices: any[], fragment: DocumentFragment, withinGroup?: boolean): DocumentFragment;
private createChoicesFragment(choices: any[], fragment: DocumentFragment, withinGroup?: boolean): DocumentFragment;
/** Render items into a DOM fragment and append to items list */
private renderItems(items: any[], fragment?: DocumentFragment): void;
private createItemsFragment(items: any[], fragment?: DocumentFragment): void;
/** Render DOM with values */
private render(): void;