kibana/test/functional/services/renderable.ts
Dzmitry Lemechko 54fddef2db
Ftr/speedup dashboard tests (#160722)
## Summary

While splitting `test/functional/apps/dashboard/group2/config.ts` in
#160612, I noticed that some tests (`it` function level) takes 30-45
seconds though having little actions to do in Kibana.

After closer look I found that:
- `await PageObjects.dashboard.clickNewDashboard();` call takes ~13-15
seconds when dashboard is empty
- `await dashboardAddPanel.closeAddPanel();` call takes ~12 seconds when
there are no flyouts displayed

Expected improvement:
- `await PageObjects.dashboard.clickNewDashboard()` call takes **2**
seconds, used **103** times in tests.
- `await dashboardAddPanel.closeAddPanel()` call takes **3** seconds,
used **21** times in tests.

PR FTR configs runtime
<img width="778" alt="image"
src="673fee19-91ef-4bc3-9848-5f844b42774c">

`main` branch last 3 days avg configs runtime
<img width="1555" alt="image"
src="6e364cb9-c786-411a-9491-a749351f4c94">



flaky test runner 50x for 6 most affected configs
https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/2519
2023-06-28 18:49:32 +02:00

76 lines
3.1 KiB
TypeScript

/*
* 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 { FtrService } from '../ftr_provider_context';
const RENDER_COMPLETE_SELECTOR = '[data-render-complete="true"]';
const RENDER_COMPLETE_PENDING_SELECTOR = '[data-render-complete="false"]';
const DATA_LOADING_SELECTOR = '[data-loading]';
export class RenderableService extends FtrService {
private readonly log = this.ctx.getService('log');
private readonly retry = this.ctx.getService('retry');
private readonly find = this.ctx.getService('find');
/**
* 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.
*/
public async waitForRender(count: number = 1): Promise<void> {
this.log.debug(`Renderable.waitForRender for ${count} elements`);
// exit if there are no objects expected
if (count === 0) {
return;
}
await this.retry.try(async () => {
const completedElements = await this.find.allByCssSelector(RENDER_COMPLETE_SELECTOR);
if (completedElements.length < count) {
const pendingElements = await this.find.allByCssSelector(
RENDER_COMPLETE_PENDING_SELECTOR,
2500
);
const pendingElementNames = [];
for (const pendingElement of pendingElements) {
const title = await pendingElement.getAttribute('data-title');
pendingElementNames.push(title);
}
throw new Error(`${
completedElements.length
} elements completed rendering, still waiting on a total of ${count}
specifically:\n${pendingElementNames.join('\n')}`);
}
const stillLoadingElements = await this.find.allByCssSelector(DATA_LOADING_SELECTOR, 1000);
if (stillLoadingElements.length > 0) {
throw new Error(`${stillLoadingElements.length} elements still loading contents`);
}
});
}
public async getRenderCount(count: number = 1): Promise<Record<string, number>> {
const map: Record<string, number> = {};
await this.waitForRender(count);
const renderedElements = await this.find.allByCssSelector(RENDER_COMPLETE_SELECTOR);
for (let i = 0; i < renderedElements.length; i++) {
const renderedElement = renderedElements[i];
const title = (await renderedElement.getAttribute('data-title')) || i.toString();
const renderingCount = Number(
(await renderedElement.getAttribute('data-rendering-count')) || '0'
);
map[title] = renderingCount;
}
return map;
}
}