"use strict";

var _react = require("react");

var _react2 = _interopRequireDefault(_react);

var _reactDom = require("react-dom");

var _reactDom2 = _interopRequireDefault(_reactDom);

var _propTypes = require("prop-types");

var _propTypes2 = _interopRequireDefault(_propTypes);

var _chai = require("chai");

var _chai2 = _interopRequireDefault(_chai);

var _chaiEnzyme = require("chai-enzyme");

var _chaiEnzyme2 = _interopRequireDefault(_chaiEnzyme);

var _enzyme = require("enzyme");

var _lodash = require("lodash.assign");

var _lodash2 = _interopRequireDefault(_lodash);

var _testUtils = require("react-dom/test-utils");

var _enzymeHelpers = require("../../../tests/enzyme-helpers");

var _menuDropdown = require("../../menu-dropdown");

var _menuDropdown2 = _interopRequireDefault(_menuDropdown);

var _iconSettings = require("../../icon-settings");

var _iconSettings2 = _interopRequireDefault(_iconSettings);

var _menuList = require("../../utilities/menu-list");

var _menuList2 = _interopRequireDefault(_menuList);

var _keyCode = require("../../../utilities/key-code");

var _keyCode2 = _interopRequireDefault(_keyCode);

function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }

function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }

function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }

function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }

function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }

function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }

function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } return _assertThisInitialized(self); }

function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }

function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, enumerable: false, writable: true, configurable: true } }); if (superClass) Object.setPrototypeOf ? Object.setPrototypeOf(subClass, superClass) : subClass.__proto__ = superClass; }

/* Set Chai to use chaiEnzyme for enzyme compatible assertions:
 * https://github.com/producthunt/chai-enzyme
 */
_chai2.default.use((0, _chaiEnzyme2.default)());

var menuOptions = [{
  label: 'A super short',
  value: 'A0'
}, {
  label: 'B Option Super Super Long',
  value: 'B0'
}, {
  label: 'C Option',
  value: 'C0'
}, {
  disabled: true,
  label: 'D Option',
  value: 'D0'
}];
var defaultProps = {
  iconCategory: 'utility',
  iconName: 'down',
  id: 'sample-dropdown',
  label: 'Test',
  menuPosition: 'relative',
  openOn: 'click',
  options: menuOptions,
  placeholder: 'Select a contact',
  value: 'B0'
};
/* eslint-disable react/prop-types */

var DropdownCustomContent = function DropdownCustomContent(props) {
  return _react2.default.createElement("div", {
    id: "custom-dropdown-menu-content"
  }, _react2.default.createElement("div", {
    className: "slds-m-around--medium"
  }, _react2.default.createElement("div", {
    className: "slds-tile slds-tile--board slds-m-horizontal--small"
  }, _react2.default.createElement("p", {
    className: "tile__title slds-text-heading--small"
  }, "Art Vandelay"), _react2.default.createElement("div", {
    className: "slds-tile__detail"
  }, _react2.default.createElement("p", {
    className: "slds-truncate"
  }, _react2.default.createElement("a", {
    id: "custom-dropdown-menu-content-link",
    className: "slds-m-right--medium",
    href: "javascript:void(0);",
    onClick: props.onClick
  }, "Settings"), _react2.default.createElement("a", {
    href: "javascript:void(0);",
    onClick: props.onClick
  }, "Log Out"))))));
};

DropdownCustomContent.displayName = 'DropdownCustomContent';
/* A re-usable demo component fixture outside of `describe` sections
 * can accept props within each test and be unmounted after each tests.
 * This wrapping component will be similar to your wrapping component
 * you will create in the React Storybook for manual testing.
 */

var DemoComponent =
/*#__PURE__*/
function (_React$Component) {
  _inherits(DemoComponent, _React$Component);

  function DemoComponent() {
    _classCallCheck(this, DemoComponent);

    return _possibleConstructorReturn(this, (DemoComponent.__proto__ || Object.getPrototypeOf(DemoComponent)).apply(this, arguments));
  }

  _createClass(DemoComponent, [{
    key: "render",
    value: function render() {
      return _react2.default.createElement(_iconSettings2.default, {
        iconPath: "/assets/icons"
      }, _react2.default.createElement(_menuDropdown2.default, _extends({}, defaultProps, this.props), this.props.children));
    }
  }]);

  return DemoComponent;
}(_react2.default.Component);

DemoComponent.displayName = 'DropdownDemoComponent';
DemoComponent.defaultProps = defaultProps;

var getNodes = function getNodes(_ref) {
  var wrapper = _ref.wrapper;
  return {
    trigger: wrapper.find('.slds-dropdown-trigger'),
    button: wrapper.find('.slds-dropdown-trigger button'),
    menu: wrapper.find('.slds-dropdown'),
    customContent: wrapper.find('#custom-dropdown-menu-content'),
    customContentLink: wrapper.find('#custom-dropdown-menu-content #custom-dropdown-menu-content-link')
  };
};
/* All tests for component being tested should be wrapped in a root `describe`,
 * which should be named after the component being tested.
 * When read aloud, the cumulative `describe` and `it` names should form a coherent
 * sentence, eg "Date Picker default structure and css is present with expected
 * attributes set". If you are having trouble constructing a cumulative short
 * sentence, this may be an indicator that your test is poorly structured.
 * String provided as first parameter names the `describe` section. Limit to nouns
 * as much as possible/appropriate.`
 */


describe('SLDSMenuDropdown', function () {
  var wrapper;
  describe('Styling', function () {
    beforeEach((0, _enzymeHelpers.mountComponent)(_react2.default.createElement(DemoComponent, {
      menuStyle: {
        height: '500px'
      }
    })));
    afterEach(_enzymeHelpers.unmountComponent);
    it('has correct CSS classes and style', function () {
      var nodes = getNodes({
        wrapper: this.wrapper
      });
      nodes.button.simulate('click', {});
      var openNodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(openNodes.menu).to.exist;
      (0, _chai.expect)(openNodes.menu).to.have.style('height', '500px');
    });
  });
  describe('Custom Content Present', function () {
    beforeEach((0, _enzymeHelpers.mountComponent)(_react2.default.createElement(DemoComponent, {
      nubbinPosition: "top left",
      openOn: "click"
    }, _react2.default.createElement(DropdownCustomContent, null), _react2.default.createElement(_menuList2.default, {
      options: [{
        label: 'Custom Content Option'
      }].concat(menuOptions)
    }))));
    afterEach(_enzymeHelpers.unmountComponent);
    it('has content with custom ID is present', function () {
      var nodes = getNodes({
        wrapper: this.wrapper
      });
      nodes.button.simulate('click', {});
      var openNodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(openNodes.customContent.length).to.equal(1);
    });
    it('closes when custom content is clicked', function () {
      var nodes = getNodes({
        wrapper: this.wrapper
      });
      nodes.button.simulate('click', {});
      var openNodes = getNodes({
        wrapper: this.wrapper
      });
      openNodes.customContentLink.simulate('click', {});
      var closedNodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(closedNodes.customContent.length).to.equal(0);
    });
    it("has additional ListItem from list child's options prop", function () {
      var nodes = getNodes({
        wrapper: this.wrapper
      });
      var buttonId = nodes.trigger.prop('id');
      nodes.button.simulate('click', {});
      var openNodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(openNodes.menu.find("li#".concat(buttonId, "-item-0")).text()).to.equal('Custom Content Option');
    });
  });
  describe('Clickable', function () {
    var onClick = sinon.spy();
    beforeEach((0, _enzymeHelpers.mountComponent)(_react2.default.createElement(DemoComponent, {
      onClick: onClick
    })));
    afterEach(_enzymeHelpers.unmountComponent);
    it('does not expand on hover', function () {
      var nodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(nodes.menu.length).to.equal(0);
      nodes.trigger.simulate('mouseEnter', {});
      var hoverNodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(hoverNodes.menu.length).to.equal(0);
    });
    it('expands/contracts on click', function () {
      var nodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(nodes.menu.length).to.equal(0);
      nodes.trigger.simulate('click', {});
      var openNodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(openNodes.menu.length).to.equal(1);
      openNodes.trigger.simulate('click', {});
      var closedNodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(closedNodes.menu.length).to.equal(0);
    });
    it('preserves click behavior', function () {
      onClick.reset();
      var nodes = getNodes({
        wrapper: this.wrapper
      });
      nodes.trigger.simulate('click', {});
      (0, _chai.expect)(onClick.calledOnce);
    });
  });
  describe('Expanded', function () {
    var selected;
    beforeEach((0, _enzymeHelpers.mountComponent)(_react2.default.createElement(DemoComponent, {
      onSelect: function onSelect(selectedOption) {
        selected = selectedOption;
      }
    })));
    afterEach(_enzymeHelpers.unmountComponent);
    it('selects an item on click', function () {
      var nodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(nodes.menu.length).to.equal(0);
      nodes.trigger.simulate('click', {});
      var openNodes = getNodes({
        wrapper: this.wrapper
      });
      openNodes.menu.find('li a').first().simulate('click', {});
      (0, _chai.expect)(selected.value).to.equal('A0');
    });
  });
  describe('accessible markup for label Dropdowns', function () {
    beforeEach((0, _enzymeHelpers.mountComponent)(_react2.default.createElement(DemoComponent, null)));
    afterEach(_enzymeHelpers.unmountComponent);
    it('<ul> has role menu & aria-labelledby', function () {
      var nodes = getNodes({
        wrapper: this.wrapper
      });
      nodes.trigger.simulate('click', {});
      var openNodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(openNodes.menu.find('ul')).to.have.attr('role', 'menu');
      var nodeId = openNodes.trigger.prop('id');
      (0, _chai.expect)(openNodes.menu.find('ul')).attr('aria-labelledby', nodeId);
    });
    it('<a> inside <li> has role menuitem', function () {
      var nodes = getNodes({
        wrapper: this.wrapper
      });
      nodes.trigger.simulate('click', {});
      var openNodes = getNodes({
        wrapper: this.wrapper
      });
      var anchorRole = openNodes.menu.find('li a').first().prop('role');
      var match = anchorRole === 'menuitem' || anchorRole === 'menuitemradio' || anchorRole === 'menuitemcheckbox';
      (0, _chai.expect)(match).to.be.true;
    });
    it('if option.disabled, add aria-disabled to <a> that has role menuitem', function () {
      var nodes = getNodes({
        wrapper: this.wrapper
      });
      nodes.trigger.simulate('click', {});
      var openNodes = getNodes({
        wrapper: this.wrapper
      });
      var lastItemAriaDisabledRole = openNodes.menu.find('li a').at(3).prop('aria-disabled');
      (0, _chai.expect)(lastItemAriaDisabledRole).to.be.true;
    });
  });
  describe('accessible markup for Icon Only Dropdowns', function () {
    beforeEach((0, _enzymeHelpers.mountComponent)(_react2.default.createElement(DemoComponent, {
      assistiveText: "more options",
      buttonVariant: "icon",
      checkmark: true,
      iconCategory: "utility",
      iconName: "down",
      iconVariant: "border-filled"
    })));
    afterEach(_enzymeHelpers.unmountComponent);
    it('<button> has assistiveText', function () {
      var nodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(nodes.button.find('.slds-assistive-text').text()).to.equal('more options');
    });
  });
  describe('Keyboard behavior', function () {
    var selected;
    beforeEach((0, _enzymeHelpers.mountComponent)(_react2.default.createElement(DemoComponent, {
      onSelect: function onSelect(selectedOption) {
        selected = selectedOption;
      }
    })));
    afterEach(_enzymeHelpers.unmountComponent);
    it('opens menu with enter', function () {
      var nodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(nodes.menu.length).to.equal(0);
      nodes.button.simulate('keyDown', _keyCode.keyObjects.ENTER);
      var openNodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(openNodes.menu.length).to.equal(1);
    });
    it('opens menu with down arrow key', function () {
      var nodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(nodes.menu.length).to.equal(0);
      nodes.button.simulate('keyDown', _keyCode.keyObjects.DOWN);
      var openNodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(openNodes.menu.length).to.equal(1);
    });
    it('selects an item with keyboard', function () {
      var nodes = getNodes({
        wrapper: this.wrapper
      });
      nodes.trigger.simulate('click', {});
      var openNodes = getNodes({
        wrapper: this.wrapper
      });
      openNodes.menu.simulate('keyDown', _keyCode.keyObjects.DOWN);
      openNodes.menu.simulate('keyDown', _keyCode.keyObjects.DOWN);
      openNodes.menu.simulate('keyDown', _keyCode.keyObjects.ENTER);
      (0, _chai.expect)(selected.value).to.equal('B0');
    });
    it('closes Menu on esc', function () {
      var nodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(nodes.menu.length).to.equal(0);
      nodes.trigger.simulate('click', {});
      var openNodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(openNodes.menu.length).to.equal(1);
      openNodes.menu.find('.slds-dropdown__item a').first().simulate('keyDown', _keyCode.keyObjects.ESCAPE);
      var closedNodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(closedNodes.menu.length).to.equal(0);
    });
  });
  describe('multiple selection', function () {
    beforeEach((0, _enzymeHelpers.mountComponent)(_react2.default.createElement(DemoComponent, {
      multiple: true,
      checkmark: true
    })));
    afterEach(_enzymeHelpers.unmountComponent);
    it('selects multiple items and renders checkmarks', function () {
      var nodes = getNodes({
        wrapper: this.wrapper
      });
      nodes.trigger.simulate('click', {});
      var openNodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(openNodes.menu.find('.slds-dropdown__item svg').length).to.equal(1);
      openNodes.menu.find('.slds-dropdown__item a').at(0).simulate('click');
      openNodes = getNodes({
        wrapper: this.wrapper
      });
      (0, _chai.expect)(openNodes.menu.find('.slds-dropdown__item svg').length).to.equal(2);
    });
  }); // Hover and hybrid hover UX patterns are not approved UX patterns due to accessibility concerns

  describe('Hoverable', function () {
    var body;

    var renderDropdown = function renderDropdown(inst) {
      body = document.createElement('div');
      document.body.appendChild(body); // eslint-disable-next-line react/no-render-return-value

      return _reactDom2.default.render(_react2.default.createElement(_iconSettings2.default, {
        iconPath: "/assets/icons"
      }, inst), body);
    };

    function removeDropdownTrigger() {
      _reactDom2.default.unmountComponentAtNode(body);

      document.body.removeChild(body);
    }

    var createDropdown = function createDropdown(props) {
      return _react2.default.createElement(_menuDropdown2.default, (0, _lodash2.default)({}, defaultProps, props));
    };

    createDropdown.displayName = 'createDropdown';

    var dropItDown = function dropItDown(props, children) {
      return renderDropdown(createDropdown(props, children));
    };

    var getMenu = function getMenu(dom) {
      return dom.querySelector('.slds-dropdown');
    };

    var cmp;
    var btn;
    beforeEach(function () {
      cmp = dropItDown({
        buttonClassName: 'dijkstrafied',
        openOn: 'hover',
        hoverCloseDelay: 2
      });
      btn = (0, _testUtils.findRenderedDOMComponentWithClass)(cmp, 'slds-dropdown-trigger');
    });
    afterEach(function () {
      removeDropdownTrigger(btn);
    });
    it('gives the button correct aria properties', function () {
      (0, _chai.expect)(btn.firstChild.getAttribute('aria-haspopup')).to.equal('true');
    });
    it('sets the label', function () {
      (0, _chai.expect)(btn.textContent).to.equal('Test');
    });
    it('expands the dropdown on hover', function () {
      (0, _chai.expect)(getMenu(body)).to.equal(null);

      _testUtils.Simulate.mouseEnter(btn, {});

      (0, _chai.expect)(getMenu(body).className).to.include('slds-dropdown');

      _testUtils.Simulate.mouseLeave(btn, {});
    });
    it('closes on blur based on timeout delay', function (done) {
      (0, _chai.expect)(getMenu(body)).to.equal(null);

      _testUtils.Simulate.mouseEnter(btn, {});

      _testUtils.Simulate.mouseLeave(btn);

      (0, _chai.expect)(getMenu(body)).to.not.equal(null);
      setTimeout(function () {
        (0, _chai.expect)(getMenu(body)).to.equal(null);
        done();
      }, 3);
    });
    it("doesn't close on quick hover outside", function (done) {
      (0, _chai.expect)(getMenu(body)).to.equal(null);

      _testUtils.Simulate.mouseEnter(btn, {});

      _testUtils.Simulate.mouseLeave(btn);

      setTimeout(function () {
        _testUtils.Simulate.mouseEnter(btn, {});

        (0, _chai.expect)(getMenu(body)).to.not.equal(null);
        setTimeout(function () {
          (0, _chai.expect)(getMenu(body)).to.not.equal(null);
          done();
        }, 3);
      }, 1);
    });
  });
  describe('Hybrid-able', function () {
    var body;

    var renderDropdown = function renderDropdown(inst) {
      body = document.createElement('div');
      document.body.appendChild(body); // eslint-disable-next-line react/no-render-return-value

      return _reactDom2.default.render(_react2.default.createElement(_iconSettings2.default, {
        iconPath: "/assets/icons"
      }, inst), body);
    };

    function removeDropdownTrigger() {
      _reactDom2.default.unmountComponentAtNode(body);

      document.body.removeChild(body);
    }

    var createDropdown = function createDropdown(props) {
      return _react2.default.createElement(_menuDropdown2.default, (0, _lodash2.default)({}, defaultProps, props));
    };

    createDropdown.displayName = 'createDropdown';

    var dropItDown = function dropItDown(props, children) {
      return renderDropdown(createDropdown(props, children));
    };

    var getMenu = function getMenu(dom) {
      return dom.querySelector('.slds-dropdown');
    };

    var cmp;
    var btn;
    var onClick = sinon.spy();
    beforeEach(function () {
      cmp = dropItDown({
        openOn: 'hybrid',
        onClick: onClick,
        hoverCloseDelay: 1
      });
      btn = (0, _testUtils.findRenderedDOMComponentWithClass)(cmp, 'slds-dropdown-trigger');
    });
    afterEach(function () {
      removeDropdownTrigger(btn);
    });
    it('doesnt expand on hover', function () {
      (0, _chai.expect)(getMenu(body)).to.equal(null);

      _testUtils.Simulate.mouseEnter(btn, {});

      (0, _chai.expect)(getMenu(body)).to.equal(null);
    });
    it('opens on click, closes on mouseLeave', function (done) {
      // open
      (0, _chai.expect)(getMenu(body)).to.equal(null);

      _testUtils.Simulate.click(btn, {});

      (0, _chai.expect)(getMenu(body).className).to.include('slds-dropdown'); // close

      _testUtils.Simulate.mouseEnter(btn, {});

      _testUtils.Simulate.mouseLeave(btn);

      (0, _chai.expect)(getMenu(body)).to.not.equal(null);
      setTimeout(function () {
        (0, _chai.expect)(getMenu(body)).to.equal(null);
        done();
      }, 2);
    });
  });
});