text: import React from 'react';
  import keycode from 'keycode';
  import { assert } from 'chai';
  import { spy } from 'sinon';
  import MenuList from 'packages/material-ui/src/MenuList';
  import MenuItem from 'packages/material-ui/src/MenuItem';
  import { createMount } from 'packages/material-ui/src/test-utils';
  
  function assertMenuItemTabIndexed(wrapper, tabIndexed) {
    const items = wrapper.find('MenuItem');
  
    items.forEach((item, index) => {
      if (index === tabIndexed) {
        assert.strictEqual(item.props().tabIndex, 0, 'should have the tab index');
      } else {
        assert.strictEqual(
          item.props().tabIndex,
          -1,
          `item at index ${index} should not be tab focusable`,
        );
      }
    });
  }
  
  function assertMenuItemFocused(wrapper, tabIndexed) {
    const items = wrapper.find('MenuItem');
  
    items.forEach((item, index) => {
      if (index === tabIndexed) {
        assert.strictEqual(item.find('li').instance(), document.activeElement, 'should be focused');
      }
    });
  }
  
  describe('<MenuList> integration', () => {
    let mount;
  
    before(() => {
      mount = createMount();
    });
  
    after(() => {
      mount.cleanUp();
    });
  
    describe('keyboard controls and tabIndex manipulation', () => {
      let wrapper;
  
      const resetWrapper = () => {
        wrapper = mount(
          <MenuList>
            <MenuItem>Menu Item 1</MenuItem>
            <MenuItem>Menu Item 2</MenuItem>
            <MenuItem>Menu Item 2</MenuItem>
            <MenuItem>Menu Item 4</MenuItem>
          </MenuList>,
        );
      };
  
      before(resetWrapper);
  
      it('should have the first item tabIndexed', () => {
        assertMenuItemTabIndexed(wrapper, 0);
      });
  
      it('should select/focus the first item', () => {
        wrapper.instance().focus();
        assertMenuItemTabIndexed(wrapper, 0);
        assertMenuItemFocused(wrapper, 0);
      });
  
      it('should still have the first item tabIndexed', () => {
        wrapper.simulate('keyDown', { which: keycode('up') });
        assertMenuItemTabIndexed(wrapper, 0);
      });
  
      it('should still have the first item tabIndexed', () => {
        wrapper.simulate('keyDown', { which: keycode('down') });
        wrapper.simulate('keyDown', { which: keycode('up') });
        assertMenuItemFocused(wrapper, 0);
      });
  
      it('should focus the second item', () => {
        wrapper.instance().focus();
        wrapper.simulate('keyDown', { which: keycode('down') });
        assertMenuItemTabIndexed(wrapper, 1);
        assertMenuItemFocused(wrapper, 1);
      });
  
      it('should reset the tabIndex to the first item after blur', done => {
        const handleBlur = spy();
        wrapper.setProps({ onBlur: handleBlur });
  
        if (!document.activeElement) {
          throw new Error('missing active element');
        }
  
        document.activeElement.blur();
        setTimeout(() => {
          assert.strictEqual(handleBlur.callCount, 1);
          wrapper.update();
          assertMenuItemTabIndexed(wrapper, 0);
          done();
        }, 60);
      });
  
      it('should reset the tabIndex to the focused element when calling resetTabIndex', () => {
        wrapper.instance().focus();
        wrapper.simulate('keyDown', { which: keycode('down') });
        wrapper.instance().setTabIndex(2);
        wrapper.instance().resetTabIndex();
  
        assertMenuItemTabIndexed(wrapper, 1);
        assertMenuItemFocused(wrapper, 1);
  
        resetWrapper();
      });
  
      it('should select/focus the first item', () => {
        wrapper.instance().focus();
        assertMenuItemTabIndexed(wrapper, 0);
        assertMenuItemFocused(wrapper, 0);
      });
  
      it('should focus the second item', () => {
        wrapper.simulate('keyDown', { which: keycode('down') });
        assertMenuItemTabIndexed(wrapper, 1);
        assertMenuItemFocused(wrapper, 1);
      });
  
      it('should focus the third item', () => {
        wrapper.simulate('keyDown', { which: keycode('down') });
        assertMenuItemTabIndexed(wrapper, 2);
        assertMenuItemFocused(wrapper, 2);
      });
  
      it('should focus the first item if not focused', () => {
        resetWrapper();
        wrapper.simulate('keyDown', { which: keycode('down') });
        assertMenuItemTabIndexed(wrapper, 0);
        assertMenuItemFocused(wrapper, 0);
  
        resetWrapper();
        wrapper.simulate('keyDown', { which: keycode('up') });
        assertMenuItemTabIndexed(wrapper, 0);
        assertMenuItemFocused(wrapper, 0);
      });
    });
  
    describe('keyboard controls and tabIndex manipulation - preselected item', () => {
      let wrapper;
  
      const resetWrapper = () => {
        wrapper = mount(
          <MenuList>
            <MenuItem>Menu Item 1</MenuItem>
            <MenuItem selected>Menu Item 2</MenuItem>
            <MenuItem>Menu Item 2</MenuItem>
            <MenuItem>Menu Item 4</MenuItem>
          </MenuList>,
        );
      };
  
      before(resetWrapper);
  
      it('should have the 2nd item tabIndexed', () => {
        assertMenuItemTabIndexed(wrapper, 1);
      });
  
      it('should select/focus the second item', () => {
        wrapper.instance().focus();
        assertMenuItemTabIndexed(wrapper, 1);
        assertMenuItemFocused(wrapper, 1);
      });
  
      it('should focus the third item', () => {
        wrapper.instance().focus();
        wrapper.simulate('keyDown', { which: keycode('down') });
        assertMenuItemTabIndexed(wrapper, 2);
        assertMenuItemFocused(wrapper, 2);
      });
  
      it('should focus the preselected item if not focused', () => {
        resetWrapper();
        wrapper.simulate('keyDown', { which: keycode('down') });
        assertMenuItemTabIndexed(wrapper, 1);
        assertMenuItemFocused(wrapper, 1);
  
        resetWrapper();
        wrapper.simulate('keyDown', { which: keycode('up') });
        assertMenuItemTabIndexed(wrapper, 1);
        assertMenuItemFocused(wrapper, 1);
      });
    });
  
    it('should not crash and burn when calling focus() on an empty MenuList', () => {
      const wrapper = mount(<MenuList />);
      wrapper.instance().focus();
    });
  
    it('should not crash and burn when calling focus() on an unmounted MenuList', () => {
      const wrapper = mount(<MenuList />);
      delete wrapper.instance().list;
      wrapper.instance().focus();
    });
  });
  