Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Time to Visualize] Adds functional tests for linking/unlinking panel from embeddable library #89612

Merged
merged 9 commits into from
Feb 8, 2021
Merged
1 change: 1 addition & 0 deletions .github/CODEOWNERS
Validating CODEOWNERS rules …
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@
/src/plugins/dashboard/ @elastic/kibana-presentation
/src/plugins/input_control_vis/ @elastic/kibana-presentation
/src/plugins/vis_type_markdown/ @elastic/kibana-presentation
/test/functional/apps/dashboard/ @elastic/kibana-presentation
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

/x-pack/plugins/canvas/ @elastic/kibana-presentation
/x-pack/plugins/dashboard_enhanced/ @elastic/kibana-presentation
/x-pack/test/functional/apps/canvas/ @elastic/kibana-presentation
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ import { NotificationsStart } from '../../services/core';
import { dashboardAddToLibraryAction } from '../../dashboard_strings';
import { DashboardPanelState, DASHBOARD_CONTAINER_TYPE, DashboardContainer } from '..';

export const ACTION_ADD_TO_LIBRARY = 'addToFromLibrary';
export const ACTION_ADD_TO_LIBRARY = 'saveToLibrary';

export interface AddToLibraryActionContext {
embeddable: IEmbeddable;
Expand Down
111 changes: 111 additions & 0 deletions test/functional/apps/dashboard/embeddable_library.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0 and the Server Side Public License, v 1; you may not use this file except
* in compliance with, at your election, the Elastic License 2.0 or the Server
* Side Public License, v 1.
*/

import expect from '@kbn/expect';

import { FtrProviderContext } from '../../ftr_provider_context';

export default function ({ getService, getPageObjects }: FtrProviderContext) {
const PageObjects = getPageObjects(['dashboard', 'header', 'visualize', 'settings', 'common']);
const esArchiver = getService('esArchiver');
const find = getService('find');
const kibanaServer = getService('kibanaServer');
const testSubjects = getService('testSubjects');
const dashboardAddPanel = getService('dashboardAddPanel');
const panelActions = getService('dashboardPanelActions');

describe('embeddable library', () => {
before(async () => {
await esArchiver.load('dashboard/current/kibana');
await kibanaServer.uiSettings.replace({
defaultIndex: '0bf35f60-3dc9-11e8-8660-4d65aa086b3c',
});
await PageObjects.common.navigateToApp('dashboard');
await PageObjects.dashboard.preserveCrossAppState();
await PageObjects.dashboard.clickNewDashboard();
});

it('unlink visualize panel from embeddable library', async () => {
// add heatmap panel from library
await dashboardAddPanel.clickOpenAddPanel();
await dashboardAddPanel.filterEmbeddableNames('Rendering Test: heatmap');
await find.clickByButtonText('Rendering Test: heatmap');
await dashboardAddPanel.closeAddPanel();

const originalPanel = await testSubjects.find('embeddablePanelHeading-RenderingTest:heatmap');
await panelActions.unlinkFromLibary(originalPanel);
await testSubjects.existOrFail('unlinkPanelSuccess');

const updatedPanel = await testSubjects.find('embeddablePanelHeading-RenderingTest:heatmap');
const libraryActionExists = await testSubjects.descendantExists(
'embeddablePanelNotification-ACTION_LIBRARY_NOTIFICATION',
updatedPanel
);
expect(libraryActionExists).to.be(false);

await dashboardAddPanel.clickOpenAddPanel();
await dashboardAddPanel.filterEmbeddableNames('Rendering Test: heatmap');
await find.existsByLinkText('Rendering Test: heatmap');
await dashboardAddPanel.closeAddPanel();
});

it('save visualize panel to embeddable library', async () => {
const originalPanel = await testSubjects.find('embeddablePanelHeading-RenderingTest:heatmap');
await panelActions.saveToLibrary('Rendering Test: heatmap - copy', originalPanel);
await testSubjects.existOrFail('addPanelToLibrarySuccess');

const updatedPanel = await testSubjects.find(
'embeddablePanelHeading-RenderingTest:heatmap-copy'
);
const libraryActionExists = await testSubjects.descendantExists(
'embeddablePanelNotification-ACTION_LIBRARY_NOTIFICATION',
updatedPanel
);
expect(libraryActionExists).to.be(true);
});

it('unlink map panel from embeddable library', async () => {
// add map panel from library
await dashboardAddPanel.clickOpenAddPanel();
await dashboardAddPanel.filterEmbeddableNames('Rendering Test: geo map');
await find.clickByButtonText('Rendering Test: geo map');
await dashboardAddPanel.closeAddPanel();

const originalPanel = await testSubjects.find('embeddablePanelHeading-RenderingTest:geomap');
await panelActions.unlinkFromLibary(originalPanel);
await testSubjects.existOrFail('unlinkPanelSuccess');

const updatedPanel = await testSubjects.find('embeddablePanelHeading-RenderingTest:geomap');
const libraryActionExists = await testSubjects.descendantExists(
'embeddablePanelNotification-ACTION_LIBRARY_NOTIFICATION',
updatedPanel
);
expect(libraryActionExists).to.be(false);

await dashboardAddPanel.clickOpenAddPanel();
await dashboardAddPanel.filterEmbeddableNames('Rendering Test: geo map');
await find.existsByLinkText('Rendering Test: geo map');
await dashboardAddPanel.closeAddPanel();
});

it('save map panel to embeddable library', async () => {
const originalPanel = await testSubjects.find('embeddablePanelHeading-RenderingTest:geomap');
await panelActions.saveToLibrary('Rendering Test: geo map - copy', originalPanel);
await testSubjects.existOrFail('addPanelToLibrarySuccess');

const updatedPanel = await testSubjects.find(
'embeddablePanelHeading-RenderingTest:geomap-copy'
);
const libraryActionExists = await testSubjects.descendantExists(
'embeddablePanelNotification-ACTION_LIBRARY_NOTIFICATION',
updatedPanel
);
expect(libraryActionExists).to.be(true);
});
});
}
1 change: 1 addition & 0 deletions test/functional/apps/dashboard/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export default function ({ getService, loadTestFile }: FtrProviderContext) {
// The dashboard_snapshot test below requires the timestamped URL which breaks the view_edit test.
// If we don't use the timestamp in the URL, the colors in the charts will be different.
loadTestFile(require.resolve('./dashboard_snapshots'));
loadTestFile(require.resolve('./embeddable_library'));
});

// Each of these tests call initTests themselves, the way it was originally written. The above tests only load
Expand Down
25 changes: 25 additions & 0 deletions test/functional/services/dashboard/panel_actions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ const TOGGLE_EXPAND_PANEL_DATA_TEST_SUBJ = 'embeddablePanelAction-togglePanel';
const CUSTOMIZE_PANEL_DATA_TEST_SUBJ = 'embeddablePanelAction-ACTION_CUSTOMIZE_PANEL';
const OPEN_CONTEXT_MENU_ICON_DATA_TEST_SUBJ = 'embeddablePanelToggleMenuIcon';
const OPEN_INSPECTOR_TEST_SUBJ = 'embeddablePanelAction-openInspector';
const LIBRARY_NOTIFICATION_TEST_SUBJ = 'embeddablePanelNotification-ACTION_LIBRARY_NOTIFICATION';
const SAVE_TO_LIBRARY_TEST_SUBJ = 'embeddablePanelAction-saveToLibrary';

export function DashboardPanelActionsProvider({ getService, getPageObjects }: FtrProviderContext) {
const log = getService('log');
Expand Down Expand Up @@ -170,6 +172,29 @@ export function DashboardPanelActionsProvider({ getService, getPageObjects }: Ft
await testSubjects.click(OPEN_INSPECTOR_TEST_SUBJ);
}

async unlinkFromLibary(parent?: WebElementWrapper) {
log.debug('unlinkFromLibrary');
const libraryNotification = parent
? await testSubjects.findDescendant(LIBRARY_NOTIFICATION_TEST_SUBJ, parent)
: await testSubjects.find(LIBRARY_NOTIFICATION_TEST_SUBJ);
await libraryNotification.click();
await testSubjects.click('libraryNotificationUnlinkButton');
}

async saveToLibrary(newTitle: string, parent?: WebElementWrapper) {
log.debug('saveToLibrary');
await this.openContextMenu(parent);
const exists = await testSubjects.exists(SAVE_TO_LIBRARY_TEST_SUBJ);
if (!exists) {
await this.clickContextMenuMoreItem();
}
await testSubjects.click(SAVE_TO_LIBRARY_TEST_SUBJ);
await testSubjects.setValue('savedObjectTitle', newTitle, {
clearWithKeyboard: true,
});
await testSubjects.click('confirmSaveSavedObjectButton');
}

async expectExistsRemovePanelAction() {
log.debug('expectExistsRemovePanelAction');
await this.expectExistsPanelAction(REMOVE_PANEL_DATA_TEST_SUBJ);
Expand Down
38 changes: 38 additions & 0 deletions x-pack/test/functional/apps/lens/dashboard.ts
Original file line number Diff line number Diff line change
Expand Up @@ -156,5 +156,43 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await panelActions.clickContextMenuMoreItem();
await testSubjects.existOrFail(ACTION_TEST_SUBJ);
});

it('unlink lens panel from embeddable library', async () => {
await PageObjects.common.navigateToApp('dashboard');
await PageObjects.dashboard.clickNewDashboard();
await dashboardAddPanel.clickOpenAddPanel();
await dashboardAddPanel.filterEmbeddableNames('lnsPieVis');
await find.clickByButtonText('lnsPieVis');
await dashboardAddPanel.closeAddPanel();

const originalPanel = await testSubjects.find('embeddablePanelHeading-lnsPieVis');
await panelActions.unlinkFromLibary(originalPanel);
await testSubjects.existOrFail('unlinkPanelSuccess');

const updatedPanel = await testSubjects.find('embeddablePanelHeading-lnsPieVis');
const libraryActionExists = await testSubjects.descendantExists(
'embeddablePanelNotification-ACTION_LIBRARY_NOTIFICATION',
updatedPanel
);
expect(libraryActionExists).to.be(false);
});

it('save lens panel to embeddable library', async () => {
const originalPanel = await testSubjects.find('embeddablePanelHeading-lnsPieVis');
await panelActions.saveToLibrary('lnsPieVis - copy', originalPanel);
await testSubjects.click('confirmSaveSavedObjectButton');
await testSubjects.existOrFail('addPanelToLibrarySuccess');

const updatedPanel = await testSubjects.find('embeddablePanelHeading-lnsPieVis-copy');
const libraryActionExists = await testSubjects.descendantExists(
'embeddablePanelNotification-ACTION_LIBRARY_NOTIFICATION',
updatedPanel
);
expect(libraryActionExists).to.be(true);

await dashboardAddPanel.clickOpenAddPanel();
await dashboardAddPanel.filterEmbeddableNames('lnsPieVis');
await find.existsByLinkText('lnsPieVis');
});
});
}
80 changes: 80 additions & 0 deletions x-pack/test/functional/apps/maps/embeddable/embeddable_library.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import expect from '@kbn/expect';

export default function ({ getPageObjects, getService }) {
const find = getService('find');
const testSubjects = getService('testSubjects');
const PageObjects = getPageObjects(['common', 'dashboard', 'header', 'maps', 'visualize']);
const kibanaServer = getService('kibanaServer');
const security = getService('security');
const dashboardAddPanel = getService('dashboardAddPanel');
const dashboardPanelActions = getService('dashboardPanelActions');
const dashboardVisualizations = getService('dashboardVisualizations');

describe('maps in embeddable library', () => {
before(async () => {
await security.testUser.setRoles(
[
'test_logstash_reader',
'global_maps_all',
'geoshape_data_reader',
'global_dashboard_all',
'meta_for_geoshape_data_reader',
],
false
);
await kibanaServer.uiSettings.replace({
defaultIndex: 'c698b940-e149-11e8-a35a-370a8516603a',
});
await PageObjects.common.navigateToApp('dashboard');
await PageObjects.dashboard.clickNewDashboard();
await dashboardAddPanel.clickCreateNewLink();
await dashboardVisualizations.ensureNewVisualizationDialogIsShowing();
await PageObjects.visualize.clickMapsApp();
await PageObjects.header.waitUntilLoadingHasFinished();
await PageObjects.maps.waitForLayersToLoad();
await PageObjects.maps.clickSaveAndReturnButton();
await PageObjects.dashboard.waitForRenderComplete();
});

after(async () => {
await security.testUser.restoreDefaults();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One concern I have about this test is that "document example" saved object is used in other maps tests. What happens if there is an error linking the saved object back to the library? Will down stream tests be effected? Seems like there is not a good way to clean up the "document example" saved object incase it gets left in a stranded state. How about creating a new map saved object in https://github.com/elastic/kibana/blob/master/x-pack/test/functional/es_archives/maps/kibana/data.json that is used only in this test to avoid an potential flaky tests if this test fails.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The 'unlink' feature doesn't delete any saved objects. It only affects the panel that it is applied against, and this panel looks to be created on a new dashboard so it shouldn't cause any downstream problems.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nreese I've updated the maps tests to create a new map. Can you take a look when you get a chance?

});

it('save map panel to embeddable library', async () => {
await dashboardPanelActions.saveToLibrary('embeddable library map');
await testSubjects.existOrFail('addPanelToLibrarySuccess');

const mapPanel = await testSubjects.find('embeddablePanelHeading-embeddablelibrarymap');
const libraryActionExists = await testSubjects.descendantExists(
'embeddablePanelNotification-ACTION_LIBRARY_NOTIFICATION',
mapPanel
);
expect(libraryActionExists).to.be(true);
});

it('unlink map panel from embeddable library', async () => {
const originalPanel = await testSubjects.find('embeddablePanelHeading-embeddablelibrarymap');
await dashboardPanelActions.unlinkFromLibary(originalPanel);
await testSubjects.existOrFail('unlinkPanelSuccess');

const updatedPanel = await testSubjects.find('embeddablePanelHeading-embeddablelibrarymap');
const libraryActionExists = await testSubjects.descendantExists(
'embeddablePanelNotification-ACTION_LIBRARY_NOTIFICATION',
updatedPanel
);
expect(libraryActionExists).to.be(false);

await dashboardAddPanel.clickOpenAddPanel();
await dashboardAddPanel.filterEmbeddableNames('embeddable library map');
await find.existsByLinkText('embeddable library map');
await dashboardAddPanel.closeAddPanel();
});
});
}
1 change: 1 addition & 0 deletions x-pack/test/functional/apps/maps/embeddable/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ export default function ({ loadTestFile }) {
describe('embeddable', function () {
loadTestFile(require.resolve('./save_and_return'));
loadTestFile(require.resolve('./dashboard'));
loadTestFile(require.resolve('./embeddable_library'));
loadTestFile(require.resolve('./embeddable_state'));
loadTestFile(require.resolve('./tooltip_filter_actions'));
});
Expand Down