/* * 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. * * Any 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. */ // @ts-ignore import sizeMe from 'react-sizeme'; import React from 'react'; import { mountWithIntl } from 'test_utils/enzyme_helpers'; import { skip } from 'rxjs/operators'; import { DashboardGrid, DashboardGridProps } from './dashboard_grid'; import { DashboardContainer, DashboardContainerOptions } from '../dashboard_container'; import { getSampleDashboardInput } from '../../test_helpers'; import { CONTACT_CARD_EMBEDDABLE, ContactCardEmbeddableFactory, } from '../../../../../embeddable/public/lib/test_samples'; import { embeddablePluginMock } from '../../../../../embeddable/public/mocks'; import { OpenSearchDashboardsContextProvider } from '../../../../../opensearch_dashboards_react/public'; let dashboardContainer: DashboardContainer | undefined; function prepare(props?: Partial<DashboardGridProps>) { const { setup, doStart } = embeddablePluginMock.createInstance(); setup.registerEmbeddableFactory( CONTACT_CARD_EMBEDDABLE, new ContactCardEmbeddableFactory((() => null) as any, {} as any) ); const start = doStart(); const getEmbeddableFactory = start.getEmbeddableFactory; const initialInput = getSampleDashboardInput({ panels: { '1': { gridData: { x: 0, y: 0, w: 6, h: 6, i: '1' }, type: CONTACT_CARD_EMBEDDABLE, explicitInput: { id: '1' }, }, '2': { gridData: { x: 6, y: 6, w: 6, h: 6, i: '2' }, type: CONTACT_CARD_EMBEDDABLE, explicitInput: { id: '2' }, }, }, }); const options: DashboardContainerOptions = { application: {} as any, embeddable: { getTriggerCompatibleActions: (() => []) as any, getEmbeddableFactories: start.getEmbeddableFactories, getEmbeddablePanel: jest.fn(), getEmbeddableFactory, } as any, notifications: {} as any, overlays: {} as any, inspector: { isAvailable: jest.fn(), } as any, SavedObjectFinder: () => null, ExitFullScreenButton: () => null, uiActions: { getTriggerCompatibleActions: (() => []) as any, } as any, }; dashboardContainer = new DashboardContainer(initialInput, options); const defaultTestProps: DashboardGridProps = { container: dashboardContainer, PanelComponent: () => <div />, opensearchDashboards: null as any, intl: null as any, }; return { props: Object.assign(defaultTestProps, props), options, }; } beforeAll(() => { // sizeme detects the width to be 0 in our test environment. noPlaceholder will mean that the grid contents will // get rendered even when width is 0, which will improve our tests. sizeMe.noPlaceholders = true; }); afterAll(() => { sizeMe.noPlaceholders = false; }); test('renders DashboardGrid', () => { const { props, options } = prepare(); const component = mountWithIntl( <OpenSearchDashboardsContextProvider services={options}> <DashboardGrid {...props} /> </OpenSearchDashboardsContextProvider> ); const panelElements = component.find('EmbeddableChildPanel'); expect(panelElements.length).toBe(2); }); test('renders DashboardGrid with no visualizations', () => { const { props, options } = prepare(); const component = mountWithIntl( <OpenSearchDashboardsContextProvider services={options}> <DashboardGrid {...props} /> </OpenSearchDashboardsContextProvider> ); props.container.updateInput({ panels: {} }); component.update(); expect(component.find('EmbeddableChildPanel').length).toBe(0); }); test('DashboardGrid removes panel when removed from container', () => { const { props, options } = prepare(); const component = mountWithIntl( <OpenSearchDashboardsContextProvider services={options}> <DashboardGrid {...props} /> </OpenSearchDashboardsContextProvider> ); const originalPanels = props.container.getInput().panels; const filteredPanels = { ...originalPanels }; delete filteredPanels['1']; props.container.updateInput({ panels: filteredPanels }); component.update(); const panelElements = component.find('EmbeddableChildPanel'); expect(panelElements.length).toBe(1); }); test('DashboardGrid renders expanded panel', () => { const { props, options } = prepare(); const component = mountWithIntl( <OpenSearchDashboardsContextProvider services={options}> <DashboardGrid {...props} /> </OpenSearchDashboardsContextProvider> ); props.container.updateInput({ expandedPanelId: '1' }); component.update(); // Both panels should still exist in the dom, so nothing needs to be re-fetched once minimized. expect(component.find('EmbeddableChildPanel').length).toBe(2); expect( (component.find('DashboardGridUi').state() as { expandedPanelId?: string }).expandedPanelId ).toBe('1'); props.container.updateInput({ expandedPanelId: undefined }); component.update(); expect(component.find('EmbeddableChildPanel').length).toBe(2); expect( (component.find('DashboardGridUi').state() as { expandedPanelId?: string }).expandedPanelId ).toBeUndefined(); }); test('DashboardGrid unmount unsubscribes', (done) => { const { props, options } = prepare(); const component = mountWithIntl( <OpenSearchDashboardsContextProvider services={options}> <DashboardGrid {...props} /> </OpenSearchDashboardsContextProvider> ); component.unmount(); props.container .getInput$() .pipe(skip(1)) .subscribe(() => { done(); }); props.container.updateInput({ expandedPanelId: '1' }); });