mirror of
https://github.com/Choices-js/Choices.git
synced 2024-05-19 14:06:33 +02:00
Add util tests
This commit is contained in:
parent
bfb6571ce9
commit
f286dbc653
|
@ -26,6 +26,7 @@
|
||||||
"devDependencies": true
|
"devDependencies": true
|
||||||
}],
|
}],
|
||||||
"no-console": ["warn", { "allow": ["warn", "error"] }],
|
"no-console": ["warn", { "allow": ["warn", "error"] }],
|
||||||
|
"no-plusplus": "off",
|
||||||
"no-unused-expressions": "off",
|
"no-unused-expressions": "off",
|
||||||
"no-underscore-dangle": "off",
|
"no-underscore-dangle": "off",
|
||||||
"prettier/prettier": ["error", {
|
"prettier/prettier": ["error", {
|
||||||
|
|
|
@ -15,7 +15,7 @@ function ignoreExtensions(extensions = [], returnValue = {}) {
|
||||||
return returnValue;
|
return returnValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
extensions.forEach((ext) => {
|
extensions.forEach(ext => {
|
||||||
require.extensions[ext] = noop;
|
require.extensions[ext] = noop;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -35,7 +35,7 @@ function mockRAF(global) {
|
||||||
|
|
||||||
global.requestAnimationFrame = callback => callbacksQueue.push(callback) - 1;
|
global.requestAnimationFrame = callback => callbacksQueue.push(callback) - 1;
|
||||||
|
|
||||||
global.cancelAnimationFrame = (id) => {
|
global.cancelAnimationFrame = id => {
|
||||||
callbacksQueue[id] = false;
|
callbacksQueue[id] = false;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -46,6 +46,7 @@ global.navigator = {
|
||||||
userAgent: 'node.js',
|
userAgent: 'node.js',
|
||||||
};
|
};
|
||||||
global.CustomEvent = window.CustomEvent;
|
global.CustomEvent = window.CustomEvent;
|
||||||
|
global.Element = window.Element;
|
||||||
global.HTMLElement = window.HTMLElement;
|
global.HTMLElement = window.HTMLElement;
|
||||||
global.HTMLOptionElement = window.HTMLOptionElement;
|
global.HTMLOptionElement = window.HTMLOptionElement;
|
||||||
global.HTMLOptGroupElement = window.HTMLOptGroupElement;
|
global.HTMLOptGroupElement = window.HTMLOptGroupElement;
|
||||||
|
|
|
@ -86,11 +86,10 @@
|
||||||
],
|
],
|
||||||
"nyc": {
|
"nyc": {
|
||||||
"include": [
|
"include": [
|
||||||
"src/**/**/**/**/**/*.js"
|
"src/scripts/**/**/*.js"
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"src/**/**/**/**/**/*.test.js",
|
"src/scripts/**/**/*.test.js"
|
||||||
"src/scripts/src/lib/polyfills.js"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,15 +38,15 @@ export const generateId = function(element, prefix) {
|
||||||
(element.name && `${element.name}-${generateChars(2)}`) ||
|
(element.name && `${element.name}-${generateChars(2)}`) ||
|
||||||
generateChars(4);
|
generateChars(4);
|
||||||
id = id.replace(/(:|\.|\[|\]|,)/g, '');
|
id = id.replace(/(:|\.|\[|\]|,)/g, '');
|
||||||
id = prefix + id;
|
id = `${prefix}-${id}`;
|
||||||
|
|
||||||
return id;
|
return id;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the type of an object
|
* Gets the type of an object
|
||||||
* @param {String} type Type to test object against
|
* Why not use typeof? See here: http: //bonsaiden.github.io/JavaScript-Garden/#types.typeof
|
||||||
* @param {Object} obj Object to be tested
|
* @param {Object} obj Object to check
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
export const getType = function(obj) {
|
export const getType = function(obj) {
|
||||||
|
@ -69,14 +69,9 @@ export const isType = function(type, obj) {
|
||||||
* @param {Object} obj Object to be tested
|
* @param {Object} obj Object to be tested
|
||||||
* @return {Boolean}
|
* @return {Boolean}
|
||||||
*/
|
*/
|
||||||
export const isElement = o =>
|
export const isElement = (element) => {
|
||||||
typeof HTMLElement === 'object'
|
return element instanceof Element;
|
||||||
? o instanceof HTMLElement // DOM2
|
};
|
||||||
: o &&
|
|
||||||
typeof o === 'object' &&
|
|
||||||
o !== null &&
|
|
||||||
o.nodeType === 1 &&
|
|
||||||
typeof o.nodeName === 'string';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merges unspecified amount of objects into new object
|
* Merges unspecified amount of objects into new object
|
||||||
|
@ -294,8 +289,14 @@ export const sortByAlpha = (a, b) => {
|
||||||
const labelA = (a.label || a.value).toLowerCase();
|
const labelA = (a.label || a.value).toLowerCase();
|
||||||
const labelB = (b.label || b.value).toLowerCase();
|
const labelB = (b.label || b.value).toLowerCase();
|
||||||
|
|
||||||
if (labelA < labelB) return -1;
|
if (labelA < labelB) {
|
||||||
if (labelA > labelB) return 1;
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (labelA > labelB) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -364,20 +365,20 @@ export const reduceToValues = (items, key = 'value') => {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fetch properties from object
|
* Fetch properties from object
|
||||||
* @param {Object} object Related object
|
* @param {Object} object Related object
|
||||||
* @param {String} properties Properties from object
|
* @param {String} path Path to value
|
||||||
*/
|
*/
|
||||||
export const fetchFromObject = (object, properties) => {
|
export const fetchFromObject = (object, path) => {
|
||||||
const index = properties.indexOf('.');
|
const index = path.indexOf('.');
|
||||||
|
|
||||||
if (index > -1) {
|
if (index > -1) {
|
||||||
return fetchFromObject(
|
return fetchFromObject(
|
||||||
object[properties.substring(0, index)],
|
object[path.substring(0, index)],
|
||||||
properties.substr(index + 1),
|
path.substr(index + 1),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return object[properties];
|
return object[path];
|
||||||
};
|
};
|
||||||
|
|
||||||
export const isIE11 = () =>
|
export const isIE11 = () =>
|
||||||
|
@ -386,13 +387,13 @@ export const isIE11 = () =>
|
||||||
navigator.userAgent.match(/rv[ :]11/)
|
navigator.userAgent.match(/rv[ :]11/)
|
||||||
);
|
);
|
||||||
|
|
||||||
export const existsInArray = (array, value) =>
|
export const existsInArray = (array, value, key = 'value') =>
|
||||||
array.some(item => {
|
array.some(item => {
|
||||||
if (isType('String', value)) {
|
if (isType('String', value)) {
|
||||||
return item.value === value.trim();
|
return item[key] === value.trim();
|
||||||
}
|
}
|
||||||
|
|
||||||
return item.value === value;
|
return item[key] === value;
|
||||||
});
|
});
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,5 +1,22 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { reduceToValues } from './utils';
|
import { stub } from 'sinon';
|
||||||
|
import {
|
||||||
|
reduceToValues,
|
||||||
|
getRandomNumber,
|
||||||
|
generateChars,
|
||||||
|
generateId,
|
||||||
|
getType,
|
||||||
|
isType,
|
||||||
|
isElement,
|
||||||
|
stripHTML,
|
||||||
|
sortByAlpha,
|
||||||
|
sortByScore,
|
||||||
|
fetchFromObject,
|
||||||
|
existsInArray,
|
||||||
|
cloneObject,
|
||||||
|
regexFilter,
|
||||||
|
dispatchEvent,
|
||||||
|
} from './utils';
|
||||||
|
|
||||||
describe('utils', () => {
|
describe('utils', () => {
|
||||||
describe('reduceToValues', () => {
|
describe('reduceToValues', () => {
|
||||||
|
@ -49,4 +66,265 @@ describe('utils', () => {
|
||||||
expect(actualResponse).to.eql(expectedResponse);
|
expect(actualResponse).to.eql(expectedResponse);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('getRandomNumber', () => {
|
||||||
|
it('returns random number between range', () => {
|
||||||
|
for (let index = 0; index < 10; index++) {
|
||||||
|
const output = getRandomNumber(1, 10);
|
||||||
|
expect(output).to.be.a('number');
|
||||||
|
expect(output).to.be.within(1, 10);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('generateChars', () => {
|
||||||
|
it('generates a string of random chars with given length', () => {
|
||||||
|
const output = generateChars(10);
|
||||||
|
expect(output).to.be.a('string');
|
||||||
|
expect(output).to.have.length(10);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('generateId', () => {
|
||||||
|
describe('when given element has id value', () => {
|
||||||
|
it('generates a unique prefixed id based on given elements id', () => {
|
||||||
|
const element = document.createElement('div');
|
||||||
|
element.id = 'test-id';
|
||||||
|
const prefix = 'test-prefix';
|
||||||
|
|
||||||
|
const output = generateId(element, prefix);
|
||||||
|
|
||||||
|
expect(output).to.equal(`${prefix}-${element.id}`);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when given element has no id value but name value', () => {
|
||||||
|
it('generates a unique prefixed id based on given elements name plus 2 random characters', () => {
|
||||||
|
const element = document.createElement('div');
|
||||||
|
element.name = 'test-name';
|
||||||
|
const prefix = 'test-prefix';
|
||||||
|
|
||||||
|
const output = generateId(element, prefix);
|
||||||
|
const expectedOutput = `${prefix}-${element.name}-`;
|
||||||
|
|
||||||
|
expect(output).to.contain(expectedOutput);
|
||||||
|
expect(output).to.have.length(expectedOutput.length + 2);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('when given element has no id value and no name value', () => {
|
||||||
|
it('generates a unique prefixed id based on 4 random characters', () => {
|
||||||
|
const element = document.createElement('div');
|
||||||
|
const prefix = 'test-prefix';
|
||||||
|
|
||||||
|
const output = generateId(element, prefix);
|
||||||
|
const expectedOutput = `${prefix}-`;
|
||||||
|
|
||||||
|
expect(output).to.contain(expectedOutput);
|
||||||
|
expect(output).to.have.length(expectedOutput.length + 4);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('getType', () => {
|
||||||
|
it('returns type of given object', () => {
|
||||||
|
expect(getType({})).to.equal('Object');
|
||||||
|
expect(getType(1)).to.equal('Number');
|
||||||
|
expect(getType(true)).to.equal('Boolean');
|
||||||
|
expect(getType([])).to.equal('Array');
|
||||||
|
expect(getType(() => {})).to.equal('Function');
|
||||||
|
expect(getType(new Error())).to.equal('Error');
|
||||||
|
expect(getType(new RegExp())).to.equal('RegExp');
|
||||||
|
expect(getType(new String())).to.equal('String'); // eslint-disable-line
|
||||||
|
expect(getType('')).to.equal('String');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isType', () => {
|
||||||
|
it('checks with given object type equals given type', () => {
|
||||||
|
expect(isType('Object', {})).to.equal(true);
|
||||||
|
expect(isType('String', {})).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('isElement', () => {
|
||||||
|
it('checks with given object is an element', () => {
|
||||||
|
const element = document.createElement('div');
|
||||||
|
expect(isElement(element)).to.equal(true);
|
||||||
|
expect(isElement({})).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('stripHTML', () => {
|
||||||
|
it('strips HTML from value', () => {
|
||||||
|
const value = '<script>somethingMalicious();</script>';
|
||||||
|
const output = stripHTML(value);
|
||||||
|
expect(output).to.equal(
|
||||||
|
'<script&rt;somethingMalicious();</script&rt;',
|
||||||
|
);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('sortByAlpha', () => {
|
||||||
|
describe('sorting an array', () => {
|
||||||
|
it('sorts by value alphabetically', () => {
|
||||||
|
const values = [
|
||||||
|
{ value: 'The Strokes' },
|
||||||
|
{ value: 'Arctic Monkeys' },
|
||||||
|
{ value: 'Oasis' },
|
||||||
|
{ value: 'Tame Impala' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const output = values.sort(sortByAlpha);
|
||||||
|
|
||||||
|
expect(output).to.eql([
|
||||||
|
{ value: 'Arctic Monkeys' },
|
||||||
|
{ value: 'Oasis' },
|
||||||
|
{ value: 'Tame Impala' },
|
||||||
|
{ value: 'The Strokes' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('sorts by label alphabetically', () => {
|
||||||
|
const values = [
|
||||||
|
{ label: 'The Strokes' },
|
||||||
|
{ label: 'Arctic Monkeys' },
|
||||||
|
{ label: 'Oasis' },
|
||||||
|
{ label: 'Tame Impala' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const output = values.sort(sortByAlpha);
|
||||||
|
|
||||||
|
expect(output).to.eql([
|
||||||
|
{ label: 'Arctic Monkeys' },
|
||||||
|
{ label: 'Oasis' },
|
||||||
|
{ label: 'Tame Impala' },
|
||||||
|
{ label: 'The Strokes' },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('sortByScore', () => {
|
||||||
|
describe('sorting an array', () => {
|
||||||
|
it('sorts by score ascending', () => {
|
||||||
|
const values = [
|
||||||
|
{ score: 10 },
|
||||||
|
{ score: 3001 },
|
||||||
|
{ score: 124 },
|
||||||
|
{ score: 400 },
|
||||||
|
];
|
||||||
|
|
||||||
|
const output = values.sort(sortByScore);
|
||||||
|
|
||||||
|
expect(output).to.eql([
|
||||||
|
{ score: 10 },
|
||||||
|
{ score: 124 },
|
||||||
|
{ score: 400 },
|
||||||
|
{ score: 3001 },
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('dispatchEvent', () => {
|
||||||
|
it('dispatches custom event of given type on given element', () => {
|
||||||
|
const fakeElement = {
|
||||||
|
dispatchEvent: stub(),
|
||||||
|
};
|
||||||
|
const eventType = 'testEvent';
|
||||||
|
const customArgs = {
|
||||||
|
testing: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
dispatchEvent(fakeElement, eventType, customArgs);
|
||||||
|
|
||||||
|
expect(fakeElement.dispatchEvent.called).to.equal(true);
|
||||||
|
const event = fakeElement.dispatchEvent.lastCall.args[0];
|
||||||
|
expect(event).to.be.instanceof(CustomEvent);
|
||||||
|
expect(event.bubbles).to.equal(true);
|
||||||
|
expect(event.cancelable).to.equal(true);
|
||||||
|
expect(event.detail).to.equal(customArgs);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('regexFilter', () => {
|
||||||
|
it('tests given regex against given value', () => {
|
||||||
|
// An email address regex
|
||||||
|
const regex = /^(([^<>()\[\]\\.,;:\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,}))$/;
|
||||||
|
|
||||||
|
expect(regexFilter('joe@bloggs.com', regex)).to.equal(true);
|
||||||
|
expect(regexFilter('joe bloggs', regex)).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('reduceToValues', () => {
|
||||||
|
it('reduces an array of objects to an array of values using given key', () => {
|
||||||
|
const values = [
|
||||||
|
{ name: 'The Strokes' },
|
||||||
|
{ name: 'Arctic Monkeys' },
|
||||||
|
{ name: 'Oasis' },
|
||||||
|
{ name: 'Tame Impala' },
|
||||||
|
];
|
||||||
|
|
||||||
|
const output = reduceToValues(values, 'name');
|
||||||
|
expect(output).to.eql([
|
||||||
|
'The Strokes',
|
||||||
|
'Arctic Monkeys',
|
||||||
|
'Oasis',
|
||||||
|
'Tame Impala',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('fetchFromObject', () => {
|
||||||
|
it('fetches value from object using given path', () => {
|
||||||
|
const object = {
|
||||||
|
band: {
|
||||||
|
name: 'The Strokes',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const output = fetchFromObject(object, 'band.name');
|
||||||
|
expect(output).to.equal(object.band.name);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('existsInArray', () => {
|
||||||
|
it('determines whether a value exists within given array', () => {
|
||||||
|
const values = [
|
||||||
|
{ value: 'The Strokes' },
|
||||||
|
{ value: 'Arctic Monkeys' },
|
||||||
|
{ value: 'Oasis' },
|
||||||
|
{ value: 'Tame Impala' },
|
||||||
|
];
|
||||||
|
|
||||||
|
expect(existsInArray(values, 'Oasis', 'value')).to.equal(true);
|
||||||
|
expect(existsInArray(values, 'The Beatles', 'value')).to.equal(false);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('cloneObject', () => {
|
||||||
|
it('deeply clones a given object', () => {
|
||||||
|
const object = {
|
||||||
|
levelOne: {
|
||||||
|
id: 1,
|
||||||
|
levelTwo: {
|
||||||
|
id: 2,
|
||||||
|
levelThree: {
|
||||||
|
id: 3,
|
||||||
|
levelFour: {
|
||||||
|
id: 4,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const output = cloneObject(object);
|
||||||
|
|
||||||
|
expect(output).to.not.equal(object);
|
||||||
|
expect(output).to.eql(object);
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -15,4 +15,43 @@ describe('reducers/rootReducer', () => {
|
||||||
expect(state.choices).to.equal(choices(undefined, {}));
|
expect(state.choices).to.equal(choices(undefined, {}));
|
||||||
expect(state.items).to.equal(items(undefined, {}));
|
expect(state.items).to.equal(items(undefined, {}));
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('CLEAR_ALL', () => {
|
||||||
|
it('resets state', () => {
|
||||||
|
const output = rootReducer(
|
||||||
|
{
|
||||||
|
items: [1, 2, 3],
|
||||||
|
groups: [1, 2, 3],
|
||||||
|
choices: [1, 2, 3],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'CLEAR_ALL',
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(output).to.eql({
|
||||||
|
items: [],
|
||||||
|
groups: [],
|
||||||
|
choices: [],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('RESET_TO', () => {
|
||||||
|
it('replaces state with given state', () => {
|
||||||
|
const output = rootReducer(
|
||||||
|
{
|
||||||
|
items: [1, 2, 3],
|
||||||
|
groups: [1, 2, 3],
|
||||||
|
choices: [1, 2, 3],
|
||||||
|
},
|
||||||
|
{
|
||||||
|
type: 'RESET_TO',
|
||||||
|
state: {},
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(output).to.eql({});
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
|
Loading…
Reference in a new issue