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

[RAC][Observability]: test cases for alerts pagination functional tests #112617

Merged
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

import querystring from 'querystring';
import { chunk } from 'lodash';
import { FtrProviderContext } from '../../ftr_provider_context';
import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper';
import { FtrProviderContext } from '../../../ftr_provider_context';
import { WebElementWrapper } from '../../../../../../test/functional/services/lib/web_element_wrapper';

// Based on the x-pack/test/functional/es_archives/observability/alerts archive.
const DATE_WITH_DATA = {
Expand All @@ -19,12 +19,14 @@ const DATE_WITH_DATA = {
const ALERTS_FLYOUT_SELECTOR = 'alertsFlyout';
const COPY_TO_CLIPBOARD_BUTTON_SELECTOR = 'copy-to-clipboard';
const ALERTS_TABLE_CONTAINER_SELECTOR = 'events-viewer-panel';

const ACTION_COLUMN_INDEX = 1;

type WorkflowStatus = 'open' | 'acknowledged' | 'closed';

export function ObservabilityAlertsProvider({ getPageObjects, getService }: FtrProviderContext) {
export function ObservabilityAlertsCommonProvider({
getPageObjects,
getService,
}: FtrProviderContext) {
const testSubjects = getService('testSubjects');
const flyoutService = getService('flyout');
const pageObjects = getPageObjects(['common']);
Expand Down Expand Up @@ -156,6 +158,7 @@ export function ObservabilityAlertsProvider({ getPageObjects, getService }: FtrP
await actionsOverflowButton.click();
};

// Workflow status
const setWorkflowStatusForRow = async (rowIndex: number, workflowStatus: WorkflowStatus) => {
await openActionsMenuForRow(rowIndex);

Expand Down
21 changes: 21 additions & 0 deletions x-pack/test/functional/services/observability/alerts/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/*
* 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 { ObservabilityAlertsPaginationProvider } from './pagination';
import { ObservabilityAlertsCommonProvider } from './common';

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

export function ObservabilityAlertsProvider(context: FtrProviderContext) {
const common = ObservabilityAlertsCommonProvider(context);
const pagination = ObservabilityAlertsPaginationProvider(context);

return {
common,
pagination,
};
}
109 changes: 109 additions & 0 deletions x-pack/test/functional/services/observability/alerts/pagination.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* 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 { FtrProviderContext } from '../../../ftr_provider_context';

const ALERTS_ROWS_PER_PAGE_SELECTOR = 'tablePaginationPopoverButton';
mgiota marked this conversation as resolved.
Show resolved Hide resolved
const ALERTS_PAGINATION_BUTTON_PREVIOUS = 'pagination-button-previous';
const ALERTS_PAGINATION_BUTTON_NEXT = 'pagination-button-next';
const ALERTS_PAGINATION_TEN_ROWS = 'tablePagination-10-rows';
const ALERTS_PAGINATION_TWENTY_FIVE_ROWS = 'tablePagination-25-rows';
const ALERTS_PAGINATION_FIFTY_ROWS = 'tablePagination-50-rows';
const ALERTS_PAGINATION_BUTTON_ONE = 'pagination-button-0';
const ALERTS_PAGINATION_BUTTON_TWO = 'pagination-button-1';

export function ObservabilityAlertsPaginationProvider({ getService }: FtrProviderContext) {
const testSubjects = getService('testSubjects');

const getPageSizeSelector = async () => {
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit: These properties seem to be sorted by which page element they are using, but it's still a flat list. Would it be helpful to group related properties in an object?

I'm thinking something like:

const pageSizeSelector = {
    get: async () => { ...
    getOrFail: async () => { ...
    getOrMissing: async () => { ...
}

That would make it faster to scan which properties exist for a particular page element. A middle ground between having many small providers while still helping with some readability.
Not sure what would be done for those that only have function.

return await testSubjects.find(ALERTS_ROWS_PER_PAGE_SELECTOR);
};

const getPageSizeSelectorOrFail = async () => {
return await testSubjects.existOrFail(ALERTS_ROWS_PER_PAGE_SELECTOR);
};

const missingPageSizeSelectorOrFail = async () => {
return await testSubjects.missingOrFail(ALERTS_ROWS_PER_PAGE_SELECTOR);
};

const getTenRowsPageSelector = async () => {
return await testSubjects.find(ALERTS_PAGINATION_TEN_ROWS);
};

const getTwentyFiveRowsPageSelector = async () => {
return await testSubjects.find(ALERTS_PAGINATION_TWENTY_FIVE_ROWS);
};

const getFiftyRowsPageSelector = async () => {
return await testSubjects.find(ALERTS_PAGINATION_FIFTY_ROWS);
};

const getPrevPageButton = async () => {
return await testSubjects.find(ALERTS_PAGINATION_BUTTON_PREVIOUS);
};

const getPrevPageButtonOrFail = async () => {
return await testSubjects.existOrFail(ALERTS_PAGINATION_BUTTON_PREVIOUS);
};

const missingPrevPageButtonOrFail = async () => {
return await testSubjects.missingOrFail(ALERTS_ROWS_PER_PAGE_SELECTOR);
};

const getNextPageButton = async () => {
return await testSubjects.find(ALERTS_PAGINATION_BUTTON_NEXT, 20000);
};

const getNextPageButtonOrFail = async () => {
return await testSubjects.existOrFail(ALERTS_PAGINATION_BUTTON_NEXT);
};

const getPaginationButtonOne = async () => {
return await testSubjects.find(ALERTS_PAGINATION_BUTTON_ONE);
};

const getPaginationButtonTwo = async () => {
return await testSubjects.find(ALERTS_PAGINATION_BUTTON_TWO);
};

const goToNextPage = async () => {
return await (await getNextPageButton()).click();
};

const goToPrevPage = async () => {
return await (await getPrevPageButton()).click();
};

const goToFirstPage = async () => {
await (await getPaginationButtonOne()).click();
};

const getPrevButtonDisabledValue = async () => {
return await (await getPrevPageButton()).getAttribute('disabled');
};

return {
getPageSizeSelector,
getPageSizeSelectorOrFail,
missingPageSizeSelectorOrFail,
getTenRowsPageSelector,
getTwentyFiveRowsPageSelector,
getFiftyRowsPageSelector,
getPrevPageButton,
getPrevPageButtonOrFail,
missingPrevPageButtonOrFail,
getNextPageButton,
getNextPageButtonOrFail,
getPaginationButtonOne,
getPaginationButtonTwo,
goToNextPage,
goToPrevPage,
goToFirstPage,
getPrevButtonDisabledValue,
};
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {

before(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/observability/alerts');
await observability.alerts.navigateToTimeWithData();
await observability.alerts.common.navigateToTimeWithData();
});

after(async () => {
Expand All @@ -40,96 +40,97 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {

describe('Alerts table', () => {
it('Renders the table', async () => {
await observability.alerts.getTableOrFail();
await observability.alerts.common.getTableOrFail();
});

it('Renders the correct number of cells', async () => {
await retry.try(async () => {
const cells = await observability.alerts.getTableCells();
const cells = await observability.alerts.common.getTableCells();
expect(cells.length).to.be(TOTAL_ALERTS_CELL_COUNT);
});
});

describe('Filtering', () => {
afterEach(async () => {
await observability.alerts.clearQueryBar();
await observability.alerts.common.clearQueryBar();
});

after(async () => {
// NOTE: We do this as the query bar takes the place of the datepicker when it is in focus, so we'll reset
// back to default.
await observability.alerts.submitQuery('');
await observability.alerts.common.submitQuery('');
});

it('Autocompletion works', async () => {
await observability.alerts.typeInQueryBar('kibana.alert.s');
await observability.alerts.common.typeInQueryBar('kibana.alert.s');
await testSubjects.existOrFail('autocompleteSuggestion-field-kibana.alert.start-');
await testSubjects.existOrFail('autocompleteSuggestion-field-kibana.alert.status-');
});

it('Applies filters correctly', async () => {
await observability.alerts.submitQuery('kibana.alert.status: recovered');
await observability.alerts.common.submitQuery('kibana.alert.status: recovered');
await retry.try(async () => {
const cells = await observability.alerts.getTableCells();
const cells = await observability.alerts.common.getTableCells();
expect(cells.length).to.be(RECOVERED_ALERTS_CELL_COUNT);
});
});

it('Displays a no data state when filters produce zero results', async () => {
await observability.alerts.submitQuery('kibana.alert.consumer: uptime');
await observability.alerts.getNoDataStateOrFail();
await observability.alerts.common.submitQuery('kibana.alert.consumer: uptime');
await observability.alerts.common.getNoDataStateOrFail();
});
});

describe('Date selection', () => {
after(async () => {
await observability.alerts.navigateToTimeWithData();
await observability.alerts.common.navigateToTimeWithData();
});

it('Correctly applies date picker selections', async () => {
await retry.try(async () => {
await (await testSubjects.find('superDatePickerToggleQuickMenuButton')).click();
// We shouldn't expect any data for the last 15 minutes
await (await testSubjects.find('superDatePickerCommonlyUsed_Last_15 minutes')).click();
await observability.alerts.getNoDataStateOrFail();
await observability.alerts.common.getNoDataStateOrFail();
await pageObjects.common.waitUntilUrlIncludes('rangeFrom=now-15m&rangeTo=now');
});
});
});

describe('Flyout', () => {
it('Can be opened', async () => {
await observability.alerts.openAlertsFlyout();
await observability.alerts.getAlertsFlyoutOrFail();
await observability.alerts.common.openAlertsFlyout();
await observability.alerts.common.getAlertsFlyoutOrFail();
});

it('Can be closed', async () => {
await observability.alerts.closeAlertsFlyout();
await observability.alerts.common.closeAlertsFlyout();
await testSubjects.missingOrFail('alertsFlyout');
});

describe('When open', async () => {
before(async () => {
await observability.alerts.openAlertsFlyout();
await observability.alerts.common.openAlertsFlyout();
});

after(async () => {
await observability.alerts.closeAlertsFlyout();
await observability.alerts.common.closeAlertsFlyout();
});

it('Displays the correct title', async () => {
await retry.try(async () => {
const titleText = await (
await observability.alerts.getAlertsFlyoutTitle()
await observability.alerts.common.getAlertsFlyoutTitle()
).getVisibleText();
expect(titleText).to.contain('Log threshold');
});
});

it('Displays the correct content', async () => {
const flyoutTitles = await observability.alerts.getAlertsFlyoutDescriptionListTitles();
const flyoutTitles =
await observability.alerts.common.getAlertsFlyoutDescriptionListTitles();
const flyoutDescriptions =
await observability.alerts.getAlertsFlyoutDescriptionListDescriptions();
await observability.alerts.common.getAlertsFlyoutDescriptionListDescriptions();

const expectedTitles = [
'Status',
Expand Down Expand Up @@ -158,43 +159,43 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
});

it('Displays a View in App button', async () => {
await observability.alerts.getAlertsFlyoutViewInAppButtonOrFail();
await observability.alerts.common.getAlertsFlyoutViewInAppButtonOrFail();
});
});
});

describe('Cell actions', () => {
beforeEach(async () => {
await retry.try(async () => {
const cells = await observability.alerts.getTableCells();
const cells = await observability.alerts.common.getTableCells();
const alertStatusCell = cells[2];
await alertStatusCell.moveMouseTo();
await retry.waitFor(
'cell actions visible',
async () => await observability.alerts.copyToClipboardButtonExists()
async () => await observability.alerts.common.copyToClipboardButtonExists()
);
});
});

afterEach(async () => {
await observability.alerts.clearQueryBar();
await observability.alerts.common.clearQueryBar();
});

it('Copy button works', async () => {
// NOTE: We don't have access to the clipboard in a headless environment,
// so we'll just check the button is clickable in the functional tests.
await (await observability.alerts.getCopyToClipboardButton()).click();
await (await observability.alerts.common.getCopyToClipboardButton()).click();
});

it('Filter for value works', async () => {
await (await observability.alerts.getFilterForValueButton()).click();
await (await observability.alerts.common.getFilterForValueButton()).click();
const queryBarValue = await (
await observability.alerts.getQueryBar()
await observability.alerts.common.getQueryBar()
).getAttribute('value');
expect(queryBarValue).to.be('kibana.alert.status: "active"');
// Wait for request
await retry.try(async () => {
const cells = await observability.alerts.getTableCells();
const cells = await observability.alerts.common.getTableCells();
expect(cells.length).to.be(ACTIVE_ALERTS_CELL_COUNT);
});
});
Expand Down
Loading