110640 tests for alert bulk actions (#117264) (#118428)

* bulk actions test cases outline

* helpers to filter alerts per rule type (reason)

* add proper apm indices/privileges to observability functional tests

* cleanup

* add apm archive data

* add correct apm archive data, add helper to select checkbox per solution & cleanup

* enable more tests

* cleanup

* tests for bulk container

* more tests for bulk container

* fix eslint issues

* fix failing unit tests (use ~= for multiple space separated values)

* remove unused value

* fix typescript error with container.querySelector

* remove apm test archive data

* use getByTestId in the tests

* fix security cypress tests

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>

Co-authored-by: mgiota <giota85@gmail.com>
This commit is contained in:
Kibana Machine 2021-11-11 17:06:54 -05:00 committed by GitHub
parent acdd56704a
commit 1be554f2e5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 282 additions and 5 deletions

View file

@ -12,7 +12,7 @@ export const ALERTS = '[data-test-subj="events-viewer-panel"] [data-test-subj="e
export const ALERTS_COUNT =
'[data-test-subj="events-viewer-panel"] [data-test-subj="server-side-event-count"]';
export const ALERT_CHECKBOX = '[data-test-subj="select-event"].euiCheckbox__input';
export const ALERT_CHECKBOX = '[data-test-subj~="select-event"].euiCheckbox__input';
export const ALERT_GRID_CELL = '[data-test-subj="dataGridRowCell"]';

View file

@ -45,8 +45,8 @@ describe('checkbox control column', () => {
const { getByTestId } = render(
<RowCheckBox {...defaultProps} onRowSelected={onRowSelected} />
);
fireEvent.click(getByTestId('select-event'));
const checkbox = getByTestId(/^select-event/);
fireEvent.click(checkbox);
expect(onRowSelected).toHaveBeenCalled();
});

View file

@ -7,6 +7,7 @@
import { EuiCheckbox, EuiLoadingSpinner } from '@elastic/eui';
import React, { useCallback } from 'react';
import { ALERT_RULE_PRODUCER } from '@kbn/rule-data-utils';
import { ActionProps, HeaderActionProps } from '../../../../../common';
import * as i18n from './translations';
@ -18,7 +19,10 @@ export const RowCheckBox = ({
columnValues,
disabled,
loadingEventIds,
data,
}: ActionProps) => {
const ruleProducers = data.find((d) => d.field === ALERT_RULE_PRODUCER)?.value ?? [];
const ruleProducer = ruleProducers[0];
const handleSelectEvent = useCallback(
(event: React.ChangeEvent<HTMLInputElement>) => {
if (!disabled) {
@ -35,7 +39,7 @@ export const RowCheckBox = ({
<EuiLoadingSpinner size="m" data-test-subj="event-loader" />
) : (
<EuiCheckbox
data-test-subj="select-event"
data-test-subj={`select-event select-event-rule-producer-${ruleProducer}`}
id={eventId}
checked={checked && !disabled}
disabled={disabled}

View file

@ -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 { FtrProviderContext } from '../../../ftr_provider_context';
const CHECKBOX_SELECTOR = 'select-event';
const CHECKBOX_PRODUCER_SELECTOR = 'select-event-rule-producer';
const BULK_ACTIONS_CONTAINER = 'bulk-actions-button-container';
const SELECTED_BULK_ACTIONS_BUTTON = 'selectedShowBulkActionsButton';
export function ObservabilityAlertsBulkActionsProvider({ getService }: FtrProviderContext) {
const find = getService('find');
const testSubjects = getService('testSubjects');
const getCheckboxSelector = async () => {
return await find.allByCssSelector(testSubjects.getCssSelector(`~${CHECKBOX_SELECTOR}`));
};
const missingCheckboxSelectorOrFail = async () => {
return await testSubjects.missingOrFail(`~${CHECKBOX_SELECTOR}`);
};
const getCheckboxSelectorPerProducer = async (producer: string) => {
return await find.allByCssSelector(
testSubjects.getCssSelector(`~${CHECKBOX_PRODUCER_SELECTOR}-${producer}`)
);
};
const getBulkActionsContainer = async () => {
return await testSubjects.find(BULK_ACTIONS_CONTAINER);
};
const getBulkActionsContainerOrFail = async () => {
return await testSubjects.existOrFail(BULK_ACTIONS_CONTAINER);
};
const getBulkActionsButton = async () => {
return await testSubjects.find(SELECTED_BULK_ACTIONS_BUTTON);
};
return {
getCheckboxSelector,
getCheckboxSelectorPerProducer,
missingCheckboxSelectorOrFail,
getBulkActionsContainer,
getBulkActionsContainerOrFail,
getBulkActionsButton,
};
}

View file

@ -8,6 +8,7 @@
import { ObservabilityAlertsPaginationProvider } from './pagination';
import { ObservabilityAlertsCommonProvider } from './common';
import { ObservabilityAlertsAddToCaseProvider } from './add_to_case';
import { ObservabilityAlertsBulkActionsProvider } from './bulk_actions';
import { FtrProviderContext } from '../../../ftr_provider_context';
@ -15,9 +16,12 @@ export function ObservabilityAlertsProvider(context: FtrProviderContext) {
const common = ObservabilityAlertsCommonProvider(context);
const pagination = ObservabilityAlertsPaginationProvider(context);
const addToCase = ObservabilityAlertsAddToCaseProvider(context);
const bulkActions = ObservabilityAlertsBulkActionsProvider(context);
return {
common,
pagination,
addToCase,
bulkActions,
};
}

View file

@ -72,7 +72,20 @@ const defineBasicObservabilityRole = (
...((features.infrastructure?.length ?? 0) > 0
? [{ names: ['metricbeat-*', 'metrics-*'], privileges: ['all'] }]
: []),
...((features.apm?.length ?? 0) > 0 ? [{ names: ['apm-*'], privileges: ['all'] }] : []),
...((features.apm?.length ?? 0) > 0
? [
{
names: [
'apm-*',
'logs-apm*',
'metrics-apm*',
'traces-apm*',
'observability-annotations',
],
privileges: ['read', 'view_index_metadata'],
},
]
: []),
...((features.uptime?.length ?? 0) > 0
? [{ names: ['heartbeat-*,synthetics-*'], privileges: ['all'] }]
: []),

View file

@ -0,0 +1,203 @@
/*
* 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 expect from '@kbn/expect';
import { FtrProviderContext } from '../../../ftr_provider_context';
async function asyncForEach<T>(array: T[], callback: (item: T, index: number) => void) {
for (let index = 0; index < array.length; index++) {
await callback(array[index], index);
}
}
export default ({ getService, getPageObjects }: FtrProviderContext) => {
const esArchiver = getService('esArchiver');
const observability = getService('observability');
const retry = getService('retry');
describe('Observability alerts / Bulk actions', function () {
this.tags('includeFirefox');
before(async () => {
await esArchiver.load('x-pack/test/functional/es_archives/observability/alerts');
await esArchiver.load('x-pack/test/functional/es_archives/infra/metrics_and_logs');
await esArchiver.load(
'x-pack/test/apm_api_integration/common/fixtures/es_archiver/apm_8.0.0'
);
});
after(async () => {
await esArchiver.unload('x-pack/test/functional/es_archives/infra/metrics_and_logs');
await esArchiver.unload('x-pack/test/functional/es_archives/observability/alerts');
await esArchiver.unload(
'x-pack/test/apm_api_integration/common/fixtures/es_archiver/apm_8.0.0'
);
});
describe('When user has all priviledges for logs app', () => {
before(async () => {
await observability.users.setTestUserRole(
observability.users.defineBasicObservabilityRole({
logs: ['all'],
})
);
await observability.alerts.common.navigateToTimeWithData();
});
after(async () => {
await observability.users.restoreDefaultTestUserRole();
});
it('logs checkboxes are enabled', async () => {
const logsCheckboxes =
await observability.alerts.bulkActions.getCheckboxSelectorPerProducer('logs');
await asyncForEach(logsCheckboxes, async (checkbox, index) => {
expect(await checkbox.isEnabled()).to.be(true);
});
});
describe('when checkbox is clicked', async () => {
it('shows bulk actions container', async () => {
const logsCheckboxes =
await observability.alerts.bulkActions.getCheckboxSelectorPerProducer('logs');
await logsCheckboxes[0].click();
await observability.alerts.bulkActions.getBulkActionsContainerOrFail();
});
describe('when selected bulk action button is clicked', async () => {
it('opens overflow menu with workflow status options', async () => {
await retry.try(async () => {
await (await observability.alerts.bulkActions.getBulkActionsButton()).click();
});
});
});
});
});
describe('When user has all priviledges for apm app', () => {
before(async () => {
await observability.users.setTestUserRole(
observability.users.defineBasicObservabilityRole({
apm: ['all'],
})
);
await observability.alerts.common.navigateToTimeWithData();
});
after(async () => {
await observability.users.restoreDefaultTestUserRole();
});
it('apm checkboxes are enabled', async () => {
const apmCheckboxes = await observability.alerts.bulkActions.getCheckboxSelectorPerProducer(
'apm'
);
await asyncForEach(apmCheckboxes, async (checkbox, index) => {
expect(await checkbox.isEnabled()).to.be(true);
});
});
describe('when checkbox is clicked', async () => {
it('shows bulk actions container', async () => {
const apmCheckboxes =
await observability.alerts.bulkActions.getCheckboxSelectorPerProducer('apm');
await apmCheckboxes[0].click();
await observability.alerts.bulkActions.getBulkActionsContainerOrFail();
});
describe('when selected bulk action button is clicked', async () => {
it('opens overflow menu with workflow status options', async () => {
await retry.try(async () => {
await (await observability.alerts.bulkActions.getBulkActionsButton()).click();
});
});
});
});
});
describe('When user has read permissions for logs', () => {
before(async () => {
await observability.users.setTestUserRole(
observability.users.defineBasicObservabilityRole({
logs: ['read'],
})
);
await observability.alerts.common.navigateToTimeWithData();
});
after(async () => {
await observability.users.restoreDefaultTestUserRole();
});
it('checkbox is not visible', async () => {
await observability.alerts.bulkActions.missingCheckboxSelectorOrFail();
});
});
describe('When user has read permissions for apm', () => {
before(async () => {
await observability.users.setTestUserRole(
observability.users.defineBasicObservabilityRole({
apm: ['read'],
})
);
await observability.alerts.common.navigateToTimeWithData();
});
after(async () => {
await observability.users.restoreDefaultTestUserRole();
});
it('checkbox is not displayed', async () => {
await observability.alerts.bulkActions.missingCheckboxSelectorOrFail();
});
});
describe('When user has mixed permissions for observability apps', () => {
before(async () => {
await observability.users.setTestUserRole(
observability.users.defineBasicObservabilityRole({
logs: ['all'],
apm: ['read'],
observabilityCases: ['read'],
})
);
await observability.alerts.common.navigateToTimeWithData();
});
after(async () => {
await observability.users.restoreDefaultTestUserRole();
});
it('apm checkboxes are disabled', async () => {
const apmCheckboxes = await observability.alerts.bulkActions.getCheckboxSelectorPerProducer(
'apm'
);
await asyncForEach(apmCheckboxes, async (checkbox, index) => {
expect(await checkbox.isEnabled()).to.be(false);
});
});
it('logs checkboxes are enabled', async () => {
const logsCheckboxes =
await observability.alerts.bulkActions.getCheckboxSelectorPerProducer('logs');
await asyncForEach(logsCheckboxes, async (checkbox, index) => {
expect(await checkbox.isEnabled()).to.be(true);
});
});
});
});
};

View file

@ -18,5 +18,6 @@ export default function ({ loadTestFile }: FtrProviderContext) {
loadTestFile(require.resolve('./alerts/pagination'));
loadTestFile(require.resolve('./alerts/add_to_case'));
loadTestFile(require.resolve('./alerts/state_synchronization'));
loadTestFile(require.resolve('./alerts/bulk_actions'));
});
}