/* * 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, { ReactNode } from 'react'; import { render, mount } from 'enzyme'; import { requiredProps } from '../../test/required_props'; import { OuiPopover, getPopoverPositionFromAnchorPosition, getPopoverAlignFromAnchorPosition, PopoverAnchorPosition, } from './popover'; import { keys } from '../../services'; jest.mock('../portal', () => ({ OuiPortal: ({ children }: { children: ReactNode }) => children, })); let id = 0; const getId = () => `${id++}`; describe('OuiPopover', () => { test('is rendered', () => { const component = render( } closePopover={() => {}} {...requiredProps} /> ); expect(component).toMatchSnapshot(); }); test('children is rendered', () => { const component = render( } closePopover={() => {}}> Children ); expect(component).toMatchSnapshot(); }); describe('props', () => { describe('display block', () => { test('is rendered', () => { const component = render( } closePopover={() => {}} /> ); expect(component).toMatchSnapshot(); }); }); describe('anchorClassName', () => { test('is rendered', () => { const component = render( } closePopover={() => {}} /> ); expect(component).toMatchSnapshot(); }); }); describe('closePopover', () => { it('is called when ESC key is hit and the popover is open', () => { const closePopoverHandler = jest.fn(); const component = mount( } closePopover={closePopoverHandler} isOpen /> ); component.simulate('keydown', { key: keys.ESCAPE }); expect(closePopoverHandler).toBeCalledTimes(1); }); it('is not called when ESC key is hit and the popover is closed', () => { const closePopoverHandler = jest.fn(); const component = mount( } closePopover={closePopoverHandler} isOpen={false} /> ); component.simulate('keydown', { key: keys.ESCAPE }); expect(closePopoverHandler).not.toBeCalled(); }); }); describe('anchorPosition', () => { test('defaults to centerDown', () => { const component = render( } closePopover={() => {}} /> ); expect(component).toMatchSnapshot(); }); test('leftCenter is rendered', () => { const component = render( } closePopover={() => {}} anchorPosition="leftCenter" /> ); expect(component).toMatchSnapshot(); }); test('downRight is rendered', () => { const component = render( } closePopover={() => {}} anchorPosition="downRight" /> ); expect(component).toMatchSnapshot(); }); }); describe('isOpen', () => { test('defaults to false', () => { const component = render( } closePopover={() => {}} /> ); expect(component).toMatchSnapshot(); }); test('renders true', () => { const component = mount(
} closePopover={() => {}} isOpen />
); // console.log(component.debug()); expect(component.render()).toMatchSnapshot(); }); }); describe('ownFocus', () => { test('defaults to true', () => { const component = mount(
} closePopover={() => {}} />
); expect(component.render()).toMatchSnapshot(); }); test('renders false', () => { const component = mount(
} closePopover={() => {}} />
); expect(component.render()).toMatchSnapshot(); }); }); describe('panelClassName', () => { test('is rendered', () => { const component = mount(
} closePopover={() => {}} panelClassName="test" isOpen />
); expect(component.render()).toMatchSnapshot(); }); }); describe('panelPaddingSize', () => { test('is rendered', () => { const component = mount(
} closePopover={() => {}} panelPaddingSize="s" isOpen />
); expect(component.render()).toMatchSnapshot(); }); }); describe('panelProps', () => { test('is rendered', () => { const component = mount(
} closePopover={() => {}} panelProps={requiredProps} isOpen />
); expect(component.render()).toMatchSnapshot(); }); }); describe('focusTrapProps', () => { test('is rendered', () => { const component = mount(
} closePopover={() => {}} focusTrapProps={{ clickOutsideDisables: false, noIsolation: false, scrollLock: false, }} isOpen />
); expect(component.render()).toMatchSnapshot(); }); }); describe('offset', () => { test('with arrow', () => { const component = mount(
} closePopover={() => {}} offset={10} isOpen />
); expect(component.render()).toMatchSnapshot(); }); test('without arrow', () => { const component = mount(
} closePopover={() => {}} offset={10} hasArrow={false} isOpen />
); expect(component.render()).toMatchSnapshot(); }); }); describe('arrowChildren', () => { test('is rendered', () => { const component = mount(
} closePopover={() => {}} arrowChildren={} isOpen />
); expect(component.render()).toMatchSnapshot(); }); }); test('buffer', () => { const component = mount(
} closePopover={() => {}} buffer={0} isOpen />
); expect(component.render()).toMatchSnapshot(); }); test('buffer for all sides', () => { const component = mount(
} closePopover={() => {}} buffer={[20, 40, 60, 80]} isOpen />
); expect(component.render()).toMatchSnapshot(); }); }); describe('listener cleanup', () => { let _raf: typeof window['requestAnimationFrame']; let _caf: typeof window['cancelAnimationFrame']; beforeAll(() => { jest.useFakeTimers(); _raf = window.requestAnimationFrame; _caf = window.cancelAnimationFrame; const activeAnimationFrames = new Map(); let nextAnimationFrameId = 0; window.requestAnimationFrame = (fn) => { const animationFrameId = nextAnimationFrameId++; activeAnimationFrames.set(animationFrameId, setTimeout(fn)); return animationFrameId; }; window.cancelAnimationFrame = (id: number) => { const timeoutId = activeAnimationFrames.get(id); if (timeoutId) { clearTimeout(timeoutId); activeAnimationFrames.delete(id); } }; }); afterAll(() => { jest.useRealTimers(); window.requestAnimationFrame = _raf; window.cancelAnimationFrame = _caf; }); it('cleans up timeouts and rAFs on unmount', () => { const component = mount( } closePopover={() => {}} panelPaddingSize="s" isOpen={false} /> ); component.setProps({ isOpen: true }); component.unmount(); // OUI's jest configuration throws an error if there are any console.error calls, like // React's setState on an unmounted component warning // to be future proof, verify that's still the case expect(() => { console.error('This is a test'); }).toThrow(); // execute any pending timeouts or animation frame callbacks // and validate the timeout/rAF clearing done by OuiPopover jest.advanceTimersByTime(10); }); }); }); describe('getPopoverPositionFromAnchorPosition', () => { it('maps the first anchor position in a camel-cased string to a popover position', () => { expect(getPopoverPositionFromAnchorPosition('upLeft')).toBe('top'); expect(getPopoverPositionFromAnchorPosition('rightDown')).toBe('right'); expect(getPopoverPositionFromAnchorPosition('downRight')).toBe('bottom'); expect(getPopoverPositionFromAnchorPosition('leftUp')).toBe('left'); }); it('returns undefined when an invalid position is extracted', () => { expect( getPopoverPositionFromAnchorPosition( 'nowhereNohow' as PopoverAnchorPosition ) ).toBeUndefined(); }); }); describe('getPopoverAlignFromAnchorPosition', () => { it('maps the second anchor position in a camel-cased string to a popover position', () => { expect(getPopoverAlignFromAnchorPosition('upLeft')).toBe('left'); expect(getPopoverAlignFromAnchorPosition('rightDown')).toBe('bottom'); expect(getPopoverAlignFromAnchorPosition('downRight')).toBe('right'); expect(getPopoverAlignFromAnchorPosition('leftUp')).toBe('top'); }); it('returns undefined when an invalid position is extracted', () => { expect( getPopoverAlignFromAnchorPosition('nowhereNohow' as PopoverAnchorPosition) ).toBeUndefined(); }); });