UNPKG

lucid-ui

Version:

A UI component library from AppNexus.

504 lines (479 loc) 26.4 kB
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'); }); }); }); });