From b7ab54b3b96e1c5782c6f50fc6ee8b5005cd8f7e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Thu, 9 Sep 2021 20:35:35 +0200 Subject: [PATCH 1/4] Test the workflow status actions in the row menus --- .../pages/alerts/alerts_table_t_grid.tsx | 1 + .../alerts/workflow_status_filter.test.tsx | 2 +- .../pages/alerts/workflow_status_filter.tsx | 6 +- .../services/observability/alerts.ts | 79 +++++++++++++--- .../observability/alerts/workflow_status.ts | 90 +++++++++++++++++++ .../apps/observability/index.ts | 1 + 6 files changed, 164 insertions(+), 15 deletions(-) create mode 100644 x-pack/test/observability_functional/apps/observability/alerts/workflow_status.ts diff --git a/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx b/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx index bca8c8095511e..9b6e9e249346e 100644 --- a/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/alerts_table_t_grid.tsx @@ -277,6 +277,7 @@ function ObservabilityActions({ iconType="boxesHorizontal" aria-label="More" onClick={() => toggleActionsPopover(eventId)} + data-test-subj="alerts-table-row-action-more" /> } isOpen={openActionsPopoverId === eventId} diff --git a/x-pack/plugins/observability/public/pages/alerts/workflow_status_filter.test.tsx b/x-pack/plugins/observability/public/pages/alerts/workflow_status_filter.test.tsx index cc16f1c5a44a1..f7441742ff387 100644 --- a/x-pack/plugins/observability/public/pages/alerts/workflow_status_filter.test.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/workflow_status_filter.test.tsx @@ -28,7 +28,7 @@ describe('StatusFilter', () => { const props = { onChange, status }; const { getByTestId } = render(); - const button = getByTestId(`WorkflowStatusFilter ${status} button`); + const button = getByTestId(`workflow-status-filter-${status}-button`); const input = button.querySelector('input') as Element; Simulate.change(input); diff --git a/x-pack/plugins/observability/public/pages/alerts/workflow_status_filter.tsx b/x-pack/plugins/observability/public/pages/alerts/workflow_status_filter.tsx index 475ba17a9d2f5..20073e9937b4f 100644 --- a/x-pack/plugins/observability/public/pages/alerts/workflow_status_filter.tsx +++ b/x-pack/plugins/observability/public/pages/alerts/workflow_status_filter.tsx @@ -21,7 +21,7 @@ const options: Array = label: i18n.translate('xpack.observability.alerts.workflowStatusFilter.openButtonLabel', { defaultMessage: 'Open', }), - 'data-test-subj': 'WorkflowStatusFilter open button', + 'data-test-subj': 'workflow-status-filter-open-button', }, { id: 'acknowledged', @@ -31,14 +31,14 @@ const options: Array = defaultMessage: 'Acknowledged', } ), - 'data-test-subj': 'WorkflowStatusFilter acknowledged button', + 'data-test-subj': 'workflow-status-filter-acknowledged-button', }, { id: 'closed', label: i18n.translate('xpack.observability.alerts.workflowStatusFilter.closedButtonLabel', { defaultMessage: 'Closed', }), - 'data-test-subj': 'WorkflowStatusFilter closed button', + 'data-test-subj': 'workflow-status-filter-closed-button', }, ]; diff --git a/x-pack/test/functional/services/observability/alerts.ts b/x-pack/test/functional/services/observability/alerts.ts index ba7f952b30c64..a8acfce4f2000 100644 --- a/x-pack/test/functional/services/observability/alerts.ts +++ b/x-pack/test/functional/services/observability/alerts.ts @@ -6,6 +6,7 @@ */ import querystring from 'querystring'; +import { chunk } from 'lodash'; import { FtrProviderContext } from '../../ftr_provider_context'; import { WebElementWrapper } from '../../../../../test/functional/services/lib/web_element_wrapper'; @@ -17,11 +18,14 @@ const DATE_WITH_DATA = { const ALERTS_FLYOUT_SELECTOR = 'alertsFlyout'; +const ACTION_COLUMN_INDEX = 1; + export function ObservabilityAlertsProvider({ getPageObjects, getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const flyoutService = getService('flyout'); const pageObjects = getPageObjects(['common']); const retry = getService('retry'); + const toasts = getService('toasts'); const navigateToTimeWithData = async () => { return await pageObjects.common.navigateToUrlWithBrowserHistory( @@ -31,11 +35,27 @@ export function ObservabilityAlertsProvider({ getPageObjects, getService }: FtrP ); }; + const getTableColumnHeaders = async () => { + const table = await testSubjects.find('events-viewer-panel'); + const tableHeaderRow = await testSubjects.findDescendant('dataGridHeader', table); + const columnHeaders = await tableHeaderRow.findAllByXpath('./div'); + return columnHeaders; + }; + const getTableCells = async () => { // NOTE: This isn't ideal, but EuiDataGrid doesn't really have the concept of "rows" return await testSubjects.findAll('dataGridRowCell'); }; + const getTableCellsInRows = async () => { + const columnHeaders = await getTableColumnHeaders(); + if (columnHeaders.length <= 0) { + return []; + } + const cells = await getTableCells(); + return chunk(cells, columnHeaders.length); + }; + const getTableOrFail = async () => { return await testSubjects.existOrFail('events-viewer-panel'); }; @@ -109,21 +129,58 @@ export function ObservabilityAlertsProvider({ getPageObjects, getService }: FtrP return await testSubjects.findAllDescendant('alertsFlyoutDescriptionListDescription', flyout); }; + const openRowActionsOverflowMenu = async (rowIndex: number) => { + const rows = await getTableCellsInRows(); + const actionsOverflowButton = await testSubjects.findDescendant( + 'alerts-table-row-action-more', + rows[rowIndex][ACTION_COLUMN_INDEX] + ); + await actionsOverflowButton.click(); + }; + + const setSingleAlertWorkflowStatus = async ( + rowIndex: number, + workflowStatus: 'open' | 'acknowledged' | 'closed' + ) => { + await openRowActionsOverflowMenu(rowIndex); + + if (workflowStatus === 'closed') { + await testSubjects.click('close-alert-status'); + } else { + await testSubjects.click(`${workflowStatus}-alert-status`); + } + + // wait for a confirmation toast (the css index is 1-based) + await toasts.getToastElement(1); + await toasts.dismissAllToasts(); + }; + + const setWorkflowStatusFilter = async (workflowStatus: 'open' | 'acknowledged' | 'closed') => { + const buttonGroupButton = await testSubjects.find( + `workflow-status-filter-${workflowStatus}-button` + ); + await buttonGroupButton.click(); + }; + return { clearQueryBar, - typeInQueryBar, - submitQuery, - getTableCells, - getTableOrFail, - getNoDataStateOrFail, - openAlertsFlyout, - getAlertsFlyout, - getAlertsFlyoutTitle, closeAlertsFlyout, - navigateToTimeWithData, + getAlertsFlyout, + getAlertsFlyoutDescriptionListDescriptions, + getAlertsFlyoutDescriptionListTitles, getAlertsFlyoutOrFail, + getAlertsFlyoutTitle, getAlertsFlyoutViewInAppButtonOrFail, - getAlertsFlyoutDescriptionListTitles, - getAlertsFlyoutDescriptionListDescriptions, + getNoDataStateOrFail, + getTableCells, + getTableCellsInRows, + getTableColumnHeaders, + getTableOrFail, + navigateToTimeWithData, + openAlertsFlyout, + setSingleAlertWorkflowStatus, + setWorkflowStatusFilter, + submitQuery, + typeInQueryBar, }; } diff --git a/x-pack/test/observability_functional/apps/observability/alerts/workflow_status.ts b/x-pack/test/observability_functional/apps/observability/alerts/workflow_status.ts new file mode 100644 index 0000000000000..75314f8d9b23e --- /dev/null +++ b/x-pack/test/observability_functional/apps/observability/alerts/workflow_status.ts @@ -0,0 +1,90 @@ +/* + * 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 expect from '@kbn/expect'; +import { FtrProviderContext } from '../../../ftr_provider_context'; + +export default ({ getService }: FtrProviderContext) => { + const esArchiver = getService('esArchiver'); + + describe('workflow status', function () { + this.tags('includeFirefox'); + + const observability = getService('observability'); + const retry = getService('retry'); + + before(async () => { + await esArchiver.load('x-pack/test/functional/es_archives/observability/alerts'); + await observability.alerts.navigateToTimeWithData(); + }); + + after(async () => { + await esArchiver.unload('x-pack/test/functional/es_archives/observability/alerts'); + }); + + it('is filtered for "open" by default', async () => { + await retry.try(async () => { + const tableRows = await observability.alerts.getTableCellsInRows(); + expect(tableRows.length).to.be(12); + }); + }); + + it('can be set to "acknowledged" using the row menu', async () => { + await observability.alerts.setSingleAlertWorkflowStatus(0, 'acknowledged'); + + await retry.try(async () => { + const tableRows = await observability.alerts.getTableCellsInRows(); + expect(tableRows.length).to.be(11); + }); + }); + + it('can be filtered for "acknowledged" using the filter button', async () => { + await observability.alerts.setWorkflowStatusFilter('acknowledged'); + + await retry.try(async () => { + const tableRows = await observability.alerts.getTableCellsInRows(); + expect(tableRows.length).to.be(3); + }); + }); + + it('can be set to "closed" using the row menu', async () => { + await observability.alerts.setSingleAlertWorkflowStatus(0, 'closed'); + + await retry.try(async () => { + const tableRows = await observability.alerts.getTableCellsInRows(); + expect(tableRows.length).to.be(2); + }); + }); + + it('can be filtered for "closed" using the filter button', async () => { + await observability.alerts.setWorkflowStatusFilter('closed'); + + await retry.try(async () => { + const tableRows = await observability.alerts.getTableCellsInRows(); + expect(tableRows.length).to.be(4); + }); + }); + + it('can be set to "open" using the row menu', async () => { + await observability.alerts.setSingleAlertWorkflowStatus(0, 'open'); + + await retry.try(async () => { + const tableRows = await observability.alerts.getTableCellsInRows(); + expect(tableRows.length).to.be(3); + }); + }); + + it('can be filtered for "open" using the filter button', async () => { + await observability.alerts.setWorkflowStatusFilter('open'); + + await retry.try(async () => { + const tableRows = await observability.alerts.getTableCellsInRows(); + expect(tableRows.length).to.be(12); + }); + }); + }); +}; diff --git a/x-pack/test/observability_functional/apps/observability/index.ts b/x-pack/test/observability_functional/apps/observability/index.ts index fbb401a67b55d..b823e1ee0869b 100644 --- a/x-pack/test/observability_functional/apps/observability/index.ts +++ b/x-pack/test/observability_functional/apps/observability/index.ts @@ -12,5 +12,6 @@ export default function ({ loadTestFile }: FtrProviderContext) { this.tags('ciGroup6'); loadTestFile(require.resolve('./feature_controls')); loadTestFile(require.resolve('./alerts')); + loadTestFile(require.resolve('./alerts/workflow_status')); }); } From 426849f878c844617e7d9338ff611ab73628068e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Thu, 16 Sep 2021 13:04:20 +0200 Subject: [PATCH 2/4] Extract table container selector into a constant --- x-pack/test/functional/services/observability/alerts.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/x-pack/test/functional/services/observability/alerts.ts b/x-pack/test/functional/services/observability/alerts.ts index a8acfce4f2000..895ed412ef857 100644 --- a/x-pack/test/functional/services/observability/alerts.ts +++ b/x-pack/test/functional/services/observability/alerts.ts @@ -17,6 +17,7 @@ const DATE_WITH_DATA = { }; const ALERTS_FLYOUT_SELECTOR = 'alertsFlyout'; +const ALERTS_TABLE_CONTAINER_SELECTOR = 'events-viewer-panel'; const ACTION_COLUMN_INDEX = 1; @@ -36,7 +37,7 @@ export function ObservabilityAlertsProvider({ getPageObjects, getService }: FtrP }; const getTableColumnHeaders = async () => { - const table = await testSubjects.find('events-viewer-panel'); + const table = await testSubjects.find(ALERTS_TABLE_CONTAINER_SELECTOR); const tableHeaderRow = await testSubjects.findDescendant('dataGridHeader', table); const columnHeaders = await tableHeaderRow.findAllByXpath('./div'); return columnHeaders; @@ -57,7 +58,7 @@ export function ObservabilityAlertsProvider({ getPageObjects, getService }: FtrP }; const getTableOrFail = async () => { - return await testSubjects.existOrFail('events-viewer-panel'); + return await testSubjects.existOrFail(ALERTS_TABLE_CONTAINER_SELECTOR); }; const getNoDataStateOrFail = async () => { From 8b5fa4375550c82f759ec082aa5935a5e61caaae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Thu, 16 Sep 2021 13:39:02 +0200 Subject: [PATCH 3/4] Improve test case names --- .../apps/observability/alerts/workflow_status.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/x-pack/test/observability_functional/apps/observability/alerts/workflow_status.ts b/x-pack/test/observability_functional/apps/observability/alerts/workflow_status.ts index 75314f8d9b23e..613e485c8085f 100644 --- a/x-pack/test/observability_functional/apps/observability/alerts/workflow_status.ts +++ b/x-pack/test/observability_functional/apps/observability/alerts/workflow_status.ts @@ -11,7 +11,7 @@ import { FtrProviderContext } from '../../../ftr_provider_context'; export default ({ getService }: FtrProviderContext) => { const esArchiver = getService('esArchiver'); - describe('workflow status', function () { + describe('alert workflow status', function () { this.tags('includeFirefox'); const observability = getService('observability'); @@ -26,7 +26,7 @@ export default ({ getService }: FtrProviderContext) => { await esArchiver.unload('x-pack/test/functional/es_archives/observability/alerts'); }); - it('is filtered for "open" by default', async () => { + it('is filtered to only show "open" alerts by default', async () => { await retry.try(async () => { const tableRows = await observability.alerts.getTableCellsInRows(); expect(tableRows.length).to.be(12); @@ -42,7 +42,7 @@ export default ({ getService }: FtrProviderContext) => { }); }); - it('can be filtered for "acknowledged" using the filter button', async () => { + it('can be filtered to only show "acknowledged" alerts using the filter button', async () => { await observability.alerts.setWorkflowStatusFilter('acknowledged'); await retry.try(async () => { @@ -60,7 +60,7 @@ export default ({ getService }: FtrProviderContext) => { }); }); - it('can be filtered for "closed" using the filter button', async () => { + it('can be filtered to only show "closed" alerts using the filter button', async () => { await observability.alerts.setWorkflowStatusFilter('closed'); await retry.try(async () => { @@ -78,7 +78,7 @@ export default ({ getService }: FtrProviderContext) => { }); }); - it('can be filtered for "open" using the filter button', async () => { + it('can be filtered to only show "open" alerts using the filter button', async () => { await observability.alerts.setWorkflowStatusFilter('open'); await retry.try(async () => { From ad77056006a153f819eabc44bd4592a0ec118075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Felix=20St=C3=BCrmer?= Date: Thu, 16 Sep 2021 13:43:10 +0200 Subject: [PATCH 4/4] Improve naming of functions and types --- .../functional/services/observability/alerts.ts | 15 +++++++-------- .../apps/observability/alerts/workflow_status.ts | 6 +++--- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/x-pack/test/functional/services/observability/alerts.ts b/x-pack/test/functional/services/observability/alerts.ts index 895ed412ef857..8926d734d7313 100644 --- a/x-pack/test/functional/services/observability/alerts.ts +++ b/x-pack/test/functional/services/observability/alerts.ts @@ -21,6 +21,8 @@ const ALERTS_TABLE_CONTAINER_SELECTOR = 'events-viewer-panel'; const ACTION_COLUMN_INDEX = 1; +type WorkflowStatus = 'open' | 'acknowledged' | 'closed'; + export function ObservabilityAlertsProvider({ getPageObjects, getService }: FtrProviderContext) { const testSubjects = getService('testSubjects'); const flyoutService = getService('flyout'); @@ -130,7 +132,7 @@ export function ObservabilityAlertsProvider({ getPageObjects, getService }: FtrP return await testSubjects.findAllDescendant('alertsFlyoutDescriptionListDescription', flyout); }; - const openRowActionsOverflowMenu = async (rowIndex: number) => { + const openActionsMenuForRow = async (rowIndex: number) => { const rows = await getTableCellsInRows(); const actionsOverflowButton = await testSubjects.findDescendant( 'alerts-table-row-action-more', @@ -139,11 +141,8 @@ export function ObservabilityAlertsProvider({ getPageObjects, getService }: FtrP await actionsOverflowButton.click(); }; - const setSingleAlertWorkflowStatus = async ( - rowIndex: number, - workflowStatus: 'open' | 'acknowledged' | 'closed' - ) => { - await openRowActionsOverflowMenu(rowIndex); + const setWorkflowStatusForRow = async (rowIndex: number, workflowStatus: WorkflowStatus) => { + await openActionsMenuForRow(rowIndex); if (workflowStatus === 'closed') { await testSubjects.click('close-alert-status'); @@ -156,7 +155,7 @@ export function ObservabilityAlertsProvider({ getPageObjects, getService }: FtrP await toasts.dismissAllToasts(); }; - const setWorkflowStatusFilter = async (workflowStatus: 'open' | 'acknowledged' | 'closed') => { + const setWorkflowStatusFilter = async (workflowStatus: WorkflowStatus) => { const buttonGroupButton = await testSubjects.find( `workflow-status-filter-${workflowStatus}-button` ); @@ -179,7 +178,7 @@ export function ObservabilityAlertsProvider({ getPageObjects, getService }: FtrP getTableOrFail, navigateToTimeWithData, openAlertsFlyout, - setSingleAlertWorkflowStatus, + setWorkflowStatusForRow, setWorkflowStatusFilter, submitQuery, typeInQueryBar, diff --git a/x-pack/test/observability_functional/apps/observability/alerts/workflow_status.ts b/x-pack/test/observability_functional/apps/observability/alerts/workflow_status.ts index 613e485c8085f..d491e239c6035 100644 --- a/x-pack/test/observability_functional/apps/observability/alerts/workflow_status.ts +++ b/x-pack/test/observability_functional/apps/observability/alerts/workflow_status.ts @@ -34,7 +34,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('can be set to "acknowledged" using the row menu', async () => { - await observability.alerts.setSingleAlertWorkflowStatus(0, 'acknowledged'); + await observability.alerts.setWorkflowStatusForRow(0, 'acknowledged'); await retry.try(async () => { const tableRows = await observability.alerts.getTableCellsInRows(); @@ -52,7 +52,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('can be set to "closed" using the row menu', async () => { - await observability.alerts.setSingleAlertWorkflowStatus(0, 'closed'); + await observability.alerts.setWorkflowStatusForRow(0, 'closed'); await retry.try(async () => { const tableRows = await observability.alerts.getTableCellsInRows(); @@ -70,7 +70,7 @@ export default ({ getService }: FtrProviderContext) => { }); it('can be set to "open" using the row menu', async () => { - await observability.alerts.setSingleAlertWorkflowStatus(0, 'open'); + await observability.alerts.setWorkflowStatusForRow(0, 'open'); await retry.try(async () => { const tableRows = await observability.alerts.getTableCellsInRows();