lucid-ui
Version:
A UI component library from AppNexus.
504 lines (479 loc) • 26.4 kB
JavaScript
import _escapeRegExp from "lodash/escapeRegExp";
import _size from "lodash/size";
import _map from "lodash/map";
import _first from "lodash/first";
import _forEach from "lodash/forEach";
import _isEqual from "lodash/isEqual";
import _includes from "lodash/includes";
function _slicedToArray(arr, i) { return _arrayWithHoles(arr) || _iterableToArrayLimit(arr, i) || _unsupportedIterableToArray(arr, i) || _nonIterableRest(); }
function _nonIterableRest() { throw new TypeError("Invalid attempt to destructure non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
function _iterableToArrayLimit(arr, i) { if (typeof Symbol === "undefined" || !(Symbol.iterator in Object(arr))) return; var _arr = []; var _n = true; var _d = false; var _e = undefined; try { for (var _i = arr[Symbol.iterator](), _s; !(_n = (_s = _i.next()).done); _n = true) { _arr.push(_s.value); if (i && _arr.length === i) break; } } catch (err) { _d = true; _e = err; } finally { try { if (!_n && _i["return"] != null) _i["return"](); } finally { if (_d) throw _e; } } return _arr; }
function _arrayWithHoles(arr) { if (Array.isArray(arr)) return arr; }
import React from 'react';
import { mount, shallow } from 'enzyme';
import assert from 'assert';
import sinon from 'sinon';
import { filterTypes, rejectTypes } from '../../util/component-types';
import { common } from '../../util/generic-tests';
import { SearchableSelectDumb as SearchableSelect } from './SearchableSelect';
import { DropMenuDumb as DropMenu } from '../DropMenu/DropMenu';
var _ref = SearchableSelect,
Placeholder = _ref.Placeholder,
Option = _ref.Option,
OptionGroup = _ref.OptionGroup,
SearchField = _ref.SearchField;
describe('SearchableSelect', function () {
common(SearchableSelect, {
exemptFunctionProps: ['optionFilter', 'richChildRenderer']
});
describe('render', function () {
it('should render a DropMenu', function () {
var wrapper = shallow( /*#__PURE__*/React.createElement(SearchableSelect, null, /*#__PURE__*/React.createElement(Placeholder, null, "control"), /*#__PURE__*/React.createElement(Option, null, "option a"), /*#__PURE__*/React.createElement(Option, null, "option b"), /*#__PURE__*/React.createElement(Option, null, "option c")));
assert.equal(wrapper.find('DropMenu').length, 1);
});
});
describe('props', function () {
describe('children', function () {
it('should not render any direct child elements which are not SearchableSelect-specific', function () {
var wrapper = shallow( /*#__PURE__*/React.createElement(SearchableSelect, null, /*#__PURE__*/React.createElement("button", null, "button"), /*#__PURE__*/React.createElement(Placeholder, null, "control", /*#__PURE__*/React.createElement("i", null, "italic")), /*#__PURE__*/React.createElement(Option, null, "option a"), /*#__PURE__*/React.createElement(Option, null, "option b"), /*#__PURE__*/React.createElement(Option, null, "option c"), /*#__PURE__*/React.createElement("h1", null, "header")));
assert.equal(wrapper.find('button').length, 0);
assert.equal(wrapper.find('h1').length, 0);
assert.equal(wrapper.find('i').length, 1);
});
});
describe('hasReset', function () {
var wrapper;
afterEach(function () {
if (wrapper) {
wrapper.unmount();
}
});
it('should render the placeholder option as the first one in the menu and be a null option', function () {
wrapper = mount( /*#__PURE__*/React.createElement(SearchableSelect, {
hasReset: true,
selectedIndex: 1,
DropMenu: {
isExpanded: true
}
}, /*#__PURE__*/React.createElement(Placeholder, null, "select one"), /*#__PURE__*/React.createElement(Option, null, "option a"), /*#__PURE__*/React.createElement(Option, null, "option b"), /*#__PURE__*/React.createElement(Option, null, "option c")));
var menuDOMNode = document.querySelector('.lucid-ContextMenu-FlyOut .lucid-DropMenu-option-container');
assert(_includes(menuDOMNode.children[0].className, 'lucid-DropMenu-Option-is-null'));
});
it('should not render the placeholder null option as the first one in the menu', function () {
wrapper = mount( /*#__PURE__*/React.createElement(SearchableSelect, {
hasReset: false,
selectedIndex: 1,
DropMenu: {
isExpanded: true
}
}, /*#__PURE__*/React.createElement(Placeholder, null, "select one"), /*#__PURE__*/React.createElement(Option, null, "option a"), /*#__PURE__*/React.createElement(Option, null, "option b"), /*#__PURE__*/React.createElement(Option, null, "option c")));
var menuDOMNode = document.querySelector('.lucid-ContextMenu-FlyOut .lucid-DropMenu-option-container');
assert(!_includes(menuDOMNode.children[0].className, 'lucid-DropMenu-Option-is-null'));
});
});
describe('isDisabled', function () {
it('should pass the `isDisabled` prop thru to the underlying DropMenu', function () {
var wrapper = shallow( /*#__PURE__*/React.createElement(SearchableSelect, {
isDisabled: true
}, /*#__PURE__*/React.createElement(Placeholder, null, "select one"), /*#__PURE__*/React.createElement(Option, null, "option a"), /*#__PURE__*/React.createElement(Option, null, "option b"), /*#__PURE__*/React.createElement(Option, null, "option c")));
var dropMenuWrapper = wrapper.find('DropMenu');
assert.equal(dropMenuWrapper.prop('isDisabled'), true);
});
it('should apply the appropriate classNames to the control', function () {
var wrapper = shallow( /*#__PURE__*/React.createElement(SearchableSelect, {
isDisabled: true,
selectedIndex: 2
}, /*#__PURE__*/React.createElement(Placeholder, null, "select one"), /*#__PURE__*/React.createElement(Option, null, "option a"), /*#__PURE__*/React.createElement(Option, null, "option b"), /*#__PURE__*/React.createElement(Option, null, "option c")));
var controlWrapper = wrapper.find('.lucid-SearchableSelect-Control');
assert(controlWrapper.hasClass('lucid-SearchableSelect-Control-is-disabled'));
assert(!controlWrapper.hasClass('lucid-SearchableSelect-Control-is-selected'));
});
});
describe('isLoading', function () {
it('should render a &-Loading Option and disable all Options', function () {
var wrapper = shallow( /*#__PURE__*/React.createElement(SearchableSelect, {
isLoading: true
}, /*#__PURE__*/React.createElement(Placeholder, null, "select one"), /*#__PURE__*/React.createElement(Option, null, "option a"), /*#__PURE__*/React.createElement(Option, null, "option b"), /*#__PURE__*/React.createElement(Option, null, "option c")));
var options = wrapper.find(DropMenu).shallow().find('.lucid-DropMenu-Option'); // first option should be the loading indicator.
assert(options.at(0).hasClass('lucid-SearchableSelect-Loading'));
assert(options.every('.lucid-DropMenu-Option-is-disabled'));
});
});
describe('isSelectionHighlighted', function () {
describe('default', function () {
it('should apply the appropriate classNames to the control', function () {
var wrapper = shallow( /*#__PURE__*/React.createElement(SearchableSelect, {
selectedIndex: 2
}, /*#__PURE__*/React.createElement(Placeholder, null, "select one"), /*#__PURE__*/React.createElement(Option, null, "option a"), /*#__PURE__*/React.createElement(Option, null, "option b"), /*#__PURE__*/React.createElement(Option, null, "option c")));
var controlWrapper = wrapper.find('.lucid-SearchableSelect-Control');
assert(controlWrapper.hasClass('lucid-SearchableSelect-Control-is-selected'));
assert(controlWrapper.hasClass('lucid-SearchableSelect-Control-is-highlighted'));
});
});
describe('false', function () {
it('should apply the appropriate classNames to the control', function () {
var wrapper = shallow( /*#__PURE__*/React.createElement(SearchableSelect, {
isSelectionHighlighted: false,
selectedIndex: 2
}, /*#__PURE__*/React.createElement(Placeholder, null, "select one"), /*#__PURE__*/React.createElement(Option, null, "option a"), /*#__PURE__*/React.createElement(Option, null, "option b"), /*#__PURE__*/React.createElement(Option, null, "option c")));
var controlWrapper = wrapper.find('.lucid-SearchableSelect-Control');
assert(!controlWrapper.hasClass('lucid-SearchableSelect-Control-is-selected'));
assert(!controlWrapper.hasClass('lucid-SearchableSelect-Control-is-highlighted'));
});
});
});
describe('selectedIndex', function () {
it('should pass the selectedIndex in an array of 1 to the underlying DropMenu', function () {
var wrapper = shallow( /*#__PURE__*/React.createElement(SearchableSelect, {
selectedIndex: 2
}, /*#__PURE__*/React.createElement(Placeholder, null, "select one"), /*#__PURE__*/React.createElement(Option, null, "option a"), /*#__PURE__*/React.createElement(Option, null, "option b"), /*#__PURE__*/React.createElement(Option, null, "option c")));
var dropMenuWrapper = wrapper.find('DropMenu');
assert(_isEqual(dropMenuWrapper.prop('selectedIndices'), [2]));
});
it('should render selected option in the control', function () {
var wrapper = shallow( /*#__PURE__*/React.createElement(SearchableSelect, {
selectedIndex: 2
}, /*#__PURE__*/React.createElement(Placeholder, null, "select one"), /*#__PURE__*/React.createElement(Option, null, "option a"), /*#__PURE__*/React.createElement(Option, null, "option b"), /*#__PURE__*/React.createElement(Option, null, "option c")));
var dropMenuControlWrapper = wrapper.find('DropMenu').childAt(0);
assert.equal('option c', dropMenuControlWrapper.find('.lucid-SearchableSelect-Control-content').text());
});
});
describe('maxMenuHeight', function () {
it('should pass through to DropMenu prop `optionContainerStyle.maxHeight`', function () {
var wrapper = shallow( /*#__PURE__*/React.createElement(SearchableSelect, {
maxMenuHeight: 123
}, /*#__PURE__*/React.createElement(Placeholder, null, "select one"), /*#__PURE__*/React.createElement(Option, null, "option a"), /*#__PURE__*/React.createElement(Option, null, "option b"), /*#__PURE__*/React.createElement(Option, null, "option c")));
var dropMenuWrapper = wrapper.find(DropMenu);
var optionContainerStyle = dropMenuWrapper.prop('optionContainerStyle');
assert.equal(123, optionContainerStyle.maxHeight, 'must match prop value');
});
});
describe('onSelect', function () {
/* eslint-disable no-console */
var error, wrapper;
beforeEach(function () {
error = console.error;
console.error = jest.fn();
});
afterEach(function () {
if (wrapper) {
wrapper.unmount();
}
console.error = error;
});
it('should be called when an option is selected with the appropriate arguments', function () {
var onSelect = sinon.spy();
wrapper = mount( /*#__PURE__*/React.createElement(SearchableSelect, {
onSelect: onSelect,
DropMenu: {
isExpanded: true
}
}, /*#__PURE__*/React.createElement(Placeholder, null, "select one"), /*#__PURE__*/React.createElement(Option, null, "option a"), /*#__PURE__*/React.createElement(Option, null, "option b"), /*#__PURE__*/React.createElement(Option, {
testProp: "foo"
}, "option c")));
var menuDOMNode = document.querySelector('.lucid-ContextMenu-FlyOut .lucid-DropMenu-option-container');
menuDOMNode.children[2].click();
assert(onSelect.called);
var _onSelect$lastCall$ar = _slicedToArray(onSelect.lastCall.args, 2),
optionIndex = _onSelect$lastCall$ar[0],
_onSelect$lastCall$ar2 = _onSelect$lastCall$ar[1],
props = _onSelect$lastCall$ar2.props,
event = _onSelect$lastCall$ar2.event;
assert.equal(optionIndex, 2);
assert(props);
assert.equal(props.testProp, 'foo');
assert(event);
});
/* eslint-enable no-console */
});
describe('onSearch', function () {
it('should be called when a new value is entered into the search input', function () {
var onSearch = sinon.spy();
var wrapper = shallow( /*#__PURE__*/React.createElement(SearchableSelect, {
onSearch: onSearch,
DropMenu: {
isExpanded: true
}
}, /*#__PURE__*/React.createElement(Placeholder, null, "select one"), /*#__PURE__*/React.createElement(Option, null, "option a"), /*#__PURE__*/React.createElement(Option, null, "option b"), /*#__PURE__*/React.createElement(Option, {
testProp: "foo"
}, "option c")));
var searchFieldWrapper = wrapper.find(SearchField);
searchFieldWrapper.simulate('change', 'asdf', {
event: {}
});
assert(onSearch.calledWith('asdf'));
});
});
describe('DropMenu', function () {
it('should pass thru all DropMenu props to the underlying DropMenu', function () {
var explicitDropMenuProps = {
isExpanded: true,
direction: 'up',
focusedIndex: 2
};
var wrapper = shallow( /*#__PURE__*/React.createElement(SearchableSelect, {
DropMenu: explicitDropMenuProps
}, /*#__PURE__*/React.createElement(Placeholder, null, "control"), /*#__PURE__*/React.createElement(Option, null, "option a"), /*#__PURE__*/React.createElement(Option, null, "option b"), /*#__PURE__*/React.createElement(Option, null, "option c")));
var dropMenuProps = wrapper.find('DropMenu').props();
_forEach(explicitDropMenuProps, function (value, key) {
assert(_isEqual(dropMenuProps[key], value));
});
});
});
describe('Error', function () {
it('should pass the error class if the Error prop is passed', function () {
var wrapper = shallow( /*#__PURE__*/React.createElement(SearchableSelect, {
Error: 'Error message'
}, /*#__PURE__*/React.createElement(Placeholder, null, "control"), /*#__PURE__*/React.createElement(Option, null, "option a"), /*#__PURE__*/React.createElement(Option, null, "option b"), /*#__PURE__*/React.createElement(Option, null, "option c")));
var searchWrapper = wrapper.find('.lucid-SearchableSelect-Control-is-error');
var errorWrapper = wrapper.find('.lucid-SearchableSelect-error-content');
expect(errorWrapper.exists()).toBeTruthy();
expect(searchWrapper.exists()).toBeTruthy();
expect(errorWrapper.text()).toEqual('Error message');
});
});
});
describe('child elements', function () {
describe('SearchField', function () {
it('should pass the searchfield props through to the underlying SearchField element', function () {
var wrapper = shallow( /*#__PURE__*/React.createElement(SearchableSelect, {
DropMenu: {
isExpanded: true
}
}, /*#__PURE__*/React.createElement(SearchField, {
placeholder: "custom"
}), /*#__PURE__*/React.createElement(Option, {
name: "OptionA"
}, "option a"), /*#__PURE__*/React.createElement(Option, {
name: "OptionB"
}, "option b"), /*#__PURE__*/React.createElement(Option, {
name: "OptionC"
}, "option c")));
var dropMenuHeader = wrapper.childAt(0).childAt(1);
var searchFieldWrapper = dropMenuHeader.childAt(0);
assert.equal(searchFieldWrapper.prop('placeholder'), 'custom');
});
});
describe('Placeholder', function () {
it('should pass the placeholder thru to the underlying DropMenu Control when no option is selected', function () {
var wrapper = shallow( /*#__PURE__*/React.createElement(SearchableSelect, {
selectedIndex: null
}, /*#__PURE__*/React.createElement(Placeholder, null, "select one"), /*#__PURE__*/React.createElement(Option, {
name: "OptionA"
}, "option a"), /*#__PURE__*/React.createElement(Option, {
name: "OptionB"
}, "option b"), /*#__PURE__*/React.createElement(Option, {
name: "OptionC"
}, "option c"))); // navigate down the virutal DOM tree to find the Control content
var dropMenuWrapper = wrapper.find('DropMenu');
var dropMenuChildren = dropMenuWrapper.prop('children');
var controlProps = _first(_map(filterTypes(dropMenuChildren, DropMenu.Control), 'props'));
var dropMenuControlChildElement = _first(React.Children.toArray(controlProps.children));
var SearchableSelectControlChildren = React.Children.toArray(dropMenuControlChildElement.props.children);
var SearchableSelectControlContent = SearchableSelectControlChildren[0];
assert.equal(React.Children.toArray(SearchableSelectControlContent.props.children)[0], 'select one');
});
it('should pass the placeholder thru to the underlying DropMenu NullOption when an option is selected', function () {
var wrapper = shallow( /*#__PURE__*/React.createElement(SearchableSelect, {
selectedIndex: 1
}, /*#__PURE__*/React.createElement(Placeholder, null, "select one"), /*#__PURE__*/React.createElement(Option, {
name: "OptionA"
}, "option a"), /*#__PURE__*/React.createElement(Option, {
name: "OptionB"
}, "option b"), /*#__PURE__*/React.createElement(Option, {
name: "OptionC"
}, "option c"))); // navigate down the virutal DOM tree to find the Control content
var dropMenuWrapper = wrapper.find('DropMenu');
var dropMenuChildren = dropMenuWrapper.prop('children');
var nullOptionProps = _first(_map(filterTypes(dropMenuChildren, DropMenu.NullOption), 'props'));
assert.equal(React.Children.toArray(nullOptionProps.children)[0], 'select one');
});
});
describe('Option', function () {
it('should pass options thru to the underlying DropMenu', function () {
var wrapper = shallow( /*#__PURE__*/React.createElement(SearchableSelect, null, /*#__PURE__*/React.createElement(Placeholder, null, "select one"), /*#__PURE__*/React.createElement(Option, {
name: "OptionA"
}, "option a"), /*#__PURE__*/React.createElement(Option, {
name: "OptionB"
}, "option b"), /*#__PURE__*/React.createElement(Option, {
name: "OptionC"
}, "option c")));
var dropMenuWrapper = wrapper.find('DropMenu');
var dropMenuChildren = dropMenuWrapper.prop('children');
var optionsProps = _map(filterTypes(dropMenuChildren, DropMenu.Option), 'props');
assert.equal(_size(optionsProps), 3);
assert(_isEqual(optionsProps[0], {
name: 'OptionA',
children: 'option a',
isDisabled: false,
isHidden: false,
isWrapped: true
}));
assert(_isEqual(optionsProps[1], {
name: 'OptionB',
children: 'option b',
isDisabled: false,
isHidden: false,
isWrapped: true
}));
assert(_isEqual(optionsProps[2], {
name: 'OptionC',
children: 'option c',
isDisabled: false,
isHidden: false,
isWrapped: true
}));
});
it('should render Option.Selected in the Placeholder area', function () {
expect(shallow( /*#__PURE__*/React.createElement(SearchableSelect, {
selectedIndex: 1
}, /*#__PURE__*/React.createElement(Placeholder, null, "select one"), /*#__PURE__*/React.createElement(Option, {
name: "OptionA",
Selected: "option a"
}, /*#__PURE__*/React.createElement("div", {
style: {
display: 'flex'
}
}, /*#__PURE__*/React.createElement("div", {
style: {
width: 100
}
}, "id"), /*#__PURE__*/React.createElement("div", null, "option a"))), /*#__PURE__*/React.createElement(Option, {
name: "OptionB",
Selected: "option b"
}, /*#__PURE__*/React.createElement("div", {
style: {
display: 'flex'
}
}, /*#__PURE__*/React.createElement("div", {
style: {
width: 100
}
}, "id"), /*#__PURE__*/React.createElement("div", null, "option b"))), /*#__PURE__*/React.createElement(Option, {
name: "OptionC",
Selected: "option c"
}, /*#__PURE__*/React.createElement("div", {
style: {
display: 'flex'
}
}, /*#__PURE__*/React.createElement("div", {
style: {
width: 100
}
}, "id"), /*#__PURE__*/React.createElement("div", null, "option c")))))).toMatchSnapshot();
});
it('should render Option child function by passing in {searchText}, setting filterText on each option and using a custom optionFilter', function () {
var optionFilter = function optionFilter(searchText, _ref2) {
var filterText = _ref2.filterText;
if (filterText) {
return new RegExp(_escapeRegExp(searchText), 'i').test(filterText);
}
return true;
};
expect(shallow( /*#__PURE__*/React.createElement(SearchableSelect, {
optionFilter: optionFilter,
searchText: "tion"
}, /*#__PURE__*/React.createElement(Placeholder, null, "select one"), /*#__PURE__*/React.createElement(Option, {
name: "OptionA",
Selected: "option a",
filterText: "option a"
}, function (_ref3) {
var searchText = _ref3.searchText;
return /*#__PURE__*/React.createElement("div", {
style: {
display: 'flex'
}
}, /*#__PURE__*/React.createElement("div", {
style: {
width: 100
}
}, searchText), /*#__PURE__*/React.createElement("div", null, "option a"));
}), /*#__PURE__*/React.createElement(Option, {
name: "OptionB",
Selected: "option b",
filterText: "option b"
}, function (_ref4) {
var searchText = _ref4.searchText;
return /*#__PURE__*/React.createElement("div", {
style: {
display: 'flex'
}
}, /*#__PURE__*/React.createElement("div", {
style: {
width: 100
}
}, searchText), /*#__PURE__*/React.createElement("div", null, "option b"));
}), /*#__PURE__*/React.createElement(Option, {
name: "OptionC",
Selected: "option c",
filterText: "option c"
}, function (_ref5) {
var searchText = _ref5.searchText;
return /*#__PURE__*/React.createElement("div", {
style: {
display: 'flex'
}
}, /*#__PURE__*/React.createElement("div", {
style: {
width: 100
}
}, searchText), /*#__PURE__*/React.createElement("div", null, "option c"));
})))).toMatchSnapshot();
});
});
describe('OptionGroup', function () {
var wrapper;
var dropMenuWrapper;
var dropMenuChildren;
var optionGroupProps;
beforeEach(function () {
wrapper = shallow( /*#__PURE__*/React.createElement(SearchableSelect, null, /*#__PURE__*/React.createElement(Placeholder, null, "select one"), /*#__PURE__*/React.createElement(OptionGroup, {
name: "TestGroup"
}, "Group Label", /*#__PURE__*/React.createElement(Option, {
name: "OptionA"
}, "option a"), /*#__PURE__*/React.createElement(Option, {
name: "OptionB"
}, "option b"), /*#__PURE__*/React.createElement(Option, {
name: "OptionC"
}, "option c"))));
dropMenuWrapper = wrapper.find('DropMenu');
dropMenuChildren = dropMenuWrapper.prop('children');
optionGroupProps = _first(_map(filterTypes(dropMenuChildren, DropMenu.OptionGroup), 'props'));
});
it('should pass thru all props to the underlying DropMenu OptionGroup', function () {
assert.equal(optionGroupProps.name, 'TestGroup');
});
it('should pass options thru to the underlying DropMenu OptionGroup Options', function () {
var optionsProps = _map(filterTypes(optionGroupProps.children, DropMenu.Option), 'props');
assert.equal(_size(optionsProps), 3);
assert(_isEqual(optionsProps[0], {
name: 'OptionA',
children: 'option a',
isDisabled: false,
isHidden: false,
isWrapped: true
}));
assert(_isEqual(optionsProps[1], {
name: 'OptionB',
children: 'option b',
isDisabled: false,
isHidden: false,
isWrapped: true
}));
assert(_isEqual(optionsProps[2], {
name: 'OptionC',
children: 'option c',
isDisabled: false,
isHidden: false,
isWrapped: true
}));
});
it('should pass all other elemens thru to the underlying DropMenu OptionGroup', function () {
var otherOptionGroupChildren = rejectTypes(optionGroupProps.children, [Placeholder, Option, OptionGroup]);
assert.equal(_first(otherOptionGroupChildren), 'Group Label');
});
});
});
});