/*
 * SPDX-License-Identifier: Apache-2.0
 *
 * The OpenSearch Contributors require contributions made to
 * this file be licensed under the Apache-2.0 license or a
 * compatible open source license.
 *
 * Modifications Copyright OpenSearch Contributors. See
 * GitHub history for details.
 */
/*
 * Licensed to Elasticsearch B.V. under one or more contributor
 * license agreements. See the NOTICE file distributed with
 * this work for additional information regarding copyright
 * ownership. Elasticsearch B.V. licenses this file to you under
 * the Apache License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
import React from 'react';
import { render, mount, ReactWrapper } from 'enzyme';
import { findTestSubject, requiredProps } from '../../test';
import { OuiContextMenuPanel, SIZES } from './context_menu_panel';
import { OuiContextMenuItem } from './context_menu_item';
import { tick } from './context_menu.test';
import { keys } from '../../services';
const items = [
  
    Option A
  ,
  
    Option B
  ,
  
    Option C
  ,
];
describe('OuiContextMenuPanel', () => {
  test('is rendered', () => {
    const component = render(
      Hello
    );
    expect(component).toMatchSnapshot();
  });
  describe('props', () => {
    describe('title', () => {
      test('is rendered', () => {
        const component = render();
        expect(component).toMatchSnapshot();
      });
    });
    describe('size', () => {
      SIZES.forEach((size) => {
        it(`${size} is rendered`, () => {
          const component = render(
            
          );
          expect(component).toMatchSnapshot();
        });
      });
    });
    describe('onClose', () => {
      test('renders a button as a title', () => {
        const component = render(
           {}} />
        );
        expect(component).toMatchSnapshot();
      });
      test("isn't called upon instantiation", () => {
        const onCloseHandler = jest.fn();
        mount();
        expect(onCloseHandler).not.toHaveBeenCalled();
      });
      test('is called when the title is clicked', () => {
        const onCloseHandler = jest.fn();
        const component = mount(
          
        );
        component.find('button').simulate('click');
        expect(onCloseHandler).toHaveBeenCalledTimes(1);
      });
    });
    describe('onHeightChange', () => {
      it('is called with a height value', () => {
        const onHeightChange = jest.fn();
        mount();
        expect(onHeightChange).toHaveBeenCalledWith(0);
      });
    });
    describe('transitionDirection', () => {
      describe('next', () => {
        describe('with transitionType', () => {
          describe('in', () => {
            test('is rendered', () => {
              const component = render(
                
              );
              expect(component).toMatchSnapshot();
            });
          });
          describe('out', () => {
            test('is rendered', () => {
              const component = render(
                
              );
              expect(component).toMatchSnapshot();
            });
          });
        });
      });
      describe('previous', () => {
        describe('with transitionType', () => {
          describe('in', () => {
            test('is rendered', () => {
              const component = render(
                
              );
              expect(component).toMatchSnapshot();
            });
          });
          describe('out', () => {
            test('is rendered', () => {
              const component = render(
                
              );
              expect(component).toMatchSnapshot();
            });
          });
        });
      });
    });
    describe('initialFocusedItemIndex', () => {
      it('sets focus on the item occupying that index', async () => {
        const component = mount(
          
        );
        await tick(20);
        expect(findTestSubject(component, 'itemB').getDOMNode()).toBe(
          document.activeElement
        );
      });
      it('sets focus on the panel when set to `-1`', async () => {
        const component = mount(
          
        );
        await tick(20);
        expect(component.getDOMNode()).toBe(document.activeElement);
      });
    });
    describe('onUseKeyboardToNavigate', () => {
      it('is called when up arrow is pressed', () => {
        const onUseKeyboardToNavigateHandler = jest.fn();
        const component = mount(
          
        );
        component.simulate('keydown', { key: keys.ARROW_UP });
        expect(onUseKeyboardToNavigateHandler).toHaveBeenCalledTimes(1);
      });
      it('is called when down arrow is pressed', () => {
        const onUseKeyboardToNavigateHandler = jest.fn();
        const component = mount(
          
        );
        component.simulate('keydown', { key: keys.ARROW_UP });
        expect(onUseKeyboardToNavigateHandler).toHaveBeenCalledTimes(1);
      });
      describe('left arrow', () => {
        it('calls handler if showPreviousPanel exists', () => {
          const onUseKeyboardToNavigateHandler = jest.fn();
          const component = mount(
             {}}
              onUseKeyboardToNavigate={onUseKeyboardToNavigateHandler}
            />
          );
          component.simulate('keydown', { key: keys.ARROW_LEFT });
          expect(onUseKeyboardToNavigateHandler).toHaveBeenCalledTimes(1);
        });
        it("doesn't call handler if showPreviousPanel doesn't exist", () => {
          const onUseKeyboardToNavigateHandler = jest.fn();
          const component = mount(
            
          );
          component.simulate('keydown', { key: keys.ARROW_LEFT });
          expect(onUseKeyboardToNavigateHandler).not.toHaveBeenCalled();
        });
      });
      describe('right arrow', () => {
        it('calls handler if showNextPanel exists', () => {
          const onUseKeyboardToNavigateHandler = jest.fn();
          const component = mount(
             {}}
              onUseKeyboardToNavigate={onUseKeyboardToNavigateHandler}
            />
          );
          component.simulate('keydown', { key: keys.ARROW_RIGHT });
          expect(onUseKeyboardToNavigateHandler).toHaveBeenCalledTimes(1);
        });
        it("doesn't call handler if showNextPanel doesn't exist", () => {
          const onUseKeyboardToNavigateHandler = jest.fn();
          const component = mount(
            
          );
          component.simulate('keydown', { key: keys.ARROW_RIGHT });
          expect(onUseKeyboardToNavigateHandler).not.toHaveBeenCalled();
        });
      });
    });
  });
  describe('behavior', () => {
    describe('focus', () => {
      it('is set on the first focusable element by default if there are no items and hasFocus is true', async () => {
        const component = mount(
          
            
          
        );
        await tick(20);
        expect(findTestSubject(component, 'button').getDOMNode()).toBe(
          document.activeElement
        );
      });
      it('is not set on anything if hasFocus is false', () => {
        const component = mount(
          
            
          
        );
        expect(findTestSubject(component, 'button').getDOMNode()).not.toBe(
          document.activeElement
        );
      });
    });
    describe('keyboard navigation of items', () => {
      let component: ReactWrapper;
      let showNextPanelHandler: jest.Mock;
      let showPreviousPanelHandler: jest.Mock;
      beforeEach(() => {
        showNextPanelHandler = jest.fn();
        showPreviousPanelHandler = jest.fn();
        component = mount(
          
        );
      });
      it('focuses the panel by default', async () => {
        await tick(20);
        expect(component.getDOMNode()).toBe(document.activeElement);
      });
      it('down arrow key focuses the first menu item', async () => {
        component.simulate('keydown', { key: keys.ARROW_DOWN });
        await tick(20);
        expect(findTestSubject(component, 'itemA').getDOMNode()).toBe(
          document.activeElement
        );
      });
      it('subsequently, down arrow key focuses the next menu item', async () => {
        component.simulate('keydown', { key: keys.ARROW_DOWN });
        component.simulate('keydown', { key: keys.ARROW_DOWN });
        await tick(20);
        expect(findTestSubject(component, 'itemB').getDOMNode()).toBe(
          document.activeElement
        );
      });
      it('down arrow key wraps to first menu item', async () => {
        component.simulate('keydown', { key: keys.ARROW_UP });
        component.simulate('keydown', { key: keys.ARROW_DOWN });
        await tick(20);
        expect(findTestSubject(component, 'itemA').getDOMNode()).toBe(
          document.activeElement
        );
      });
      it('up arrow key focuses the last menu item', async () => {
        component.simulate('keydown', { key: keys.ARROW_UP });
        await tick(20);
        expect(findTestSubject(component, 'itemC').getDOMNode()).toBe(
          document.activeElement
        );
      });
      it('subsequently, up arrow key focuses the previous menu item', async () => {
        component.simulate('keydown', { key: keys.ARROW_UP });
        component.simulate('keydown', { key: keys.ARROW_UP });
        await tick(20);
        expect(findTestSubject(component, 'itemB').getDOMNode()).toBe(
          document.activeElement
        );
      });
      it('up arrow key wraps to last menu item', async () => {
        component.simulate('keydown', { key: keys.ARROW_DOWN });
        component.simulate('keydown', { key: keys.ARROW_UP });
        await tick(20);
        expect(findTestSubject(component, 'itemC').getDOMNode()).toBe(
          document.activeElement
        );
      });
      it("right arrow key shows next panel with focused item's index", () => {
        component.simulate('keydown', { key: keys.ARROW_DOWN });
        component.simulate('keydown', { key: keys.ARROW_RIGHT });
        expect(showNextPanelHandler).toHaveBeenCalledWith(0);
      });
      it('left arrow key shows previous panel', () => {
        component.simulate('keydown', { key: keys.ARROW_LEFT });
        expect(showPreviousPanelHandler).toHaveBeenCalledTimes(1);
      });
    });
  });
  describe('updating items and content', () => {
    describe('updates to items', () => {
      it("should not re-render if any items's watchedItemProps did not change", () => {
        expect.assertions(2); // make sure the assertion in the `setProps` callback is executed
        // by not passing `watchedItemProps` no changes to items should cause a re-render
        const component = mount(
          
                Option A
              ,
              
                Option B
              ,
            ]}
          />
        );
        expect(component.debug()).toMatchSnapshot();
        component.setProps(
          {
            items: [
              
                Option A
              ,
              
                Option B
              ,
            ],
          },
          () => {
            expect(component.debug()).toMatchSnapshot();
          }
        );
      });
      it("should re-render if any items's watchedItemProps did change", () => {
        expect.assertions(2); // make sure the assertion in the `setProps` callback is executed
        // by referencing the `data-counter` property in `watchedItemProps`
        // changes to the items should be picked up and re-rendered
        const component = mount(
          
                Option A
              ,
              
                Option B
              ,
            ]}
          />
        );
        expect(component.debug()).toMatchSnapshot();
        component.setProps(
          {
            items: [
              
                Option A
              ,
              
                Option B
              ,
            ],
          },
          () => {
            expect(component.debug()).toMatchSnapshot();
          }
        );
      });
      it('should re-render at all times when children exists', () => {
        expect.assertions(2); // make sure the assertion in the `setProps` callback is executed
        const component = mount(
          Hello World
        );
        expect(component.debug()).toMatchSnapshot();
        component.setProps({ children: 'More Salutations' }, () => {
          expect(component.debug()).toMatchSnapshot();
        });
      });
    });
  });
});