mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[8.8] [ResponseOps][Maintenance Window] Add and improve E2E tests for the maintenance window table (#156611) (#156853)
# Backport This will backport the following commits from `main` to `8.8`: - [[ResponseOps][Maintenance Window] Add and improve E2E tests for the maintenance window table (#156611)](https://github.com/elastic/kibana/pull/156611) <!--- Backport version: 8.9.7 --> ### Questions ? Please refer to the [Backport tool documentation](https://github.com/sqren/backport) <!--BACKPORT [{"author":{"name":"Alexi Doak","email":"109488926+doakalexi@users.noreply.github.com"},"sourceCommit":{"committedDate":"2023-05-05T12:47:40Z","message":"[ResponseOps][Maintenance Window] Add and improve E2E tests for the maintenance window table (#156611)\n\n## Summary\r\n\r\nAdds functional tests for the maintenance windows table.\r\n\r\nShould test:\r\n- Cancel a maintenance window\r\n- Archiving/Unarchiving a maintenance window\r\n- Cancelling and archiving a maintenance window\r\n- Searching/filtering\r\n\r\n\r\nIssue linked - https://github.com/elastic/kibana/issues/155902","sha":"3fef5e5cda748c11786cfe66f69644b56841d656","branchLabelMapping":{"^v8.9.0$":"main","^v(\\d+).(\\d+).\\d+$":"$1.$2"}},"sourcePullRequest":{"labels":["release_note:skip","Team:ResponseOps","v8.8.0","v8.9.0"],"number":156611,"url":"https://github.com/elastic/kibana/pull/156611","mergeCommit":{"message":"[ResponseOps][Maintenance Window] Add and improve E2E tests for the maintenance window table (#156611)\n\n## Summary\r\n\r\nAdds functional tests for the maintenance windows table.\r\n\r\nShould test:\r\n- Cancel a maintenance window\r\n- Archiving/Unarchiving a maintenance window\r\n- Cancelling and archiving a maintenance window\r\n- Searching/filtering\r\n\r\n\r\nIssue linked - https://github.com/elastic/kibana/issues/155902","sha":"3fef5e5cda748c11786cfe66f69644b56841d656"}},"sourceBranch":"main","suggestedTargetBranches":["8.8"],"targetPullRequestStates":[{"branch":"8.8","label":"v8.8.0","labelRegex":"^v(\\d+).(\\d+).\\d+$","isSourceBranch":false,"state":"NOT_CREATED"},{"branch":"main","label":"v8.9.0","labelRegex":"^v8.9.0$","isSourceBranch":true,"state":"MERGED","url":"https://github.com/elastic/kibana/pull/156611","number":156611,"mergeCommit":{"message":"[ResponseOps][Maintenance Window] Add and improve E2E tests for the maintenance window table (#156611)\n\n## Summary\r\n\r\nAdds functional tests for the maintenance windows table.\r\n\r\nShould test:\r\n- Cancel a maintenance window\r\n- Archiving/Unarchiving a maintenance window\r\n- Cancelling and archiving a maintenance window\r\n- Searching/filtering\r\n\r\n\r\nIssue linked - https://github.com/elastic/kibana/issues/155902","sha":"3fef5e5cda748c11786cfe66f69644b56841d656"}}]}] BACKPORT--> Co-authored-by: Alexi Doak <109488926+doakalexi@users.noreply.github.com>
This commit is contained in:
parent
b7f0eadd86
commit
772c00c87e
11 changed files with 345 additions and 6 deletions
|
@ -45,6 +45,7 @@ const COLUMNS: Array<EuiBasicTableColumn<MaintenanceWindowFindResponse>> = [
|
|||
{
|
||||
field: 'status',
|
||||
name: i18n.TABLE_STATUS,
|
||||
'data-test-subj': 'maintenance-windows-column-status',
|
||||
render: (status: MaintenanceWindowStatus) => {
|
||||
return (
|
||||
<EuiBadge color={STATUS_DISPLAY[status].color}>{STATUS_DISPLAY[status].label}</EuiBadge>
|
||||
|
@ -168,7 +169,7 @@ export const MaintenanceWindowsList = React.memo<MaintenanceWindowsListProps>(
|
|||
|
||||
return (
|
||||
<EuiInMemoryTable
|
||||
data-test-subj="mw-table"
|
||||
data-test-subj="maintenance-windows-table"
|
||||
css={tableCss}
|
||||
itemId="id"
|
||||
loading={loading || isLoadingFinish || isLoadingArchive || isLoadingFinishAndArchive}
|
||||
|
|
|
@ -217,6 +217,7 @@ export const TableActionsPopover: React.FC<TableActionsPopoverProps> = React.mem
|
|||
closePopover={closePopover}
|
||||
panelPaddingSize="none"
|
||||
anchorPosition="downCenter"
|
||||
data-test-subj="table-actions-popover"
|
||||
>
|
||||
<EuiContextMenuPanel items={items} />
|
||||
</EuiPopover>
|
||||
|
|
|
@ -78,7 +78,7 @@ describe('Maintenance windows page', () => {
|
|||
};
|
||||
appMockRenderer = createAppMockRenderer({ capabilities, license });
|
||||
const result = appMockRenderer.render(<MaintenanceWindowsPage />);
|
||||
expect(result.queryByTestId('mw-table')).toBeInTheDocument();
|
||||
expect(result.queryByTestId('maintenance-windows-table')).toBeInTheDocument();
|
||||
expect(appMockRenderer.mocked.setBadge).toBeCalledTimes(1);
|
||||
});
|
||||
});
|
||||
|
|
|
@ -45,6 +45,7 @@ import { SearchSessionsPageProvider } from './search_sessions_management_page';
|
|||
import { DetectionsPageObject } from '../../security_solution_ftr/page_objects/detections';
|
||||
import { BannersPageObject } from './banners_page';
|
||||
import { InfraHostsViewProvider } from './infra_hosts_view';
|
||||
import { MaintenanceWindowsPageProvider } from './maintenance_windows_page';
|
||||
|
||||
// just like services, PageObjects are defined as a map of
|
||||
// names to Providers. Merge in Kibana's or pick specific ones
|
||||
|
@ -88,4 +89,5 @@ export const pageObjects = {
|
|||
banners: BannersPageObject,
|
||||
detections: DetectionsPageObject,
|
||||
observability: ObservabilityPageProvider,
|
||||
maintenanceWindows: MaintenanceWindowsPageProvider,
|
||||
};
|
||||
|
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* 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 ENTER_KEY = '\uE007';
|
||||
|
||||
export function MaintenanceWindowsPageProvider({ getService }: FtrProviderContext) {
|
||||
const find = getService('find');
|
||||
|
||||
return {
|
||||
async getMaintenanceWindowsList() {
|
||||
const table = await find.byCssSelector('[data-test-subj="maintenance-windows-table"] table');
|
||||
const $ = await table.parseDomContent();
|
||||
return $.findTestSubjects('list-item')
|
||||
.toArray()
|
||||
.map((row) => {
|
||||
return {
|
||||
status: $(row)
|
||||
.findTestSubject('maintenance-windows-column-status')
|
||||
.find('.euiTableCellContent')
|
||||
.text(),
|
||||
};
|
||||
});
|
||||
},
|
||||
async searchMaintenanceWindows(searchText: string) {
|
||||
const searchBox = await find.byCssSelector(
|
||||
'.euiFieldSearch:not(.euiSelectableTemplateSitewide__search)'
|
||||
);
|
||||
await searchBox.click();
|
||||
await searchBox.clearValue();
|
||||
await searchBox.type(searchText);
|
||||
await searchBox.pressKeys(ENTER_KEY);
|
||||
await find.byCssSelector(
|
||||
'.euiBasicTable[data-test-subj="maintenance-windows-table"]:not(.euiBasicTable-loading)'
|
||||
);
|
||||
},
|
||||
};
|
||||
}
|
|
@ -16,5 +16,6 @@ export default ({ loadTestFile, getService }: FtrProviderContext) => {
|
|||
loadTestFile(require.resolve('./connectors'));
|
||||
loadTestFile(require.resolve('./logs_list'));
|
||||
loadTestFile(require.resolve('./rules_settings'));
|
||||
loadTestFile(require.resolve('./maintenance_windows'));
|
||||
});
|
||||
};
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
/*
|
||||
* 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';
|
||||
|
||||
export default ({ loadTestFile }: FtrProviderContext) => {
|
||||
describe('Maintenance Windows', function () {
|
||||
loadTestFile(require.resolve('./maintenance_windows_table'));
|
||||
});
|
||||
};
|
|
@ -0,0 +1,216 @@
|
|||
/*
|
||||
* 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';
|
||||
import { ObjectRemover } from '../../../lib/object_remover';
|
||||
import { generateUniqueKey } from '../../../lib/get_test_data';
|
||||
import { createMaintenanceWindow, createObjectRemover } from './utils';
|
||||
|
||||
export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
||||
const testSubjects = getService('testSubjects');
|
||||
const pageObjects = getPageObjects(['common', 'maintenanceWindows', 'header']);
|
||||
const retry = getService('retry');
|
||||
|
||||
let objectRemover: ObjectRemover;
|
||||
const browser = getService('browser');
|
||||
|
||||
describe('Maintenance windows table', function () {
|
||||
before(async () => {
|
||||
objectRemover = await createObjectRemover({ getService });
|
||||
});
|
||||
|
||||
beforeEach(async () => {
|
||||
await pageObjects.common.navigateToApp('maintenanceWindows');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
await objectRemover.removeAll();
|
||||
});
|
||||
|
||||
it('should should cancel a running maintenance window', async () => {
|
||||
const name = generateUniqueKey();
|
||||
const createdMaintenanceWindow = await createMaintenanceWindow({
|
||||
name,
|
||||
getService,
|
||||
});
|
||||
objectRemover.add(createdMaintenanceWindow.id, 'rules/maintenance_window', 'alerting', true);
|
||||
await browser.refresh();
|
||||
|
||||
await pageObjects.maintenanceWindows.searchMaintenanceWindows(name);
|
||||
|
||||
let list = await pageObjects.maintenanceWindows.getMaintenanceWindowsList();
|
||||
expect(list.length).to.eql(1);
|
||||
expect(list[0].status).to.eql('Running');
|
||||
|
||||
await testSubjects.click('table-actions-popover');
|
||||
await testSubjects.click('table-actions-cancel');
|
||||
await testSubjects.click('confirmModalConfirmButton');
|
||||
|
||||
await retry.try(async () => {
|
||||
const toastTitle = await pageObjects.common.closeToast();
|
||||
expect(toastTitle).to.eql(`Cancelled running maintenance window '${name}'`);
|
||||
});
|
||||
|
||||
await pageObjects.maintenanceWindows.searchMaintenanceWindows(name);
|
||||
|
||||
list = await pageObjects.maintenanceWindows.getMaintenanceWindowsList();
|
||||
expect(list.length).to.eql(1);
|
||||
expect(list[0].status).to.not.eql('Running');
|
||||
});
|
||||
|
||||
it('should should archive finished maintenance window', async () => {
|
||||
const name = generateUniqueKey();
|
||||
const createdMaintenanceWindow = await createMaintenanceWindow({
|
||||
name,
|
||||
startDate: new Date('05-01-2023'),
|
||||
notRecurring: true,
|
||||
getService,
|
||||
});
|
||||
objectRemover.add(createdMaintenanceWindow.id, 'rules/maintenance_window', 'alerting', true);
|
||||
await browser.refresh();
|
||||
|
||||
await pageObjects.maintenanceWindows.searchMaintenanceWindows(name);
|
||||
|
||||
let list = await pageObjects.maintenanceWindows.getMaintenanceWindowsList();
|
||||
expect(list.length).to.eql(1);
|
||||
expect(list[0].status).to.eql('Finished');
|
||||
|
||||
await testSubjects.click('table-actions-popover');
|
||||
await testSubjects.click('table-actions-archive');
|
||||
await testSubjects.click('confirmModalConfirmButton');
|
||||
|
||||
await retry.try(async () => {
|
||||
const toastTitle = await pageObjects.common.closeToast();
|
||||
expect(toastTitle).to.eql(`Archived maintenance window '${name}'`);
|
||||
});
|
||||
|
||||
await pageObjects.maintenanceWindows.searchMaintenanceWindows(name);
|
||||
|
||||
list = await pageObjects.maintenanceWindows.getMaintenanceWindowsList();
|
||||
expect(list.length).to.eql(1);
|
||||
expect(list[0].status).to.eql('Archived');
|
||||
});
|
||||
|
||||
it('should should cancel and archive a running maintenance window', async () => {
|
||||
const name = generateUniqueKey();
|
||||
const createdMaintenanceWindow = await createMaintenanceWindow({
|
||||
name,
|
||||
getService,
|
||||
});
|
||||
objectRemover.add(createdMaintenanceWindow.id, 'rules/maintenance_window', 'alerting', true);
|
||||
await browser.refresh();
|
||||
|
||||
await pageObjects.maintenanceWindows.searchMaintenanceWindows(name);
|
||||
|
||||
let list = await pageObjects.maintenanceWindows.getMaintenanceWindowsList();
|
||||
expect(list.length).to.eql(1);
|
||||
expect(list[0].status).to.eql('Running');
|
||||
|
||||
await testSubjects.click('table-actions-popover');
|
||||
await testSubjects.click('table-actions-cancel-and-archive');
|
||||
await testSubjects.click('confirmModalConfirmButton');
|
||||
|
||||
await retry.try(async () => {
|
||||
const toastTitle = await pageObjects.common.closeToast();
|
||||
expect(toastTitle).to.eql(`Cancelled and archived running maintenance window '${name}'`);
|
||||
});
|
||||
|
||||
await pageObjects.maintenanceWindows.searchMaintenanceWindows(name);
|
||||
|
||||
list = await pageObjects.maintenanceWindows.getMaintenanceWindowsList();
|
||||
expect(list.length).to.eql(1);
|
||||
expect(list[0].status).to.eql('Archived');
|
||||
});
|
||||
|
||||
it('should should unarchive a maintenance window', async () => {
|
||||
const name = generateUniqueKey();
|
||||
const createdMaintenanceWindow = await createMaintenanceWindow({
|
||||
name,
|
||||
startDate: new Date('05-01-2023'),
|
||||
notRecurring: true,
|
||||
getService,
|
||||
});
|
||||
objectRemover.add(createdMaintenanceWindow.id, 'rules/maintenance_window', 'alerting', true);
|
||||
await browser.refresh();
|
||||
|
||||
await pageObjects.maintenanceWindows.searchMaintenanceWindows(name);
|
||||
|
||||
let list = await pageObjects.maintenanceWindows.getMaintenanceWindowsList();
|
||||
expect(list.length).to.eql(1);
|
||||
expect(list[0].status).to.eql('Finished');
|
||||
|
||||
await testSubjects.click('table-actions-popover');
|
||||
await testSubjects.click('table-actions-archive');
|
||||
await testSubjects.click('confirmModalConfirmButton');
|
||||
|
||||
await retry.try(async () => {
|
||||
const toastTitle = await pageObjects.common.closeToast();
|
||||
expect(toastTitle).to.eql(`Archived maintenance window '${name}'`);
|
||||
});
|
||||
|
||||
await pageObjects.maintenanceWindows.searchMaintenanceWindows(name);
|
||||
|
||||
list = await pageObjects.maintenanceWindows.getMaintenanceWindowsList();
|
||||
expect(list.length).to.eql(1);
|
||||
expect(list[0].status).to.eql('Archived');
|
||||
|
||||
await testSubjects.click('table-actions-popover');
|
||||
await testSubjects.click('table-actions-unarchive');
|
||||
await testSubjects.click('confirmModalConfirmButton');
|
||||
|
||||
await retry.try(async () => {
|
||||
const toastTitle = await pageObjects.common.closeToast();
|
||||
expect(toastTitle).to.eql(`Unarchived maintenance window '${name}'`);
|
||||
});
|
||||
|
||||
await pageObjects.maintenanceWindows.searchMaintenanceWindows(name);
|
||||
|
||||
list = await pageObjects.maintenanceWindows.getMaintenanceWindowsList();
|
||||
expect(list.length).to.eql(1);
|
||||
expect(list[0].status).to.eql('Finished');
|
||||
});
|
||||
|
||||
it('should filter maintenance windows by the status', async () => {
|
||||
const running = await createMaintenanceWindow({
|
||||
name: 'running-mw',
|
||||
getService,
|
||||
});
|
||||
objectRemover.add(running.id, 'rules/maintenance_window', 'alerting', true);
|
||||
const finished = await createMaintenanceWindow({
|
||||
name: 'finished-mw',
|
||||
startDate: new Date('05-01-2023'),
|
||||
notRecurring: true,
|
||||
getService,
|
||||
});
|
||||
objectRemover.add(finished.id, 'rules/maintenance_window', 'alerting', true);
|
||||
|
||||
const date = new Date();
|
||||
date.setDate(date.getDate() + 1);
|
||||
const upcoming = await createMaintenanceWindow({
|
||||
name: 'upcoming-mw',
|
||||
startDate: date,
|
||||
getService,
|
||||
});
|
||||
objectRemover.add(upcoming.id, 'rules/maintenance_window', 'alerting', true);
|
||||
await browser.refresh();
|
||||
|
||||
await pageObjects.maintenanceWindows.searchMaintenanceWindows('mw');
|
||||
|
||||
const list = await pageObjects.maintenanceWindows.getMaintenanceWindowsList();
|
||||
expect(list.length).to.eql(3);
|
||||
|
||||
await testSubjects.click('status-filter-button');
|
||||
await testSubjects.click('status-filter-upcoming'); // select Upcoming status filter
|
||||
await retry.try(async () => {
|
||||
const upcomingList = await pageObjects.maintenanceWindows.getMaintenanceWindowsList();
|
||||
expect(upcomingList.length).to.equal(1);
|
||||
expect(upcomingList[0].status).to.equal('Upcoming');
|
||||
});
|
||||
});
|
||||
});
|
||||
};
|
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
* 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 { ObjectRemover } from '../../../lib/object_remover';
|
||||
import { FtrProviderContext } from '../../../ftr_provider_context';
|
||||
|
||||
export const createObjectRemover = async ({
|
||||
getService,
|
||||
}: {
|
||||
getService: FtrProviderContext['getService'];
|
||||
}) => {
|
||||
const supertest = getService('supertest');
|
||||
const objectRemover = new ObjectRemover(supertest);
|
||||
|
||||
return objectRemover;
|
||||
};
|
||||
|
||||
export const createMaintenanceWindow = async ({
|
||||
name,
|
||||
startDate,
|
||||
notRecurring,
|
||||
getService,
|
||||
}: {
|
||||
name: string;
|
||||
startDate?: Date;
|
||||
notRecurring?: boolean;
|
||||
getService: FtrProviderContext['getService'];
|
||||
}) => {
|
||||
const supertest = getService('supertest');
|
||||
const dtstart = startDate ? startDate : new Date();
|
||||
const createParams = {
|
||||
title: name,
|
||||
duration: 60 * 60 * 1000,
|
||||
r_rule: {
|
||||
dtstart: dtstart.toISOString(),
|
||||
tzid: 'UTC',
|
||||
...(notRecurring ? { freq: 1, count: 1 } : { freq: 2 }),
|
||||
},
|
||||
};
|
||||
|
||||
const { body } = await supertest
|
||||
.post(`/internal/alerting/rules/maintenance_window`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.send(createParams)
|
||||
.expect(200);
|
||||
|
||||
return body;
|
||||
};
|
|
@ -61,6 +61,9 @@ export default async function ({ readConfigFile }: FtrConfigProviderContext) {
|
|||
triggersActionsConnectors: {
|
||||
pathname: '/app/management/insightsAndAlerting/triggersActionsConnectors',
|
||||
},
|
||||
maintenanceWindows: {
|
||||
pathname: '/app/management/insightsAndAlerting/maintenanceWindows',
|
||||
},
|
||||
},
|
||||
esTestCluster: {
|
||||
...xpackFunctionalConfig.get('esTestCluster'),
|
||||
|
|
|
@ -9,6 +9,7 @@ interface ObjectToRemove {
|
|||
id: string;
|
||||
type: string;
|
||||
plugin: string;
|
||||
isInternal?: boolean;
|
||||
}
|
||||
|
||||
export class ObjectRemover {
|
||||
|
@ -19,15 +20,20 @@ export class ObjectRemover {
|
|||
this.supertest = supertest;
|
||||
}
|
||||
|
||||
add(id: ObjectToRemove['id'], type: ObjectToRemove['type'], plugin: ObjectToRemove['plugin']) {
|
||||
this.objectsToRemove.push({ id, type, plugin });
|
||||
add(
|
||||
id: ObjectToRemove['id'],
|
||||
type: ObjectToRemove['type'],
|
||||
plugin: ObjectToRemove['plugin'],
|
||||
isInternal?: ObjectToRemove['isInternal']
|
||||
) {
|
||||
this.objectsToRemove.push({ id, type, plugin, isInternal });
|
||||
}
|
||||
|
||||
async removeAll() {
|
||||
await Promise.all(
|
||||
this.objectsToRemove.map(({ id, type, plugin }) => {
|
||||
this.objectsToRemove.map(({ id, type, plugin, isInternal }) => {
|
||||
return this.supertest
|
||||
.delete(`/api/${plugin}/${type}/${id}`)
|
||||
.delete(`/${isInternal ? 'internal' : 'api'}/${plugin}/${type}/${id}`)
|
||||
.set('kbn-xsrf', 'foo')
|
||||
.expect(204);
|
||||
})
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue