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:
Stacey Gammon 2018-08-07 14:24:25 -04:00 committed by GitHub
parent 94be31981d
commit 9d9c6c808a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
13 changed files with 93 additions and 125 deletions

View file

@ -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);

View file

@ -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();

View file

@ -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',

View file

@ -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'));

View file

@ -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'),

View file

@ -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')
};

View file

@ -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

View file

@ -21,3 +21,4 @@ export { DashboardVisualizationProvider } from './visualizations';
export { DashboardExpectProvider } from './expectations';
export { DashboardAddPanelProvider } from './add_panel';
export { DashboardPanelActionsProvider } from './panel_actions';

View file

@ -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';

View 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`);
}
});
}
};
}

View file

@ -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';

View file

@ -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`);
}
});
}
};
}