mirror of
https://github.com/elastic/kibana.git
synced 2025-04-23 17:28:26 -04:00
[ResponseOps][MW] Allow users to delete MWs (#211399)
Resolve: https://github.com/elastic/kibana/issues/198559 Resolve: https://github.com/elastic/kibana/issues/205269 Here I used the existing DELETE /internal/alerting/rules/maintenance_window/{id} API to delete MWs from the UI. I added an action to the MW table so users can delete MWs. And show a delete confirmation modal when users delete a MW from the UI. ### Checklist - [x] Any text added follows [EUI's writing guidelines](https://elastic.github.io/eui/#/guidelines/writing), uses sentence case text and includes [i18n support](https://github.com/elastic/kibana/blob/main/src/platform/packages/shared/kbn-i18n/README.md) - [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 - [x] This was checked for breaking HTTP API changes, and any breaking changes have been approved by the breaking-change committee. The `release_note:breaking` label should be applied in these situations. - [x] [Flaky Test Runner](https://ci-stats.kibana.dev/trigger_flaky_test_runner/1) was used on any tests changed
This commit is contained in:
parent
63394e6bfd
commit
6ce22f4a33
9 changed files with 314 additions and 16 deletions
|
@ -0,0 +1,69 @@
|
|||
/*
|
||||
* 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 { waitFor, renderHook } from '@testing-library/react';
|
||||
|
||||
import { AppMockRenderer, createAppMockRenderer } from '../lib/test_utils';
|
||||
import { useDeleteMaintenanceWindow } from './use_delete_maintenance_window';
|
||||
|
||||
const mockAddDanger = jest.fn();
|
||||
const mockAddSuccess = jest.fn();
|
||||
|
||||
jest.mock('../utils/kibana_react', () => {
|
||||
const originalModule = jest.requireActual('../utils/kibana_react');
|
||||
return {
|
||||
...originalModule,
|
||||
useKibana: () => {
|
||||
const { services } = originalModule.useKibana();
|
||||
return {
|
||||
services: {
|
||||
...services,
|
||||
notifications: { toasts: { addSuccess: mockAddSuccess, addDanger: mockAddDanger } },
|
||||
},
|
||||
};
|
||||
},
|
||||
};
|
||||
});
|
||||
jest.mock('../services/maintenance_windows_api/delete', () => ({
|
||||
deleteMaintenanceWindow: jest.fn(),
|
||||
}));
|
||||
|
||||
const { deleteMaintenanceWindow } = jest.requireMock('../services/maintenance_windows_api/delete');
|
||||
|
||||
let appMockRenderer: AppMockRenderer;
|
||||
|
||||
describe('useDeleteMaintenanceWindow', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
|
||||
appMockRenderer = createAppMockRenderer();
|
||||
});
|
||||
|
||||
it('should call onSuccess if api succeeds', async () => {
|
||||
const { result } = renderHook(() => useDeleteMaintenanceWindow(), {
|
||||
wrapper: appMockRenderer.AppWrapper,
|
||||
});
|
||||
|
||||
result.current.mutate({ maintenanceWindowId: '123' });
|
||||
|
||||
await waitFor(() => expect(mockAddSuccess).toBeCalledWith('Deleted maintenance window'));
|
||||
});
|
||||
|
||||
it('should call onError if api fails', async () => {
|
||||
deleteMaintenanceWindow.mockRejectedValue('');
|
||||
|
||||
const { result } = renderHook(() => useDeleteMaintenanceWindow(), {
|
||||
wrapper: appMockRenderer.AppWrapper,
|
||||
});
|
||||
|
||||
result.current.mutate({ maintenanceWindowId: '123' });
|
||||
|
||||
await waitFor(() =>
|
||||
expect(mockAddDanger).toBeCalledWith('Failed to delete maintenance window.')
|
||||
);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* 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 { i18n } from '@kbn/i18n';
|
||||
import { useMutation } from '@tanstack/react-query';
|
||||
import { useKibana } from '../utils/kibana_react';
|
||||
import { deleteMaintenanceWindow } from '../services/maintenance_windows_api/delete';
|
||||
|
||||
export const useDeleteMaintenanceWindow = () => {
|
||||
const {
|
||||
http,
|
||||
notifications: { toasts },
|
||||
} = useKibana().services;
|
||||
|
||||
const mutationFn = ({ maintenanceWindowId }: { maintenanceWindowId: string }) => {
|
||||
return deleteMaintenanceWindow({ http, maintenanceWindowId });
|
||||
};
|
||||
|
||||
return useMutation(mutationFn, {
|
||||
onSuccess: () => {
|
||||
toasts.addSuccess(
|
||||
i18n.translate('xpack.alerting.maintenanceWindowsDeleteSuccess', {
|
||||
defaultMessage: 'Deleted maintenance window',
|
||||
})
|
||||
);
|
||||
},
|
||||
onError: () => {
|
||||
toasts.addDanger(
|
||||
i18n.translate('xpack.alerting.maintenanceWindowsDeleteFailure', {
|
||||
defaultMessage: 'Failed to delete maintenance window.',
|
||||
})
|
||||
);
|
||||
},
|
||||
});
|
||||
};
|
|
@ -32,6 +32,7 @@ import { TableActionsPopover, TableActionsPopoverProps } from './table_actions_p
|
|||
import { useFinishMaintenanceWindow } from '../../../hooks/use_finish_maintenance_window';
|
||||
import { useArchiveMaintenanceWindow } from '../../../hooks/use_archive_maintenance_window';
|
||||
import { useFinishAndArchiveMaintenanceWindow } from '../../../hooks/use_finish_and_archive_maintenance_window';
|
||||
import { useDeleteMaintenanceWindow } from '../../../hooks/use_delete_maintenance_window';
|
||||
|
||||
interface MaintenanceWindowsListProps {
|
||||
isLoading: boolean;
|
||||
|
@ -143,9 +144,24 @@ export const MaintenanceWindowsList = React.memo<MaintenanceWindowsListProps>(
|
|||
[finishAndArchiveMaintenanceWindow, refreshData]
|
||||
);
|
||||
|
||||
const { mutate: deleteMaintenanceWindow, isLoading: isLoadingDelete } =
|
||||
useDeleteMaintenanceWindow();
|
||||
|
||||
const onDelete = useCallback(
|
||||
(id: string) =>
|
||||
deleteMaintenanceWindow({ maintenanceWindowId: id }, { onSuccess: () => refreshData() }),
|
||||
[deleteMaintenanceWindow, refreshData]
|
||||
);
|
||||
|
||||
const isMutatingOrLoading = useMemo(() => {
|
||||
return isLoadingFinish || isLoadingArchive || isLoadingFinishAndArchive || isLoading;
|
||||
}, [isLoadingFinish, isLoadingArchive, isLoadingFinishAndArchive, isLoading]);
|
||||
return (
|
||||
isLoadingFinish ||
|
||||
isLoadingArchive ||
|
||||
isLoadingFinishAndArchive ||
|
||||
isLoadingDelete ||
|
||||
isLoading
|
||||
);
|
||||
}, [isLoadingFinish, isLoadingArchive, isLoadingFinishAndArchive, isLoadingDelete, isLoading]);
|
||||
|
||||
const actions: Array<EuiBasicTableColumn<MaintenanceWindow>> = useMemo(
|
||||
() => [
|
||||
|
@ -161,12 +177,13 @@ export const MaintenanceWindowsList = React.memo<MaintenanceWindowsListProps>(
|
|||
onCancel={onCancel}
|
||||
onArchive={onArchive}
|
||||
onCancelAndArchive={onCancelAndArchive}
|
||||
onDelete={onDelete}
|
||||
/>
|
||||
);
|
||||
},
|
||||
},
|
||||
],
|
||||
[isMutatingOrLoading, onArchive, onCancel, onCancelAndArchive, onEdit]
|
||||
[isMutatingOrLoading, onArchive, onCancel, onCancelAndArchive, onDelete, onEdit]
|
||||
);
|
||||
|
||||
const columns = useMemo(
|
||||
|
|
|
@ -48,6 +48,7 @@ describe('TableActionsPopover', () => {
|
|||
onCancel={() => {}}
|
||||
onArchive={() => {}}
|
||||
onCancelAndArchive={() => {}}
|
||||
onDelete={() => {}}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -64,12 +65,14 @@ describe('TableActionsPopover', () => {
|
|||
onCancel={() => {}}
|
||||
onArchive={() => {}}
|
||||
onCancelAndArchive={() => {}}
|
||||
onDelete={() => {}}
|
||||
/>
|
||||
);
|
||||
fireEvent.click(result.getByTestId('table-actions-icon-button'));
|
||||
expect(result.getByTestId('table-actions-edit')).toBeInTheDocument();
|
||||
expect(result.getByTestId('table-actions-cancel')).toBeInTheDocument();
|
||||
expect(result.getByTestId('table-actions-cancel-and-archive')).toBeInTheDocument();
|
||||
expect(result.getByTestId('table-actions-delete')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('it shows the correct actions when a maintenance window is upcoming', () => {
|
||||
|
@ -82,11 +85,13 @@ describe('TableActionsPopover', () => {
|
|||
onCancel={() => {}}
|
||||
onArchive={() => {}}
|
||||
onCancelAndArchive={() => {}}
|
||||
onDelete={() => {}}
|
||||
/>
|
||||
);
|
||||
fireEvent.click(result.getByTestId('table-actions-icon-button'));
|
||||
expect(result.getByTestId('table-actions-edit')).toBeInTheDocument();
|
||||
expect(result.getByTestId('table-actions-archive')).toBeInTheDocument();
|
||||
expect(result.getByTestId('table-actions-delete')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('it shows the correct actions when a maintenance window is finished', () => {
|
||||
|
@ -99,11 +104,13 @@ describe('TableActionsPopover', () => {
|
|||
onCancel={() => {}}
|
||||
onArchive={() => {}}
|
||||
onCancelAndArchive={() => {}}
|
||||
onDelete={() => {}}
|
||||
/>
|
||||
);
|
||||
fireEvent.click(result.getByTestId('table-actions-icon-button'));
|
||||
expect(result.getByTestId('table-actions-edit')).toBeInTheDocument();
|
||||
expect(result.getByTestId('table-actions-archive')).toBeInTheDocument();
|
||||
expect(result.getByTestId('table-actions-delete')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('it shows the correct actions when a maintenance window is archived', () => {
|
||||
|
@ -116,10 +123,12 @@ describe('TableActionsPopover', () => {
|
|||
onCancel={() => {}}
|
||||
onArchive={() => {}}
|
||||
onCancelAndArchive={() => {}}
|
||||
onDelete={() => {}}
|
||||
/>
|
||||
);
|
||||
fireEvent.click(result.getByTestId('table-actions-icon-button'));
|
||||
expect(result.getByTestId('table-actions-unarchive')).toBeInTheDocument();
|
||||
expect(result.getByTestId('table-actions-delete')).toBeInTheDocument();
|
||||
});
|
||||
|
||||
test('it shows the success toast when maintenance window id is copied', async () => {
|
||||
|
@ -138,6 +147,7 @@ describe('TableActionsPopover', () => {
|
|||
onCancel={() => {}}
|
||||
onArchive={() => {}}
|
||||
onCancelAndArchive={() => {}}
|
||||
onDelete={() => {}}
|
||||
/>
|
||||
);
|
||||
|
||||
|
@ -150,4 +160,30 @@ describe('TableActionsPopover', () => {
|
|||
|
||||
Object.assign(navigator, global.window.navigator.clipboard);
|
||||
});
|
||||
|
||||
test('it calls onDelete function when maintenance window is deleted', async () => {
|
||||
const onDelete = jest.fn();
|
||||
const user = userEvent.setup();
|
||||
const result = appMockRenderer.render(
|
||||
<TableActionsPopover
|
||||
id={'123'}
|
||||
isLoading={false}
|
||||
status={MaintenanceWindowStatus.Archived}
|
||||
onEdit={() => {}}
|
||||
onCancel={() => {}}
|
||||
onArchive={() => {}}
|
||||
onCancelAndArchive={() => {}}
|
||||
onDelete={onDelete}
|
||||
/>
|
||||
);
|
||||
|
||||
await user.click(await result.findByTestId('table-actions-icon-button'));
|
||||
expect(await result.findByTestId('table-actions-delete')).toBeInTheDocument();
|
||||
|
||||
await user.click(await result.findByTestId('table-actions-delete'));
|
||||
const deleteModalConfirmButton = await result.findByTestId('confirmModalConfirmButton');
|
||||
expect(deleteModalConfirmButton).toBeInTheDocument();
|
||||
await user.click(deleteModalConfirmButton);
|
||||
expect(onDelete).toHaveBeenCalledWith('123');
|
||||
});
|
||||
});
|
||||
|
|
|
@ -27,12 +27,13 @@ export interface TableActionsPopoverProps {
|
|||
onCancel: (id: string) => void;
|
||||
onArchive: (id: string, archive: boolean) => void;
|
||||
onCancelAndArchive: (id: string) => void;
|
||||
onDelete: (id: string) => void;
|
||||
}
|
||||
type ModalType = 'cancel' | 'cancelAndArchive' | 'archive' | 'unarchive';
|
||||
type ModalType = 'cancel' | 'cancelAndArchive' | 'archive' | 'unarchive' | 'delete';
|
||||
type ActionType = ModalType | 'edit' | 'copyId';
|
||||
|
||||
export const TableActionsPopover: React.FC<TableActionsPopoverProps> = React.memo(
|
||||
({ id, status, isLoading, onEdit, onCancel, onArchive, onCancelAndArchive }) => {
|
||||
({ id, status, isLoading, onEdit, onCancel, onArchive, onCancelAndArchive, onDelete }) => {
|
||||
const [isPopoverOpen, setIsPopoverOpen] = useState(false);
|
||||
const [isModalVisible, setIsModalVisible] = useState(false);
|
||||
const [modalType, setModalType] = useState<ModalType>();
|
||||
|
@ -104,6 +105,18 @@ export const TableActionsPopover: React.FC<TableActionsPopoverProps> = React.mem
|
|||
},
|
||||
subtitle: i18n.UNARCHIVE_MODAL_SUBTITLE,
|
||||
},
|
||||
delete: {
|
||||
props: {
|
||||
title: i18n.DELETE_MODAL_TITLE,
|
||||
onConfirm: () => {
|
||||
closeModal();
|
||||
onDelete(id);
|
||||
},
|
||||
cancelButtonText: i18n.CANCEL,
|
||||
confirmButtonText: i18n.DELETE_MODAL_TITLE,
|
||||
},
|
||||
subtitle: i18n.DELETE_MODAL_SUBTITLE,
|
||||
},
|
||||
};
|
||||
let m;
|
||||
if (isModalVisible && modalType) {
|
||||
|
@ -121,7 +134,16 @@ export const TableActionsPopover: React.FC<TableActionsPopoverProps> = React.mem
|
|||
);
|
||||
}
|
||||
return m;
|
||||
}, [id, modalType, isModalVisible, closeModal, onArchive, onCancel, onCancelAndArchive]);
|
||||
}, [
|
||||
id,
|
||||
modalType,
|
||||
isModalVisible,
|
||||
closeModal,
|
||||
onArchive,
|
||||
onCancel,
|
||||
onCancelAndArchive,
|
||||
onDelete,
|
||||
]);
|
||||
|
||||
const items = useMemo(() => {
|
||||
const menuItems = {
|
||||
|
@ -170,7 +192,7 @@ export const TableActionsPopover: React.FC<TableActionsPopoverProps> = React.mem
|
|||
<EuiContextMenuItem
|
||||
data-test-subj="table-actions-cancel-and-archive"
|
||||
key="cancel-and-archive"
|
||||
icon="trash"
|
||||
icon="folderOpen"
|
||||
onClick={() => {
|
||||
closePopover();
|
||||
showModal('cancelAndArchive');
|
||||
|
@ -183,7 +205,7 @@ export const TableActionsPopover: React.FC<TableActionsPopoverProps> = React.mem
|
|||
<EuiContextMenuItem
|
||||
data-test-subj="table-actions-archive"
|
||||
key="archive"
|
||||
icon="trash"
|
||||
icon="folderOpen"
|
||||
onClick={() => {
|
||||
closePopover();
|
||||
showModal('archive');
|
||||
|
@ -205,12 +227,25 @@ export const TableActionsPopover: React.FC<TableActionsPopoverProps> = React.mem
|
|||
{i18n.TABLE_ACTION_UNARCHIVE}
|
||||
</EuiContextMenuItem>
|
||||
),
|
||||
delete: (
|
||||
<EuiContextMenuItem
|
||||
data-test-subj="table-actions-delete"
|
||||
key="delete"
|
||||
icon="trash"
|
||||
onClick={() => {
|
||||
closePopover();
|
||||
showModal('delete');
|
||||
}}
|
||||
>
|
||||
{i18n.TABLE_ACTION_DELETE}
|
||||
</EuiContextMenuItem>
|
||||
),
|
||||
};
|
||||
const statusMenuItemsMap: Record<MaintenanceWindowStatus, ActionType[]> = {
|
||||
running: ['edit', 'copyId', 'cancel', 'cancelAndArchive'],
|
||||
upcoming: ['edit', 'copyId', 'archive'],
|
||||
finished: ['edit', 'copyId', 'archive'],
|
||||
archived: ['copyId', 'unarchive'],
|
||||
running: ['edit', 'copyId', 'cancel', 'cancelAndArchive', 'delete'],
|
||||
upcoming: ['edit', 'copyId', 'archive', 'delete'],
|
||||
finished: ['edit', 'copyId', 'archive', 'delete'],
|
||||
archived: ['copyId', 'unarchive', 'delete'],
|
||||
};
|
||||
return statusMenuItemsMap[status].map((type) => menuItems[type]);
|
||||
}, [status, closePopover, onEdit, id, toasts, showModal]);
|
||||
|
|
|
@ -626,6 +626,20 @@ export const CANCEL_AND_ARCHIVE_MODAL_SUBTITLE = i18n.translate(
|
|||
}
|
||||
);
|
||||
|
||||
export const DELETE_MODAL_TITLE = i18n.translate(
|
||||
'xpack.alerting.maintenanceWindows.deleteModal.title',
|
||||
{
|
||||
defaultMessage: 'Delete maintenance window',
|
||||
}
|
||||
);
|
||||
|
||||
export const DELETE_MODAL_SUBTITLE = i18n.translate(
|
||||
'xpack.alerting.maintenanceWindows.deleteModal.subtitle',
|
||||
{
|
||||
defaultMessage: "You won't be able to recover a deleted maintenance window.",
|
||||
}
|
||||
);
|
||||
|
||||
export const ARCHIVE = i18n.translate('xpack.alerting.maintenanceWindows.archive', {
|
||||
defaultMessage: 'Archive',
|
||||
});
|
||||
|
@ -660,6 +674,13 @@ export const TABLE_ACTION_UNARCHIVE = i18n.translate(
|
|||
}
|
||||
);
|
||||
|
||||
export const TABLE_ACTION_DELETE = i18n.translate(
|
||||
'xpack.alerting.maintenanceWindows.table.delete',
|
||||
{
|
||||
defaultMessage: 'Delete',
|
||||
}
|
||||
);
|
||||
|
||||
export const UNARCHIVE_MODAL_TITLE = i18n.translate(
|
||||
'xpack.alerting.maintenanceWindows.unarchiveModal.title',
|
||||
{
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* 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 { httpServiceMock } from '@kbn/core/public/mocks';
|
||||
import { deleteMaintenanceWindow } from './delete';
|
||||
|
||||
const http = httpServiceMock.createStartContract();
|
||||
|
||||
beforeEach(() => jest.resetAllMocks());
|
||||
|
||||
describe('deleteMaintenanceWindow', () => {
|
||||
test('should call delete maintenance window api', async () => {
|
||||
await deleteMaintenanceWindow({
|
||||
http,
|
||||
maintenanceWindowId: '123',
|
||||
});
|
||||
expect(http.delete.mock.calls[0]).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
"/internal/alerting/rules/maintenance_window/123",
|
||||
]
|
||||
`);
|
||||
});
|
||||
});
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* 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 type { HttpSetup } from '@kbn/core/public';
|
||||
import { INTERNAL_ALERTING_API_MAINTENANCE_WINDOW_PATH } from '../../../common';
|
||||
|
||||
export const deleteMaintenanceWindow = async ({
|
||||
http,
|
||||
maintenanceWindowId,
|
||||
}: {
|
||||
http: HttpSetup;
|
||||
maintenanceWindowId: string;
|
||||
}): Promise<void> => {
|
||||
await http.delete<Promise<void>>(
|
||||
`${INTERNAL_ALERTING_API_MAINTENANCE_WINDOW_PATH}/${encodeURIComponent(maintenanceWindowId)}`
|
||||
);
|
||||
};
|
|
@ -20,14 +20,12 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
const objectRemover = new ObjectRemover(supertest);
|
||||
const browser = getService('browser');
|
||||
|
||||
// FLAKY: https://github.com/elastic/kibana/issues/205269
|
||||
// Failing: See https://github.com/elastic/kibana/issues/205269
|
||||
describe.skip('Maintenance windows table', function () {
|
||||
describe('Maintenance windows table', function () {
|
||||
beforeEach(async () => {
|
||||
await pageObjects.common.navigateToApp('maintenanceWindows');
|
||||
});
|
||||
|
||||
after(async () => {
|
||||
afterEach(async () => {
|
||||
await objectRemover.removeAll();
|
||||
});
|
||||
|
||||
|
@ -291,5 +289,34 @@ export default ({ getPageObjects, getService }: FtrProviderContext) => {
|
|||
const listedOnSecondPageMWs = await testSubjects.findAll('list-item');
|
||||
expect(listedOnSecondPageMWs.length).to.be(2);
|
||||
});
|
||||
|
||||
it('should delete a maintenance window', async () => {
|
||||
const name = generateUniqueKey();
|
||||
await createMaintenanceWindow({
|
||||
name,
|
||||
getService,
|
||||
});
|
||||
|
||||
await browser.refresh();
|
||||
await pageObjects.maintenanceWindows.searchMaintenanceWindows(name);
|
||||
|
||||
const listBefore = await pageObjects.maintenanceWindows.getMaintenanceWindowsList();
|
||||
expect(listBefore.length).to.eql(1);
|
||||
|
||||
await testSubjects.click('table-actions-popover');
|
||||
await testSubjects.click('table-actions-delete');
|
||||
|
||||
await testSubjects.click('confirmModalConfirmButton');
|
||||
|
||||
await retry.try(async () => {
|
||||
const toastTitle = await toasts.getTitleAndDismiss();
|
||||
expect(toastTitle).to.eql('Deleted maintenance window');
|
||||
});
|
||||
|
||||
await pageObjects.maintenanceWindows.searchMaintenanceWindows(name);
|
||||
|
||||
const listAfter = await pageObjects.maintenanceWindows.getMaintenanceWindowsList();
|
||||
expect(listAfter.length).to.eql(0);
|
||||
});
|
||||
});
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue