/* * 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. */ import React from 'react'; import { mount } from 'enzyme'; import { nextTick } from 'test_utils/enzyme_helpers'; import { findTestSubject } from 'test_utils/helpers'; import { I18nProvider } from '@osd/i18n/react'; import { CONTEXT_MENU_TRIGGER } from '../triggers'; import { Action, UiActionsStart, ActionType } from '../../../../ui_actions/public'; import { Trigger, ViewMode } from '../types'; import { isErrorEmbeddable } from '../embeddables'; import { EmbeddablePanel } from './embeddable_panel'; import { createEditModeAction } from '../test_samples/actions'; import { ContactCardEmbeddableFactory, CONTACT_CARD_EMBEDDABLE, } from '../test_samples/embeddables/contact_card/contact_card_embeddable_factory'; import { HelloWorldContainer } from '../test_samples/embeddables/hello_world_container'; import { ContactCardEmbeddable, ContactCardEmbeddableInput, ContactCardEmbeddableOutput, } from '../test_samples/embeddables/contact_card/contact_card_embeddable'; import { inspectorPluginMock } from '../../../../inspector/public/mocks'; import { EuiBadge } from '@elastic/eui'; import { embeddablePluginMock } from '../../mocks'; import { applicationServiceMock } from '../../../../../core/public/mocks'; const actionRegistry = new Map(); const triggerRegistry = new Map(); const { setup, doStart } = embeddablePluginMock.createInstance(); const editModeAction = createEditModeAction(); const trigger: Trigger = { id: CONTEXT_MENU_TRIGGER, }; const embeddableFactory = new ContactCardEmbeddableFactory((() => null) as any, {} as any); const applicationMock = applicationServiceMock.createStartContract(); actionRegistry.set(editModeAction.id, editModeAction); triggerRegistry.set(trigger.id, trigger); setup.registerEmbeddableFactory(embeddableFactory.type, embeddableFactory); const start = doStart(); const getEmbeddableFactory = start.getEmbeddableFactory; test('HelloWorldContainer initializes embeddables', (done) => { const container = new HelloWorldContainer( { id: '123', panels: { '123': { explicitInput: { id: '123', firstName: 'Sam' }, type: CONTACT_CARD_EMBEDDABLE, }, }, }, { getEmbeddableFactory } as any ); const subscription = container.getOutput$().subscribe(() => { if (container.getOutput().embeddableLoaded['123']) { const embeddable = container.getChild('123'); expect(embeddable).toBeDefined(); expect(embeddable.id).toBe('123'); done(); } }); if (container.getOutput().embeddableLoaded['123']) { const embeddable = container.getChild('123'); expect(embeddable).toBeDefined(); expect(embeddable.id).toBe('123'); subscription.unsubscribe(); done(); } }); test('HelloWorldContainer.addNewEmbeddable', async () => { const container = new HelloWorldContainer({ id: '123', panels: {} }, { getEmbeddableFactory, } as any); const embeddable = await container.addNewEmbeddable( CONTACT_CARD_EMBEDDABLE, { firstName: 'opensearchDashboards', } ); expect(embeddable).toBeDefined(); if (!isErrorEmbeddable(embeddable)) { expect(embeddable.getInput().firstName).toBe('opensearchDashboards'); } else { expect(false).toBe(true); } const embeddableInContainer = container.getChild(embeddable.id); expect(embeddableInContainer).toBeDefined(); expect(embeddableInContainer.id).toBe(embeddable.id); }); test('Container view mode change propagates to children', async () => { const container = new HelloWorldContainer({ id: '123', panels: {}, viewMode: ViewMode.VIEW }, { getEmbeddableFactory, } as any); const embeddable = await container.addNewEmbeddable< ContactCardEmbeddableInput, ContactCardEmbeddableOutput, ContactCardEmbeddable >(CONTACT_CARD_EMBEDDABLE, { firstName: 'Bob', }); expect(embeddable.getInput().viewMode).toBe(ViewMode.VIEW); container.updateInput({ viewMode: ViewMode.EDIT }); expect(embeddable.getInput().viewMode).toBe(ViewMode.EDIT); }); test('HelloWorldContainer in view mode hides edit mode actions', async () => { const inspector = inspectorPluginMock.createStartContract(); const container = new HelloWorldContainer({ id: '123', panels: {}, viewMode: ViewMode.VIEW }, { getEmbeddableFactory, } as any); const embeddable = await container.addNewEmbeddable< ContactCardEmbeddableInput, ContactCardEmbeddableOutput, ContactCardEmbeddable >(CONTACT_CARD_EMBEDDABLE, { firstName: 'Bob', }); const component = mount( Promise.resolve([])} getAllEmbeddableFactories={start.getEmbeddableFactories} getEmbeddableFactory={start.getEmbeddableFactory} notifications={{} as any} application={applicationMock} overlays={{} as any} inspector={inspector} SavedObjectFinder={() => null} /> ); findTestSubject(component, 'embeddablePanelToggleMenuIcon').simulate('click'); expect(findTestSubject(component, `embeddablePanelContextMenuOpen`).length).toBe(1); await nextTick(); component.update(); expect(findTestSubject(component, `embeddablePanelAction-${editModeAction.id}`).length).toBe(0); }); const renderInEditModeAndOpenContextMenu = async ( embeddableInputs: any, getActions: UiActionsStart['getTriggerCompatibleActions'] = () => Promise.resolve([]) ) => { const inspector = inspectorPluginMock.createStartContract(); const container = new HelloWorldContainer({ id: '123', panels: {}, viewMode: ViewMode.VIEW }, { getEmbeddableFactory, } as any); const embeddable = await container.addNewEmbeddable< ContactCardEmbeddableInput, ContactCardEmbeddableOutput, ContactCardEmbeddable >(CONTACT_CARD_EMBEDDABLE, embeddableInputs); const component = mount( null} /> ); findTestSubject(component, 'embeddablePanelToggleMenuIcon').simulate('click'); await nextTick(); component.update(); return { component }; }; test('HelloWorldContainer in edit mode hides disabledActions', async () => { const action = { id: 'FOO', type: 'FOO' as ActionType, getIconType: () => undefined, getDisplayName: () => 'foo', isCompatible: async () => true, execute: async () => {}, order: 10, getHref: () => { return Promise.resolve(undefined); }, }; const getActions = () => Promise.resolve([action]); const { component: component1 } = await renderInEditModeAndOpenContextMenu( { firstName: 'Bob', }, getActions ); const { component: component2 } = await renderInEditModeAndOpenContextMenu( { firstName: 'Bob', disabledActions: ['FOO'], }, getActions ); const fooContextMenuActionItem1 = findTestSubject(component1, 'embeddablePanelAction-FOO'); const fooContextMenuActionItem2 = findTestSubject(component2, 'embeddablePanelAction-FOO'); expect(fooContextMenuActionItem1.length).toBe(1); expect(fooContextMenuActionItem2.length).toBe(0); }); test('HelloWorldContainer hides disabled badges', async () => { const action = { id: 'BAR', type: 'BAR' as ActionType, getIconType: () => undefined, getDisplayName: () => 'bar', isCompatible: async () => true, execute: async () => {}, order: 10, getHref: () => { return Promise.resolve(undefined); }, }; const getActions = () => Promise.resolve([action]); const { component: component1 } = await renderInEditModeAndOpenContextMenu( { firstName: 'Bob', }, getActions ); const { component: component2 } = await renderInEditModeAndOpenContextMenu( { firstName: 'Bob', disabledActions: ['BAR'], }, getActions ); expect(component1.find(EuiBadge).length).toBe(1); expect(component2.find(EuiBadge).length).toBe(0); }); test('HelloWorldContainer in edit mode shows edit mode actions', async () => { const inspector = inspectorPluginMock.createStartContract(); const container = new HelloWorldContainer({ id: '123', panels: {}, viewMode: ViewMode.VIEW }, { getEmbeddableFactory, } as any); const embeddable = await container.addNewEmbeddable< ContactCardEmbeddableInput, ContactCardEmbeddableOutput, ContactCardEmbeddable >(CONTACT_CARD_EMBEDDABLE, { firstName: 'Bob', }); const component = mount( Promise.resolve([])} getAllEmbeddableFactories={start.getEmbeddableFactories} getEmbeddableFactory={start.getEmbeddableFactory} notifications={{} as any} overlays={{} as any} application={applicationMock} inspector={inspector} SavedObjectFinder={() => null} /> ); const button = findTestSubject(component, 'embeddablePanelToggleMenuIcon'); expect(button.length).toBe(1); findTestSubject(component, 'embeddablePanelToggleMenuIcon').simulate('click'); expect(findTestSubject(component, `embeddablePanelContextMenuOpen`).length).toBe(1); await nextTick(); component.update(); expect(findTestSubject(component, `embeddablePanelAction-${editModeAction.id}`).length).toBe(0); container.updateInput({ viewMode: ViewMode.EDIT }); await nextTick(); component.update(); // Need to close and re-open to refresh. It doesn't update automatically. findTestSubject(component, 'embeddablePanelToggleMenuIcon').simulate('click'); await nextTick(); findTestSubject(component, 'embeddablePanelToggleMenuIcon').simulate('click'); await nextTick(); expect(findTestSubject(component, 'embeddablePanelContextMenuOpen').length).toBe(1); container.updateInput({ viewMode: ViewMode.VIEW }); await nextTick(); component.update(); // TODO: Fix this. // const action = findTestSubject(component, `embeddablePanelAction-${editModeAction.id}`); // expect(action.length).toBe(1); }); test('Updates when hidePanelTitles is toggled', async () => { const inspector = inspectorPluginMock.createStartContract(); const container = new HelloWorldContainer( { id: '123', panels: {}, viewMode: ViewMode.VIEW, hidePanelTitles: false }, { getEmbeddableFactory } as any ); const embeddable = await container.addNewEmbeddable< ContactCardEmbeddableInput, ContactCardEmbeddableOutput, ContactCardEmbeddable >(CONTACT_CARD_EMBEDDABLE, { firstName: 'Rob', lastName: 'Stark', }); const component = mount( Promise.resolve([])} getAllEmbeddableFactories={start.getEmbeddableFactories} getEmbeddableFactory={start.getEmbeddableFactory} notifications={{} as any} overlays={{} as any} application={applicationMock} inspector={inspector} SavedObjectFinder={() => null} /> ); let title = findTestSubject(component, `embeddablePanelHeading-HelloRobStark`); expect(title.length).toBe(1); await container.updateInput({ hidePanelTitles: true }); await nextTick(); component.update(); title = findTestSubject(component, `embeddablePanelHeading-HelloRobStark`); expect(title.length).toBe(0); await container.updateInput({ hidePanelTitles: false }); await nextTick(); component.update(); title = findTestSubject(component, `embeddablePanelHeading-HelloRobStark`); expect(title.length).toBe(1); }); test('Check when hide header option is false', async () => { const inspector = inspectorPluginMock.createStartContract(); const container = new HelloWorldContainer( { id: '123', panels: {}, viewMode: ViewMode.VIEW, hidePanelTitles: false }, { getEmbeddableFactory } as any ); const embeddable = await container.addNewEmbeddable< ContactCardEmbeddableInput, ContactCardEmbeddableOutput, ContactCardEmbeddable >(CONTACT_CARD_EMBEDDABLE, { firstName: 'Arya', lastName: 'Stark', }); const component = mount( Promise.resolve([])} getAllEmbeddableFactories={start.getEmbeddableFactories} getEmbeddableFactory={start.getEmbeddableFactory} notifications={{} as any} overlays={{} as any} application={applicationMock} inspector={inspector} SavedObjectFinder={() => null} hideHeader={false} /> ); const title = findTestSubject(component, `embeddablePanelHeading-HelloAryaStark`); expect(title.length).toBe(1); }); test('Check when hide header option is true', async () => { const inspector = inspectorPluginMock.createStartContract(); const container = new HelloWorldContainer( { id: '123', panels: {}, viewMode: ViewMode.VIEW, hidePanelTitles: false }, { getEmbeddableFactory } as any ); const embeddable = await container.addNewEmbeddable< ContactCardEmbeddableInput, ContactCardEmbeddableOutput, ContactCardEmbeddable >(CONTACT_CARD_EMBEDDABLE, { firstName: 'Arya', lastName: 'Stark', }); const component = mount( Promise.resolve([])} getAllEmbeddableFactories={start.getEmbeddableFactories} getEmbeddableFactory={start.getEmbeddableFactory} notifications={{} as any} overlays={{} as any} application={{} as any} inspector={inspector} SavedObjectFinder={() => null} hideHeader={true} /> ); const title = findTestSubject(component, `embeddablePanelHeading-HelloAryaStark`); expect(title.length).toBe(0); });