Make visualization.waitForRender more generic and put in an embeddable class (#21688)
* Make visualization.waitForRender more generic and put in an embeddable class. * embeddable -> renderable * missed a reference
This commit is contained in:
parent
94be31981d
commit
9d9c6c808a
13 changed files with 93 additions and 125 deletions
|
@ -27,6 +27,7 @@ export default function ({ getService, getPageObjects }) {
|
|||
const dashboardExpect = getService('dashboardExpect');
|
||||
const queryBar = getService('queryBar');
|
||||
const dashboardAddPanel = getService('dashboardAddPanel');
|
||||
const renderable = getService('renderable');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const filterBar = getService('filterBar');
|
||||
const dashboardPanelActions = getService('dashboardPanelActions');
|
||||
|
@ -234,10 +235,13 @@ export default function ({ getService, getPageObjects }) {
|
|||
await queryBar.submitQuery();
|
||||
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
|
||||
// We are on the visualize page, not dashboard, so can't use "PageObjects.dashboard.waitForRenderComplete();"
|
||||
// as that expects an item with the `data-shared-items-count` tag.
|
||||
await renderable.waitForRender();
|
||||
await dashboardExpect.pieSliceCount(3);
|
||||
|
||||
await PageObjects.visualize.saveVisualization('Rendering-Test:-animal-sounds-pie');
|
||||
await PageObjects.visualize.saveVisualization('Rendering Test: animal sounds pie');
|
||||
await PageObjects.header.clickDashboard();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
|
@ -247,7 +251,7 @@ export default function ({ getService, getPageObjects }) {
|
|||
it('Nested visualization filter pills filters data as expected', async () => {
|
||||
await dashboardPanelActions.clickEdit();
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
await renderable.waitForRender();
|
||||
await PageObjects.dashboard.filterOnPieSlice('grr');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await dashboardExpect.pieSliceCount(1);
|
||||
|
|
|
@ -34,6 +34,8 @@ export default function ({ getService, getPageObjects, updateBaselines }) {
|
|||
|
||||
after(async function () {
|
||||
await remote.setWindowSize(1300, 900);
|
||||
const id = await PageObjects.dashboard.getDashboardIdFromCurrentUrl();
|
||||
await PageObjects.dashboard.deleteDashboard('area', id);
|
||||
});
|
||||
|
||||
// Skip until https://github.com/elastic/kibana/issues/19471 is fixed
|
||||
|
@ -51,8 +53,6 @@ export default function ({ getService, getPageObjects, updateBaselines }) {
|
|||
await dashboardPanelActions.toggleExpandPanel();
|
||||
|
||||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
// Render complete flag doesn't handle resizes from expanding.
|
||||
await PageObjects.common.sleep(2000);
|
||||
const percentSimilar = await screenshot.compareAgainstBaseline('tsvb_dashboard', updateBaselines);
|
||||
|
||||
await PageObjects.dashboard.clickExitFullScreenLogoButton();
|
||||
|
@ -73,8 +73,6 @@ export default function ({ getService, getPageObjects, updateBaselines }) {
|
|||
await dashboardPanelActions.toggleExpandPanel();
|
||||
|
||||
await PageObjects.dashboard.waitForRenderComplete();
|
||||
// Render complete flag doesn't handle resizes from expanding.
|
||||
await PageObjects.common.sleep(2000);
|
||||
const percentSimilar = await screenshot.compareAgainstBaseline('area_chart', updateBaselines);
|
||||
|
||||
await PageObjects.dashboard.clickExitFullScreenLogoButton();
|
||||
|
|
|
@ -23,7 +23,7 @@ export default function ({ getService, getPageObjects }) {
|
|||
const log = getService('log');
|
||||
const retry = getService('retry');
|
||||
const filterBar = getService('filterBar');
|
||||
const visualization = getService('visualization');
|
||||
const renderable = getService('renderable');
|
||||
const PageObjects = getPageObjects(['common', 'visualize', 'header']);
|
||||
|
||||
const fromTime = '2015-09-19 06:31:44.000';
|
||||
|
@ -162,7 +162,7 @@ export default function ({ getService, getPageObjects }) {
|
|||
it('should correctly filter for applied time filter on the main timefield', async () => {
|
||||
await filterBar.addFilter('@timestamp', 'is between', '2015-09-19', '2015-09-21');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await visualization.waitForRender();
|
||||
await renderable.waitForRender();
|
||||
const data = await PageObjects.visualize.getTableVisData();
|
||||
expect(data.trim().split('\n')).to.be.eql([
|
||||
'2015-09-20', '4,757',
|
||||
|
@ -172,7 +172,7 @@ export default function ({ getService, getPageObjects }) {
|
|||
it('should correctly filter for pinned filters', async () => {
|
||||
await filterBar.toggleFilterPinned('@timestamp');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await visualization.waitForRender();
|
||||
await renderable.waitForRender();
|
||||
const data = await PageObjects.visualize.getTableVisData();
|
||||
expect(data.trim().split('\n')).to.be.eql([
|
||||
'2015-09-20', '4,757',
|
||||
|
|
|
@ -22,7 +22,7 @@ import expect from 'expect.js';
|
|||
export default function ({ getService, getPageObjects }) {
|
||||
const filterBar = getService('filterBar');
|
||||
const log = getService('log');
|
||||
const visualization = getService('visualization');
|
||||
const renderable = getService('renderable');
|
||||
const embedding = getService('embedding');
|
||||
const PageObjects = getPageObjects(['common', 'visualize', 'header']);
|
||||
|
||||
|
@ -46,7 +46,7 @@ export default function ({ getService, getPageObjects }) {
|
|||
|
||||
it('should allow opening table vis in embedded mode', async () => {
|
||||
await embedding.openInEmbeddedMode();
|
||||
await visualization.waitForRender();
|
||||
await renderable.waitForRender();
|
||||
|
||||
const data = await PageObjects.visualize.getTableVisData();
|
||||
log.debug(data.split('\n'));
|
||||
|
@ -67,7 +67,7 @@ export default function ({ getService, getPageObjects }) {
|
|||
it('should allow to filter in embedded mode', async () => {
|
||||
await filterBar.addFilter('@timestamp', 'is between', '2015-09-19', '2015-09-21');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await visualization.waitForRender();
|
||||
await renderable.waitForRender();
|
||||
|
||||
const data = await PageObjects.visualize.getTableVisData();
|
||||
log.debug(data.split('\n'));
|
||||
|
|
|
@ -50,8 +50,8 @@ import {
|
|||
DashboardPanelActionsProvider,
|
||||
FlyoutProvider,
|
||||
ComboBoxProvider,
|
||||
VisualizationProvider,
|
||||
EmbeddingProvider,
|
||||
RenderableProvider,
|
||||
} from './services';
|
||||
|
||||
export default async function ({ readConfigFile }) {
|
||||
|
@ -107,8 +107,8 @@ export default async function ({ readConfigFile }) {
|
|||
dashboardPanelActions: DashboardPanelActionsProvider,
|
||||
flyout: FlyoutProvider,
|
||||
comboBox: ComboBoxProvider,
|
||||
visualization: VisualizationProvider,
|
||||
embedding: EmbeddingProvider,
|
||||
renderable: RenderableProvider,
|
||||
},
|
||||
servers: commonConfig.get('servers'),
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ export function DashboardPageProvider({ getService, getPageObjects }) {
|
|||
const kibanaServer = getService('kibanaServer');
|
||||
const testSubjects = getService('testSubjects');
|
||||
const dashboardAddPanel = getService('dashboardAddPanel');
|
||||
const visualization = getService('visualization');
|
||||
const renderable = getService('renderable');
|
||||
const PageObjects = getPageObjects(['common', 'header', 'settings', 'visualize']);
|
||||
|
||||
const defaultFindTimeout = config.get('timeouts.find');
|
||||
|
@ -207,6 +207,10 @@ export function DashboardPageProvider({ getService, getPageObjects }) {
|
|||
return await testSubjects.exists('createDashboardPromptButton');
|
||||
}
|
||||
|
||||
async checkDashboardListingRow(id) {
|
||||
await testSubjects.click(`checkboxSelectRow-${id}`);
|
||||
}
|
||||
|
||||
async checkDashboardListingSelectAllCheckbox() {
|
||||
const element = await testSubjects.find('checkboxSelectAll');
|
||||
const isSelected = await element.isSelected();
|
||||
|
@ -304,6 +308,14 @@ export function DashboardPageProvider({ getService, getPageObjects }) {
|
|||
return await testSubjects.exists('saveDashboardSuccess');
|
||||
}
|
||||
|
||||
async deleteDashboard(dashboardName, dashboardId) {
|
||||
await this.gotoDashboardLandingPage();
|
||||
await this.searchForDashboardWithName(dashboardName);
|
||||
await this.checkDashboardListingRow(dashboardId);
|
||||
await this.clickDeleteSelectedDashboards();
|
||||
await PageObjects.common.clickConfirmOnModal();
|
||||
}
|
||||
|
||||
async cancelSave() {
|
||||
log.debug('Canceling save');
|
||||
await testSubjects.click('saveCancelButton');
|
||||
|
@ -550,12 +562,9 @@ export function DashboardPageProvider({ getService, getPageObjects }) {
|
|||
}
|
||||
|
||||
async waitForRenderComplete() {
|
||||
await retry.try(async () => {
|
||||
const sharedItems = await this.getPanelSharedItemData();
|
||||
await Promise.all(sharedItems.map(async sharedItem => {
|
||||
return await visualization.waitForRender(sharedItem.element, sharedItem.title, { ignoreNonVisualization: true });
|
||||
}));
|
||||
});
|
||||
log.debug('waitForRenderComplete');
|
||||
const count = await this.getSharedItemsCount();
|
||||
await renderable.waitForRender(parseInt(count));
|
||||
}
|
||||
|
||||
async getSharedContainerData() {
|
||||
|
@ -563,7 +572,8 @@ export function DashboardPageProvider({ getService, getPageObjects }) {
|
|||
const sharedContainer = await find.byCssSelector('[data-shared-items-container]');
|
||||
return {
|
||||
title: await sharedContainer.getAttribute('data-title'),
|
||||
description: await sharedContainer.getAttribute('data-description')
|
||||
description: await sharedContainer.getAttribute('data-description'),
|
||||
count: await sharedContainer.getAttribute('data-shared-items-count'),
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -572,7 +582,6 @@ export function DashboardPageProvider({ getService, getPageObjects }) {
|
|||
const sharedItems = await find.allByCssSelector('[data-shared-item]');
|
||||
return await Promise.all(sharedItems.map(async sharedItem => {
|
||||
return {
|
||||
element: sharedItem,
|
||||
title: await sharedItem.getAttribute('data-title'),
|
||||
description: await sharedItem.getAttribute('data-description')
|
||||
};
|
||||
|
|
|
@ -29,7 +29,7 @@ export function VisualizePageProvider({ getService, getPageObjects }) {
|
|||
const find = getService('find');
|
||||
const log = getService('log');
|
||||
const flyout = getService('flyout');
|
||||
const visualization = getService('visualization');
|
||||
const renderable = getService('renderable');
|
||||
const PageObjects = getPageObjects(['common', 'header']);
|
||||
const defaultFindTimeout = config.get('timeouts.find');
|
||||
|
||||
|
@ -579,7 +579,9 @@ export function VisualizePageProvider({ getService, getPageObjects }) {
|
|||
async clickGo() {
|
||||
await testSubjects.click('visualizeEditorRenderButton');
|
||||
await PageObjects.header.waitUntilLoadingHasFinished();
|
||||
await visualization.waitForRender();
|
||||
// For some reason there are two `data-render-complete` tags on each visualization in the visualize page.
|
||||
const countOfDataCompleteFlags = 2;
|
||||
await renderable.waitForRender(countOfDataCompleteFlags);
|
||||
}
|
||||
|
||||
async clickReset() {
|
||||
|
|
Binary file not shown.
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 95 KiB |
|
@ -21,3 +21,4 @@ export { DashboardVisualizationProvider } from './visualizations';
|
|||
export { DashboardExpectProvider } from './expectations';
|
||||
export { DashboardAddPanelProvider } from './add_panel';
|
||||
export { DashboardPanelActionsProvider } from './panel_actions';
|
||||
|
||||
|
|
|
@ -29,6 +29,6 @@ export { VisualizeListingTableProvider } from './visualize_listing_table';
|
|||
export { FlyoutProvider } from './flyout';
|
||||
export { EmbeddingProvider } from './embedding';
|
||||
export { ComboBoxProvider } from './combo_box';
|
||||
export { RenderableProvider } from './renderable';
|
||||
|
||||
export * from './dashboard';
|
||||
export * from './visualize';
|
||||
|
|
52
test/functional/services/renderable.js
Normal file
52
test/functional/services/renderable.js
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
const RENDER_COMPLETE_SELECTOR = '[data-render-complete="true"]';
|
||||
const DATA_LOADING_SELECTOR = '[data-loading]';
|
||||
|
||||
export function RenderableProvider({ getService }) {
|
||||
const log = getService('log');
|
||||
const retry = getService('retry');
|
||||
const find = getService('find');
|
||||
|
||||
return new class Renderable {
|
||||
|
||||
/**
|
||||
* This method waits for a certain number of objects to finish rendering and loading, which is indicated
|
||||
* by a couple tags. The RENDER_COMPLETE_SELECTOR indicates that it's done initially loading up. Some
|
||||
* visualizations also add a DATA_LOADING_SELECTOR when the internal data is loading. This test will not
|
||||
* return if any of those tags are found.
|
||||
* @param count {Number} Number of RENDER_COMPLETE_SELECTORs to wait for.
|
||||
*/
|
||||
async waitForRender(count = 1) {
|
||||
log.debug(`Renderable.waitForRender for ${count} elements`);
|
||||
await retry.try(async () => {
|
||||
const completedElements = await find.allByCssSelector(RENDER_COMPLETE_SELECTOR);
|
||||
if (completedElements.length < count) {
|
||||
throw new Error(`${completedElements.length} elements completed rendering, waiting on a total of ${count}`);
|
||||
}
|
||||
|
||||
const stillLoadingElements = await find.allByCssSelector(DATA_LOADING_SELECTOR);
|
||||
if (stillLoadingElements.length > 0) {
|
||||
throw new Error(`${stillLoadingElements.length} elements still loading contents`);
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
|
@ -1,20 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export { VisualizationProvider } from './visualization';
|
|
@ -1,78 +0,0 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
const TEST_SUBJECT_VISUALIZE = 'visualizationLoader';
|
||||
|
||||
export function VisualizationProvider({ getService }) {
|
||||
const log = getService('log');
|
||||
const retry = getService('retry');
|
||||
const find = getService('find');
|
||||
const testSubjects = getService('testSubjects');
|
||||
|
||||
return new class Visualization {
|
||||
|
||||
/**
|
||||
* This method waits for a visualization to finish rendering in case its currently rendering.
|
||||
* Every visualization indicates a loading state via an attribute while data is currently fetched
|
||||
* and then rendered. This method waits for that attribute to be gone.
|
||||
* If you call this method before a visualization started fetching its data, it might return immediately,
|
||||
* i.e. it does not wait for the next fetch and render to start.
|
||||
*
|
||||
* You can pass in a parent element, in which the visualization should be located. The parent element can also be
|
||||
* the visualization element itself. If you don't specify a parent element, this method looks for a visualization
|
||||
* in body. In case you specify a parent (or use the default) and multiple visualizations are found within that element,
|
||||
* this method will throw an error.
|
||||
*
|
||||
* This method will wait an absolute of 10 seconds for the visualization to finish rendering.
|
||||
*/
|
||||
async waitForRender(parentElement, title = '', { ignoreNonVisualization } = {}) {
|
||||
log.debug(`Visualization.waitForRender(${title})`);
|
||||
const tag = `waitForRender(${title}):`;
|
||||
if (!parentElement) {
|
||||
parentElement = await find.byCssSelector('body');
|
||||
}
|
||||
const testSubj = await parentElement.getAttribute('data-test-subj');
|
||||
let vis;
|
||||
if (testSubj === TEST_SUBJECT_VISUALIZE) {
|
||||
vis = parentElement;
|
||||
} else {
|
||||
const visualizations = await testSubjects.findAllDescendant(TEST_SUBJECT_VISUALIZE, parentElement);
|
||||
if (visualizations.length === 0 && ignoreNonVisualization) {
|
||||
log.info(`${tag} element does not contain a visualization, ignoring it`);
|
||||
return;
|
||||
}
|
||||
if (visualizations.length !== 1) {
|
||||
throw new Error(`${tag} expects exactly 1 visualization in the specified parent, but found ${visualizations.length}`);
|
||||
}
|
||||
vis = visualizations[0];
|
||||
}
|
||||
await retry.try(async () => {
|
||||
const renderComplete = await vis.getAttribute('data-render-complete');
|
||||
if (renderComplete !== 'disabled' && renderComplete !== 'true') {
|
||||
throw new Error(`${tag} visualization has not finished first render`);
|
||||
}
|
||||
const isLoading = await vis.getAttribute('data-loading');
|
||||
if (isLoading !== null) {
|
||||
throw new Error(`${tag} visualization is still loading/rendering`);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
};
|
||||
}
|
Loading…
Reference in a new issue