[Dashboard] Add better debugging to error embeddable checks (#153457)

Closes https://github.com/elastic/kibana/issues/97701

## Summary

This PR replaces all instances of `await
testSubjects.missingOrFail('embeddableError');` with a call to the new
`noErrorEmbeddablesPresent()` method from the `dashboardExpect` service.

This `noErrorEmbeddablesPresent()` method adds some extra debugging
logic to the error embeddable check where, if at least one error
embeddable is present, then both the panel title(s) and the relevant
error message(s) will be printed as part of the error that is thrown.

With these changes, if the attached flaky test fails again, we should at
least have some more information on **why** it failed.

### Flaky Test Runner

This was specifically only running the flaky
`save_search_session_relative_time.ts` test suite:

<a
href="https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/2024"><img
src="https://user-images.githubusercontent.com/8698078/227240095-a336b03b-6499-4d80-8b60-5e325d54a4ae.png"/></a>


### Checklist

- [x] [Unit or functional
tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html)
were updated or added to match the most common scenarios

### For maintainers

- [ ] This was checked for breaking API changes and was [labeled
appropriately](https://www.elastic.co/guide/en/kibana/master/contributing.html#kibana-release-notes-process)
This commit is contained in:
Hannah Mudge 2023-03-24 08:49:57 -06:00 committed by GitHub
parent 464169f0b4
commit adb0bb58d3
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 44 additions and 10 deletions

View file

@ -32,11 +32,42 @@ export class DashboardExpectService extends FtrService {
}
async visualizationsArePresent(vizList: string[]) {
this.log.debug('Checking all visualisations are present on dashsboard');
this.log.debug('Checking all visualisations are present on the dashboard');
const notLoaded = await this.dashboard.getNotLoadedVisualizations(vizList);
expect(notLoaded).to.be.empty();
}
/**
* Asserts that there is no error embeddables on the dashboard
* @throws An error if an error embeddable is present
*/
async noErrorEmbeddablesPresent() {
this.log.debug('Ensure that there are no error embeddables on the dashboard');
const errorEmbeddables = await this.testSubjects.findAll('embeddableError');
if (errorEmbeddables.length > 0) {
const errorMessages = await Promise.all(
errorEmbeddables.map(async (embeddable) => {
const panel = await embeddable.findByXpath('./..'); // get the parent of 'embeddableError'
let panelTitle = 'Empty title';
if (await this.testSubjects.descendantExists('dashboardPanelTitle', panel)) {
panelTitle = await (
await this.testSubjects.findDescendant('dashboardPanelTitle', panel)
).getVisibleText();
}
const panelError = await embeddable.getVisibleText();
return `${panelTitle}: "${panelError}"`;
})
);
throw new Error(
`Found error embeddable(s): ${errorMessages.reduce((errorString, error) => {
return errorString + '\n' + `\t- ${error}`;
}, '')}`
);
}
}
async selectedLegendColorCount(color: string, expectedCount: number) {
this.log.debug(`DashboardExpect.selectedLegendColorCount(${color}, ${expectedCount})`);
await this.retry.try(async () => {

View file

@ -16,6 +16,8 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const dashboardPanelActions = getService('dashboardPanelActions');
const queryBar = getService('queryBar');
const elasticChart = getService('elasticChart');
const dashboardExpect = getService('dashboardExpect');
const xyChartSelector = 'xyVisChart';
const enableNewChartLibraryDebug = async () => {
@ -36,7 +38,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await PageObjects.common.navigateToApp('dashboard');
await PageObjects.dashboard.loadSavedDashboard('Not Delayed');
await PageObjects.header.waitUntilLoadingHasFinished();
await testSubjects.missingOrFail('embeddableError');
await dashboardExpect.noErrorEmbeddablesPresent();
await enableNewChartLibraryDebug();
const data = await PageObjects.visChart.getBarChartData(xyChartSelector, 'Sum of bytes');
expect(data.length).to.be(5);
@ -46,7 +48,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await PageObjects.common.navigateToApp('dashboard');
await PageObjects.dashboard.loadSavedDashboard('Delayed 5s');
await PageObjects.header.waitUntilLoadingHasFinished();
await testSubjects.missingOrFail('embeddableError');
await dashboardExpect.noErrorEmbeddablesPresent();
await enableNewChartLibraryDebug();
const data = await PageObjects.visChart.getBarChartData(xyChartSelector, 'Sum of bytes');
expect(data.length).to.be(5);

View file

@ -25,6 +25,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const queryBar = getService('queryBar');
const elasticChart = getService('elasticChart');
const toasts = getService('toasts');
const dashboardExpect = getService('dashboardExpect');
const enableNewChartLibraryDebug = async () => {
await elasticChart.setNewChartUiDebugFlag();
@ -63,7 +64,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await queryBar.clickQuerySubmitButton();
await PageObjects.header.waitUntilLoadingHasFinished();
await searchSessions.expectState('completed');
await testSubjects.missingOrFail('embeddableError');
await dashboardExpect.noErrorEmbeddablesPresent();
const session2 = await dashboardPanelActions.getSearchSessionIdByTitle(
'Sum of Bytes by Extension'
);
@ -104,7 +105,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
// Check that session is restored
await searchSessions.expectState('restored');
await testSubjects.missingOrFail('embeddableError');
await dashboardExpect.noErrorEmbeddablesPresent();
// switching dashboard to edit mode (or any other non-fetch required) state change
// should leave session state untouched

View file

@ -9,7 +9,6 @@ import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../../ftr_provider_context';
export default function ({ getService, getPageObjects }: FtrProviderContext) {
const testSubjects = getService('testSubjects');
const log = getService('log');
const retry = getService('retry');
const PageObjects = getPageObjects([
@ -85,7 +84,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
async function checkSampleDashboardLoaded(visualizationContainer?: string) {
log.debug('Checking no error labels');
await testSubjects.missingOrFail('embeddableError');
await dashboardExpect.noErrorEmbeddablesPresent();
log.debug('Checking charts rendered');
await elasticChart.waitForRenderComplete(visualizationContainer ?? 'lnsVisualizationContainer');
log.debug('Checking saved searches rendered');

View file

@ -27,6 +27,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const listingTable = getService('listingTable');
const testSubjects = getService('testSubjects');
const elasticChart = getService('elasticChart');
const dashboardExpect = getService('dashboardExpect');
describe('Session and searches integration', () => {
before(async function () {
@ -195,7 +196,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
await searchSessionItem.view();
expect(await toasts.getToastCount()).to.be(0); // there should be no warnings
await searchSessions.expectState('restored', 20000);
await testSubjects.missingOrFail('embeddableError');
await dashboardExpect.noErrorEmbeddablesPresent();
const data = await elasticChart.getChartDebugData();
expect(data!.bars![0].bars.length).to.eql(4);

View file

@ -9,7 +9,6 @@ import expect from '@kbn/expect';
import { FtrProviderContext } from '../../../../ftr_provider_context';
export default function ({ getService, getPageObjects }: FtrProviderContext) {
const testSubjects = getService('testSubjects');
const spacesService = getService('spaces');
const security = getService('security');
const PageObjects = getPageObjects([
@ -26,6 +25,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
const searchSessions = getService('searchSessions');
const kibanaServer = getService('kibanaServer');
const toasts = getService('toasts');
const dashboardExpect = getService('dashboardExpect');
describe('dashboard in space', () => {
afterEach(async () => await clean());
@ -67,7 +67,7 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) {
// Check that session is restored
await searchSessions.expectState('restored');
await testSubjects.missingOrFail('embeddableError');
await dashboardExpect.noErrorEmbeddablesPresent();
expect(await toasts.getToastCount()).to.be(0); // no session restoration related warnings
});
});