UNPKG

lucid-ui

Version:

A UI component library from AppNexus.

363 lines (331 loc) 16.5 kB
import _noop from "lodash/noop"; import _isEqual from "lodash/isEqual"; import _forEach from "lodash/forEach"; import _map from "lodash/map"; 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; } function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); if (enumerableOnly) symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; } function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { ownKeys(Object(source), true).forEach(function (key) { _defineProperty(target, key, source[key]); }); } else if (Object.getOwnPropertyDescriptors) { Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)); } else { ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } } return target; } function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } import React from 'react'; import { mount, shallow } from 'enzyme'; import assert from 'assert'; import sinon from 'sinon'; import { findTypes } from '../../util/component-types'; import { common } from '../../util/generic-tests'; import { AutocompleteDumb as Autocomplete } from './Autocomplete'; import { DropMenuDumb as DropMenu } from '../DropMenu/DropMenu'; import * as KEYCODE from '../../constants/key-code'; describe('Autocomplete', function () { common(Autocomplete); describe('render', function () { it('should render a DropMenu', function () { var wrapper = shallow( /*#__PURE__*/React.createElement(Autocomplete, null), { disableLifecycleMethods: true }); assert.equal(wrapper.find('DropMenu').length, 1); }); }); describe('props', function () { describe('isDisabled', function () { it('should pass the `isDisabled` prop thru to the underlying DropMenu', function () { var wrapper = shallow( /*#__PURE__*/React.createElement(Autocomplete, { isDisabled: true }), { disableLifecycleMethods: true }); 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(Autocomplete, { isDisabled: true }), { disableLifecycleMethods: true }); var controlWrapper = wrapper.find('.lucid-Autocomplete-Control'); assert(controlWrapper.hasClass('lucid-Autocomplete-Control-is-disabled')); }); }); describe('suggestions', function () { it('should create `DropMenu.Option`s for each suggestion and pass thru to underlying DropMenu', function () { var wrapper = shallow( /*#__PURE__*/React.createElement(Autocomplete, { suggestions: ['Portland', 'portal', 'porridge', 'potent', 'please'] }), { disableLifecycleMethods: true }); var options = _map(findTypes(wrapper.find(DropMenu).props(), DropMenu.Option), 'props'); assert.equal('Portland', options[0].children); assert.equal('portal', options[1].children); assert.equal('porridge', options[2].children); assert.equal('potent', options[3].children); assert.equal('please', options[4].children); }); }); describe('value', function () { var wrapper; var rootMountNode; beforeEach(function () { rootMountNode = document.createElement('div'); document.body.appendChild(rootMountNode); }); afterEach(function () { if (wrapper) { wrapper.unmount(); } document.body.removeChild(rootMountNode); }); it('should set the text value of the input', function () { wrapper = mount( /*#__PURE__*/React.createElement(Autocomplete, { value: "Portland" }), { attachTo: rootMountNode }); var inputDOMNode = document.querySelector('.lucid-Autocomplete-Control-input'); assert.equal(inputDOMNode.value, 'Portland', 'input value must match prop value'); }); it('should change the text value of the input when the prop changes', function () { wrapper = mount( /*#__PURE__*/React.createElement(Autocomplete, { value: "Portland" }), { attachTo: rootMountNode }); wrapper.setProps(_objectSpread(_objectSpread({}, wrapper.props()), {}, { value: 'Boston' })); var inputDOMNode = document.querySelector('.lucid-Autocomplete-Control-input'); assert.equal(inputDOMNode.value, 'Boston', 'input value must match bew prop value'); }); }); 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(Autocomplete, { DropMenu: explicitDropMenuProps }), { disableLifecycleMethods: true }); var dropMenuProps = wrapper.find('DropMenu').props(); _forEach(explicitDropMenuProps, function (value, key) { assert(_isEqual(dropMenuProps[key], value)); }); }); }); describe('onChange', function () { var wrapper; var rootMountNode; beforeEach(function () { rootMountNode = document.createElement('div'); document.body.appendChild(rootMountNode); }); afterEach(function () { if (wrapper) { wrapper.unmount(); } document.body.removeChild(rootMountNode); }); describe('suggestion', function () { /* eslint-disable no-console */ var error; beforeEach(function () { error = console.error; console.error = jest.fn(); }); afterEach(function () { console.error = error; }); it('should be called when a suggestion is selected from the menu', function () { var onChange = sinon.spy(); wrapper = mount( /*#__PURE__*/React.createElement(Autocomplete, { onChange: onChange, DropMenu: { isExpanded: true }, suggestions: ['Portland', 'portal', 'porridge', 'potent', 'please'], testProp: 'foo' })); var menuDOMNode = document.querySelector('.lucid-ContextMenu-FlyOut .lucid-DropMenu-option-container'); menuDOMNode.children[2].click(); assert(onChange.called); var _onChange$lastCall$ar = _slicedToArray(onChange.lastCall.args, 2), textValue = _onChange$lastCall$ar[0], _onChange$lastCall$ar2 = _onChange$lastCall$ar[1], props = _onChange$lastCall$ar2.props, event = _onChange$lastCall$ar2.event; assert.equal(textValue, 'porridge'); assert(props); assert.equal(props.testProp, 'foo'); assert(event); expect(console.error).toHaveBeenCalledTimes(1); }); it('should be called when user types into the text box', function () { var onChange = sinon.spy(); wrapper = mount( /*#__PURE__*/React.createElement(Autocomplete, { onChange: onChange, testProp: 'foo' }), { attachTo: rootMountNode }); var inputDOMNode = document.querySelector('.lucid-Autocomplete-Control-input'); // set the input value and dispatch an `input` event inputDOMNode.value = 'aaa'; var inputEvent = document.createEvent('Event'); inputEvent.initEvent('input', true, true); inputDOMNode.dispatchEvent(inputEvent); assert(onChange.called, 'onChange must be called'); var _onChange$lastCall$ar3 = _slicedToArray(onChange.lastCall.args, 2), textValue = _onChange$lastCall$ar3[0], _onChange$lastCall$ar4 = _onChange$lastCall$ar3[1], props = _onChange$lastCall$ar4.props, event = _onChange$lastCall$ar4.event; assert.equal(textValue, 'aaa', 'value must match input'); assert(props, 'props must be passed'); assert.equal(props.testProp, 'foo', 'aditional props must be included'); assert(event, 'event must be passed'); }); /* eslint-enable no-console */ }); }); describe('onSelect', function () { var wrapper; afterEach(function () { if (wrapper) { wrapper.unmount(); } }); it('should be called when a suggestion is selected from the menu', function () { var onSelect = sinon.spy(); wrapper = mount( /*#__PURE__*/React.createElement(Autocomplete, { onSelect: onSelect, DropMenu: { isExpanded: true }, suggestions: ['Portland', 'portal', 'porridge', 'potent', 'please'], testProp: 'foo' })); var menuDOMNode = document.querySelector('.lucid-ContextMenu-FlyOut .lucid-DropMenu-option-container'); menuDOMNode.children[2].click(); assert(onSelect.called, 'onSelect must be 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, 'optionIndex must be accurate'); assert(props, 'props must be passed'); assert.equal(props.testProp, 'foo', 'aditional props must be included'); assert(event, 'event must be passed'); }); }); describe('onExpand', function () { var wrapper; var rootMountNode; beforeEach(function () { rootMountNode = document.createElement('div'); document.body.appendChild(rootMountNode); }); afterEach(function () { if (wrapper && wrapper.exists()) { wrapper.unmount(); } document.body.removeChild(rootMountNode); }); it('should be called when the input value changes to a non-empty value', function () { var onExpand = sinon.spy(); wrapper = mount( /*#__PURE__*/React.createElement(Autocomplete, { onExpand: onExpand, suggestions: ['Portland', 'portal', 'porridge', 'potent', 'please'], testProp: 'foo' }), { attachTo: rootMountNode }); var inputDOMNode = document.querySelector('.lucid-Autocomplete-Control-input'); // set the input value and dispatch an `input` event inputDOMNode.value = 'aaa'; var inputEvent = document.createEvent('Event'); inputEvent.initEvent('input', true, true); inputDOMNode.dispatchEvent(inputEvent); assert(onExpand.called, 'onExpand must be called'); var _onExpand$lastCall$ar = _slicedToArray(onExpand.lastCall.args, 1), _onExpand$lastCall$ar2 = _onExpand$lastCall$ar[0], props = _onExpand$lastCall$ar2.props, event = _onExpand$lastCall$ar2.event; assert(props, 'props must be passed'); assert.equal(props.testProp, 'foo', 'aditional props must be included'); assert(event, 'event must be passed'); }); it('should be called when not expanded and down array key is pressed', function () { var onExpand = sinon.spy(); var wrapper = shallow( /*#__PURE__*/React.createElement(Autocomplete, { onExpand: onExpand, suggestions: ['Portland', 'portal', 'porridge', 'potent', 'please'], testProp: 'foo', DropMenu: { isExpanded: false } }), { disableLifecycleMethods: true }); wrapper.find('.lucid-Autocomplete-Control-input').simulate('keydown', { keyCode: KEYCODE.ArrowDown, stopPropagation: _noop }); assert(onExpand.called, 'onExpand must be called'); var _onExpand$lastCall$ar3 = _slicedToArray(onExpand.lastCall.args, 1), _onExpand$lastCall$ar4 = _onExpand$lastCall$ar3[0], props = _onExpand$lastCall$ar4.props, event = _onExpand$lastCall$ar4.event; assert(props, 'props must be passed'); assert.equal(props.testProp, 'foo', 'aditional props must be included'); assert(event, 'event must be passed'); }); it('should be called when the control input is clicked', function () { var onExpand = sinon.spy(); wrapper = mount( /*#__PURE__*/React.createElement(Autocomplete, { onExpand: onExpand, suggestions: ['Portland', 'portal', 'porridge', 'potent', 'please'], testProp: 'foo' }), { attachTo: rootMountNode }); wrapper.find('.lucid-Autocomplete-Control-input').simulate('click'); assert(onExpand.called, 'onExpand must be called'); var _onExpand$lastCall$ar5 = _slicedToArray(onExpand.lastCall.args, 1), _onExpand$lastCall$ar6 = _onExpand$lastCall$ar5[0], props = _onExpand$lastCall$ar6.props, event = _onExpand$lastCall$ar6.event; assert(props, 'props must be passed'); assert.equal(props.testProp, 'foo', 'aditional props must be included'); assert(event, 'event must be passed'); }); it('should be called when not expanded the non-input control is clicked', function () { var onExpand = sinon.spy(); wrapper = mount( /*#__PURE__*/React.createElement(Autocomplete, { onExpand: onExpand, suggestions: ['Portland', 'portal', 'porridge', 'potent', 'please'], testProp: 'foo', DropMenu: { isExpanded: false } }), { attachTo: rootMountNode }); wrapper.find('.lucid-Autocomplete-Control').simulate('click'); assert(onExpand.called, 'onExpand must be called'); var _onExpand$lastCall$ar7 = _slicedToArray(onExpand.lastCall.args, 1), _onExpand$lastCall$ar8 = _onExpand$lastCall$ar7[0], props = _onExpand$lastCall$ar8.props, event = _onExpand$lastCall$ar8.event; assert(props, 'props must be passed'); assert.equal(props.testProp, 'foo', 'aditional props must be included'); assert(event, 'event must be passed'); }); }); }); });