mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 01:38:56 -04:00
[Security Solution][Detections] Adds exception modal tests (#74596)
This commit is contained in:
parent
8d851981ac
commit
bfdaacdaa6
5 changed files with 615 additions and 6 deletions
|
@ -112,7 +112,7 @@ export const AddExceptionComments = memo(function AddExceptionComments({
|
|||
<EuiFlexItem grow={1}>
|
||||
<EuiTextArea
|
||||
placeholder={i18n.ADD_COMMENT_PLACEHOLDER}
|
||||
aria-label="Use aria labels when no actual label is in use"
|
||||
aria-label="Comment Input"
|
||||
value={newCommentValue}
|
||||
onChange={handleOnChange}
|
||||
fullWidth={true}
|
||||
|
|
|
@ -0,0 +1,338 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { ThemeProvider } from 'styled-components';
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
|
||||
import { AddExceptionModal } from './';
|
||||
import { useKibana, useCurrentUser } from '../../../../common/lib/kibana';
|
||||
import { getExceptionListSchemaMock } from '../../../../../../lists/common/schemas/response/exception_list_schema.mock';
|
||||
import { useFetchIndexPatterns } from '../../../../detections/containers/detection_engine/rules';
|
||||
import { stubIndexPattern } from 'src/plugins/data/common/index_patterns/index_pattern.stub';
|
||||
import { useAddOrUpdateException } from '../use_add_exception';
|
||||
import { useFetchOrCreateRuleExceptionList } from '../use_fetch_or_create_rule_exception_list';
|
||||
import { useSignalIndex } from '../../../../detections/containers/detection_engine/alerts/use_signal_index';
|
||||
import { createUseKibanaMock } from '../../../mock/kibana_react';
|
||||
import { TimelineNonEcsData, Ecs } from '../../../../graphql/types';
|
||||
import * as builder from '../builder';
|
||||
import * as helpers from '../helpers';
|
||||
import { getExceptionListItemSchemaMock } from '../../../../../../lists/common/schemas/response/exception_list_item_schema.mock';
|
||||
import { EntriesArray } from '../../../../../../lists/common/schemas/types';
|
||||
import { ExceptionListItemSchema } from '../../../../../../lists/common';
|
||||
|
||||
jest.mock('../../../../detections/containers/detection_engine/alerts/use_signal_index');
|
||||
jest.mock('../../../../common/lib/kibana');
|
||||
jest.mock('../../../../detections/containers/detection_engine/rules');
|
||||
jest.mock('../use_add_exception');
|
||||
jest.mock('../use_fetch_or_create_rule_exception_list');
|
||||
jest.mock('../builder');
|
||||
|
||||
const useKibanaMock = useKibana as jest.Mock;
|
||||
|
||||
describe('When the add exception modal is opened', () => {
|
||||
const ruleName = 'test rule';
|
||||
let defaultEndpointItems: jest.SpyInstance<ReturnType<
|
||||
typeof helpers.defaultEndpointExceptionItems
|
||||
>>;
|
||||
let ExceptionBuilderComponent: jest.SpyInstance<ReturnType<
|
||||
typeof builder.ExceptionBuilderComponent
|
||||
>>;
|
||||
beforeEach(() => {
|
||||
defaultEndpointItems = jest.spyOn(helpers, 'defaultEndpointExceptionItems');
|
||||
ExceptionBuilderComponent = jest
|
||||
.spyOn(builder, 'ExceptionBuilderComponent')
|
||||
.mockReturnValue(<></>);
|
||||
|
||||
const kibanaMock = createUseKibanaMock()();
|
||||
useKibanaMock.mockImplementation(() => ({
|
||||
...kibanaMock,
|
||||
}));
|
||||
(useAddOrUpdateException as jest.Mock).mockImplementation(() => [
|
||||
{ isLoading: false },
|
||||
jest.fn(),
|
||||
]);
|
||||
(useFetchOrCreateRuleExceptionList as jest.Mock).mockImplementation(() => [
|
||||
false,
|
||||
getExceptionListSchemaMock(),
|
||||
]);
|
||||
(useSignalIndex as jest.Mock).mockImplementation(() => ({
|
||||
loading: false,
|
||||
signalIndexName: 'mock-siem-signals-index',
|
||||
}));
|
||||
(useFetchIndexPatterns as jest.Mock).mockImplementation(() => [
|
||||
{
|
||||
isLoading: false,
|
||||
indexPatterns: stubIndexPattern,
|
||||
},
|
||||
]);
|
||||
(useCurrentUser as jest.Mock).mockReturnValue({ username: 'test-username' });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('when the modal is loading', () => {
|
||||
let wrapper: ReactWrapper;
|
||||
beforeEach(() => {
|
||||
// Mocks one of the hooks as loading
|
||||
(useFetchIndexPatterns as jest.Mock).mockImplementation(() => [
|
||||
{
|
||||
isLoading: true,
|
||||
indexPatterns: stubIndexPattern,
|
||||
},
|
||||
]);
|
||||
wrapper = mount(
|
||||
<ThemeProvider theme={() => ({ eui: euiLightVars, darkMode: false })}>
|
||||
<AddExceptionModal
|
||||
ruleId={'123'}
|
||||
ruleIndices={[]}
|
||||
ruleName={ruleName}
|
||||
exceptionListType={'endpoint'}
|
||||
onCancel={jest.fn()}
|
||||
onConfirm={jest.fn()}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
});
|
||||
it('should show the loading spinner', () => {
|
||||
expect(wrapper.find('[data-test-subj="loadingAddExceptionModal"]').exists()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when there is no alert data passed to an endpoint list exception', () => {
|
||||
let wrapper: ReactWrapper;
|
||||
beforeEach(() => {
|
||||
wrapper = mount(
|
||||
<ThemeProvider theme={() => ({ eui: euiLightVars, darkMode: false })}>
|
||||
<AddExceptionModal
|
||||
ruleId={'123'}
|
||||
ruleIndices={['filebeat-*']}
|
||||
ruleName={ruleName}
|
||||
exceptionListType={'endpoint'}
|
||||
onCancel={jest.fn()}
|
||||
onConfirm={jest.fn()}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
const callProps = ExceptionBuilderComponent.mock.calls[0][0];
|
||||
act(() => callProps.onChange({ exceptionItems: [] }));
|
||||
});
|
||||
it('has the add exception button disabled', () => {
|
||||
expect(
|
||||
wrapper.find('button[data-test-subj="add-exception-confirm-button"]').getDOMNode()
|
||||
).toBeDisabled();
|
||||
});
|
||||
it('should render the exception builder', () => {
|
||||
expect(wrapper.find('[data-test-subj="alert-exception-builder"]').exists()).toBeTruthy();
|
||||
});
|
||||
it('should not render the close on add exception checkbox', () => {
|
||||
expect(
|
||||
wrapper.find('[data-test-subj="close-alert-on-add-add-exception-checkbox"]').exists()
|
||||
).toBeFalsy();
|
||||
});
|
||||
it('should contain the endpoint specific documentation text', () => {
|
||||
expect(wrapper.find('[data-test-subj="add-exception-endpoint-text"]').exists()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when there is alert data passed to an endpoint list exception', () => {
|
||||
let wrapper: ReactWrapper;
|
||||
beforeEach(() => {
|
||||
const alertDataMock: { ecsData: Ecs; nonEcsData: TimelineNonEcsData[] } = {
|
||||
ecsData: { _id: 'test-id' },
|
||||
nonEcsData: [{ field: 'file.path', value: ['test/path'] }],
|
||||
};
|
||||
wrapper = mount(
|
||||
<ThemeProvider theme={() => ({ eui: euiLightVars, darkMode: false })}>
|
||||
<AddExceptionModal
|
||||
ruleId={'123'}
|
||||
ruleIndices={['filebeat-*']}
|
||||
ruleName={ruleName}
|
||||
exceptionListType={'endpoint'}
|
||||
onCancel={jest.fn()}
|
||||
onConfirm={jest.fn()}
|
||||
alertData={alertDataMock}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
const callProps = ExceptionBuilderComponent.mock.calls[0][0];
|
||||
act(() => callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }));
|
||||
});
|
||||
it('has the add exception button enabled', () => {
|
||||
expect(
|
||||
wrapper.find('button[data-test-subj="add-exception-confirm-button"]').getDOMNode()
|
||||
).not.toBeDisabled();
|
||||
});
|
||||
it('should render the exception builder', () => {
|
||||
expect(wrapper.find('[data-test-subj="alert-exception-builder"]').exists()).toBeTruthy();
|
||||
});
|
||||
it('should prepopulate endpoint items', () => {
|
||||
expect(defaultEndpointItems).toHaveBeenCalled();
|
||||
});
|
||||
it('should render the close on add exception checkbox', () => {
|
||||
expect(
|
||||
wrapper.find('[data-test-subj="close-alert-on-add-add-exception-checkbox"]').exists()
|
||||
).toBeTruthy();
|
||||
});
|
||||
it('should have the bulk close checkbox disabled', () => {
|
||||
expect(
|
||||
wrapper
|
||||
.find('input[data-test-subj="bulk-close-alert-on-add-add-exception-checkbox"]')
|
||||
.getDOMNode()
|
||||
).toBeDisabled();
|
||||
});
|
||||
it('should contain the endpoint specific documentation text', () => {
|
||||
expect(wrapper.find('[data-test-subj="add-exception-endpoint-text"]').exists()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when there is alert data passed to a detection list exception', () => {
|
||||
let wrapper: ReactWrapper;
|
||||
beforeEach(() => {
|
||||
const alertDataMock: { ecsData: Ecs; nonEcsData: TimelineNonEcsData[] } = {
|
||||
ecsData: { _id: 'test-id' },
|
||||
nonEcsData: [{ field: 'file.path', value: ['test/path'] }],
|
||||
};
|
||||
wrapper = mount(
|
||||
<ThemeProvider theme={() => ({ eui: euiLightVars, darkMode: false })}>
|
||||
<AddExceptionModal
|
||||
ruleId={'123'}
|
||||
ruleIndices={['filebeat-*']}
|
||||
ruleName={ruleName}
|
||||
exceptionListType={'detection'}
|
||||
onCancel={jest.fn()}
|
||||
onConfirm={jest.fn()}
|
||||
alertData={alertDataMock}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
const callProps = ExceptionBuilderComponent.mock.calls[0][0];
|
||||
act(() => callProps.onChange({ exceptionItems: [getExceptionListItemSchemaMock()] }));
|
||||
});
|
||||
it('has the add exception button enabled', () => {
|
||||
expect(
|
||||
wrapper.find('button[data-test-subj="add-exception-confirm-button"]').getDOMNode()
|
||||
).not.toBeDisabled();
|
||||
});
|
||||
it('should render the exception builder', () => {
|
||||
expect(wrapper.find('[data-test-subj="alert-exception-builder"]').exists()).toBeTruthy();
|
||||
});
|
||||
it('should not prepopulate endpoint items', () => {
|
||||
expect(defaultEndpointItems).not.toHaveBeenCalled();
|
||||
});
|
||||
it('should render the close on add exception checkbox', () => {
|
||||
expect(
|
||||
wrapper.find('[data-test-subj="close-alert-on-add-add-exception-checkbox"]').exists()
|
||||
).toBeTruthy();
|
||||
});
|
||||
it('should have the bulk close checkbox disabled', () => {
|
||||
expect(
|
||||
wrapper
|
||||
.find('input[data-test-subj="bulk-close-alert-on-add-add-exception-checkbox"]')
|
||||
.getDOMNode()
|
||||
).toBeDisabled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when there is bulk-closeable alert data passed to an endpoint list exception', () => {
|
||||
let wrapper: ReactWrapper;
|
||||
let callProps: {
|
||||
onChange: (props: { exceptionItems: ExceptionListItemSchema[] }) => void;
|
||||
exceptionListItems: ExceptionListItemSchema[];
|
||||
};
|
||||
beforeEach(() => {
|
||||
// Mocks the index patterns to contain the pre-populated endpoint fields so that the exception qualifies as bulk closable
|
||||
(useFetchIndexPatterns as jest.Mock).mockImplementation(() => [
|
||||
{
|
||||
isLoading: false,
|
||||
indexPatterns: {
|
||||
...stubIndexPattern,
|
||||
fields: [
|
||||
{ name: 'file.path.text', type: 'string' },
|
||||
{ name: 'subject_name', type: 'string' },
|
||||
{ name: 'trusted', type: 'string' },
|
||||
{ name: 'file.hash.sha256', type: 'string' },
|
||||
{ name: 'event.code', type: 'string' },
|
||||
],
|
||||
},
|
||||
},
|
||||
]);
|
||||
const alertDataMock: { ecsData: Ecs; nonEcsData: TimelineNonEcsData[] } = {
|
||||
ecsData: { _id: 'test-id' },
|
||||
nonEcsData: [{ field: 'file.path', value: ['test/path'] }],
|
||||
};
|
||||
wrapper = mount(
|
||||
<ThemeProvider theme={() => ({ eui: euiLightVars, darkMode: false })}>
|
||||
<AddExceptionModal
|
||||
ruleId={'123'}
|
||||
ruleIndices={['filebeat-*']}
|
||||
ruleName={ruleName}
|
||||
exceptionListType={'endpoint'}
|
||||
onCancel={jest.fn()}
|
||||
onConfirm={jest.fn()}
|
||||
alertData={alertDataMock}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
callProps = ExceptionBuilderComponent.mock.calls[0][0];
|
||||
act(() => callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }));
|
||||
});
|
||||
it('has the add exception button enabled', () => {
|
||||
expect(
|
||||
wrapper.find('button[data-test-subj="add-exception-confirm-button"]').getDOMNode()
|
||||
).not.toBeDisabled();
|
||||
});
|
||||
it('should render the exception builder', () => {
|
||||
expect(wrapper.find('[data-test-subj="alert-exception-builder"]').exists()).toBeTruthy();
|
||||
});
|
||||
it('should prepopulate endpoint items', () => {
|
||||
expect(defaultEndpointItems).toHaveBeenCalled();
|
||||
});
|
||||
it('should render the close on add exception checkbox', () => {
|
||||
expect(
|
||||
wrapper.find('[data-test-subj="close-alert-on-add-add-exception-checkbox"]').exists()
|
||||
).toBeTruthy();
|
||||
});
|
||||
it('should contain the endpoint specific documentation text', () => {
|
||||
expect(wrapper.find('[data-test-subj="add-exception-endpoint-text"]').exists()).toBeTruthy();
|
||||
});
|
||||
it('should have the bulk close checkbox enabled', () => {
|
||||
expect(
|
||||
wrapper
|
||||
.find('input[data-test-subj="bulk-close-alert-on-add-add-exception-checkbox"]')
|
||||
.getDOMNode()
|
||||
).not.toBeDisabled();
|
||||
});
|
||||
describe('when a "is in list" entry is added', () => {
|
||||
it('should have the bulk close checkbox disabled', () => {
|
||||
act(() =>
|
||||
callProps.onChange({
|
||||
exceptionItems: [
|
||||
...callProps.exceptionListItems,
|
||||
{
|
||||
...getExceptionListItemSchemaMock(),
|
||||
entries: [
|
||||
{ field: 'event.code', operator: 'included', type: 'list' },
|
||||
] as EntriesArray,
|
||||
},
|
||||
],
|
||||
})
|
||||
);
|
||||
|
||||
expect(
|
||||
wrapper
|
||||
.find('input[data-test-subj="bulk-close-alert-on-add-add-exception-checkbox"]')
|
||||
.getDOMNode()
|
||||
).toBeDisabled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
|
@ -196,7 +196,7 @@ export const AddExceptionModal = memo(function AddExceptionModal({
|
|||
setShouldDisableBulkClose(
|
||||
entryHasListType(exceptionItemsToAdd) ||
|
||||
entryHasNonEcsType(exceptionItemsToAdd, signalIndexPatterns) ||
|
||||
exceptionItemsToAdd.length === 0
|
||||
exceptionItemsToAdd.every((item) => item.entries.length === 0)
|
||||
);
|
||||
}
|
||||
}, [
|
||||
|
@ -344,6 +344,7 @@ export const AddExceptionModal = memo(function AddExceptionModal({
|
|||
{alertData !== undefined && alertStatus !== 'closed' && (
|
||||
<EuiFormRow fullWidth>
|
||||
<EuiCheckbox
|
||||
data-test-subj="close-alert-on-add-add-exception-checkbox"
|
||||
id="close-alert-on-add-add-exception-checkbox"
|
||||
label="Close this alert"
|
||||
checked={shouldCloseAlert}
|
||||
|
@ -353,6 +354,7 @@ export const AddExceptionModal = memo(function AddExceptionModal({
|
|||
)}
|
||||
<EuiFormRow fullWidth>
|
||||
<EuiCheckbox
|
||||
data-test-subj="bulk-close-alert-on-add-add-exception-checkbox"
|
||||
id="bulk-close-alert-on-add-add-exception-checkbox"
|
||||
label={
|
||||
shouldDisableBulkClose
|
||||
|
@ -367,7 +369,7 @@ export const AddExceptionModal = memo(function AddExceptionModal({
|
|||
{exceptionListType === 'endpoint' && (
|
||||
<>
|
||||
<EuiSpacer />
|
||||
<EuiText color="subdued" size="s">
|
||||
<EuiText data-test-subj="add-exception-endpoint-text" color="subdued" size="s">
|
||||
{i18n.ENDPOINT_QUARANTINE_TEXT}
|
||||
</EuiText>
|
||||
</>
|
||||
|
@ -380,6 +382,7 @@ export const AddExceptionModal = memo(function AddExceptionModal({
|
|||
<EuiButtonEmpty onClick={onCancel}>{i18n.CANCEL}</EuiButtonEmpty>
|
||||
|
||||
<EuiButton
|
||||
data-test-subj="add-exception-confirm-button"
|
||||
onClick={onAddExceptionConfirm}
|
||||
isLoading={addExceptionIsLoading}
|
||||
isDisabled={isSubmitButtonDisabled}
|
||||
|
|
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
|
||||
* or more contributor license agreements. Licensed under the Elastic License;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React from 'react';
|
||||
import { ThemeProvider } from 'styled-components';
|
||||
import { mount, ReactWrapper } from 'enzyme';
|
||||
import euiLightVars from '@elastic/eui/dist/eui_theme_light.json';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
|
||||
import { EditExceptionModal } from './';
|
||||
import { useKibana, useCurrentUser } from '../../../../common/lib/kibana';
|
||||
import { useFetchIndexPatterns } from '../../../../detections/containers/detection_engine/rules';
|
||||
import {
|
||||
stubIndexPattern,
|
||||
stubIndexPatternWithFields,
|
||||
} from 'src/plugins/data/common/index_patterns/index_pattern.stub';
|
||||
import { useAddOrUpdateException } from '../use_add_exception';
|
||||
import { useSignalIndex } from '../../../../detections/containers/detection_engine/alerts/use_signal_index';
|
||||
import { createUseKibanaMock } from '../../../mock/kibana_react';
|
||||
import { getExceptionListItemSchemaMock } from '../../../../../../lists/common/schemas/response/exception_list_item_schema.mock';
|
||||
import { EntriesArray } from '../../../../../../lists/common/schemas/types';
|
||||
import * as builder from '../builder';
|
||||
|
||||
jest.mock('../../../../common/lib/kibana');
|
||||
jest.mock('../../../../detections/containers/detection_engine/rules');
|
||||
jest.mock('../use_add_exception');
|
||||
jest.mock('../use_fetch_or_create_rule_exception_list');
|
||||
jest.mock('../../../../detections/containers/detection_engine/alerts/use_signal_index');
|
||||
jest.mock('../builder');
|
||||
|
||||
const useKibanaMock = useKibana as jest.Mock;
|
||||
|
||||
describe('When the edit exception modal is opened', () => {
|
||||
const ruleName = 'test rule';
|
||||
|
||||
let ExceptionBuilderComponent: jest.SpyInstance<ReturnType<
|
||||
typeof builder.ExceptionBuilderComponent
|
||||
>>;
|
||||
|
||||
beforeEach(() => {
|
||||
ExceptionBuilderComponent = jest
|
||||
.spyOn(builder, 'ExceptionBuilderComponent')
|
||||
.mockReturnValue(<></>);
|
||||
|
||||
const kibanaMock = createUseKibanaMock()();
|
||||
useKibanaMock.mockImplementation(() => ({
|
||||
...kibanaMock,
|
||||
}));
|
||||
(useSignalIndex as jest.Mock).mockReturnValue({
|
||||
loading: false,
|
||||
signalIndexName: 'test-signal',
|
||||
});
|
||||
(useAddOrUpdateException as jest.Mock).mockImplementation(() => [
|
||||
{ isLoading: false },
|
||||
jest.fn(),
|
||||
]);
|
||||
(useFetchIndexPatterns as jest.Mock).mockImplementation(() => [
|
||||
{
|
||||
isLoading: false,
|
||||
indexPatterns: stubIndexPatternWithFields,
|
||||
},
|
||||
]);
|
||||
(useCurrentUser as jest.Mock).mockReturnValue({ username: 'test-username' });
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
jest.restoreAllMocks();
|
||||
});
|
||||
|
||||
describe('when the modal is loading', () => {
|
||||
let wrapper: ReactWrapper;
|
||||
beforeEach(() => {
|
||||
(useFetchIndexPatterns as jest.Mock).mockImplementation(() => [
|
||||
{
|
||||
isLoading: true,
|
||||
indexPatterns: stubIndexPattern,
|
||||
},
|
||||
]);
|
||||
wrapper = mount(
|
||||
<ThemeProvider theme={() => ({ eui: euiLightVars, darkMode: false })}>
|
||||
<EditExceptionModal
|
||||
ruleIndices={[]}
|
||||
ruleName={ruleName}
|
||||
exceptionListType={'endpoint'}
|
||||
onCancel={jest.fn()}
|
||||
onConfirm={jest.fn()}
|
||||
exceptionItem={getExceptionListItemSchemaMock()}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
});
|
||||
it('renders the loading spinner', () => {
|
||||
expect(wrapper.find('[data-test-subj="loadingEditExceptionModal"]').exists()).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when an endpoint exception with exception data is passed', () => {
|
||||
describe('when exception entry fields are included in the index pattern', () => {
|
||||
let wrapper: ReactWrapper;
|
||||
beforeEach(() => {
|
||||
const exceptionItemMock = {
|
||||
...getExceptionListItemSchemaMock(),
|
||||
entries: [
|
||||
{ field: 'response', operator: 'included', type: 'match', value: '3' },
|
||||
] as EntriesArray,
|
||||
};
|
||||
wrapper = mount(
|
||||
<ThemeProvider theme={() => ({ eui: euiLightVars, darkMode: false })}>
|
||||
<EditExceptionModal
|
||||
ruleIndices={['filebeat-*']}
|
||||
ruleName={ruleName}
|
||||
exceptionListType={'endpoint'}
|
||||
onCancel={jest.fn()}
|
||||
onConfirm={jest.fn()}
|
||||
exceptionItem={exceptionItemMock}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
const callProps = ExceptionBuilderComponent.mock.calls[0][0];
|
||||
act(() => callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }));
|
||||
});
|
||||
it('has the edit exception button enabled', () => {
|
||||
expect(
|
||||
wrapper.find('button[data-test-subj="edit-exception-confirm-button"]').getDOMNode()
|
||||
).not.toBeDisabled();
|
||||
});
|
||||
it('should have the bulk close checkbox enabled', () => {
|
||||
expect(
|
||||
wrapper
|
||||
.find('input[data-test-subj="close-alert-on-add-edit-exception-checkbox"]')
|
||||
.getDOMNode()
|
||||
).not.toBeDisabled();
|
||||
});
|
||||
it('renders the exceptions builder', () => {
|
||||
expect(
|
||||
wrapper.find('[data-test-subj="edit-exception-modal-builder"]').exists()
|
||||
).toBeTruthy();
|
||||
});
|
||||
it('should contain the endpoint specific documentation text', () => {
|
||||
expect(
|
||||
wrapper.find('[data-test-subj="edit-exception-endpoint-text"]').exists()
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when exception entry fields aren't included in the index pattern", () => {
|
||||
let wrapper: ReactWrapper;
|
||||
beforeEach(() => {
|
||||
wrapper = mount(
|
||||
<ThemeProvider theme={() => ({ eui: euiLightVars, darkMode: false })}>
|
||||
<EditExceptionModal
|
||||
ruleIndices={['filebeat-*']}
|
||||
ruleName={ruleName}
|
||||
exceptionListType={'endpoint'}
|
||||
onCancel={jest.fn()}
|
||||
onConfirm={jest.fn()}
|
||||
exceptionItem={getExceptionListItemSchemaMock()}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
const callProps = ExceptionBuilderComponent.mock.calls[0][0];
|
||||
act(() => callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }));
|
||||
});
|
||||
it('has the edit exception button enabled', () => {
|
||||
expect(
|
||||
wrapper.find('button[data-test-subj="edit-exception-confirm-button"]').getDOMNode()
|
||||
).not.toBeDisabled();
|
||||
});
|
||||
it('should have the bulk close checkbox disabled', () => {
|
||||
expect(
|
||||
wrapper
|
||||
.find('input[data-test-subj="close-alert-on-add-edit-exception-checkbox"]')
|
||||
.getDOMNode()
|
||||
).toBeDisabled();
|
||||
});
|
||||
it('renders the exceptions builder', () => {
|
||||
expect(
|
||||
wrapper.find('[data-test-subj="edit-exception-modal-builder"]').exists()
|
||||
).toBeTruthy();
|
||||
});
|
||||
it('should contain the endpoint specific documentation text', () => {
|
||||
expect(
|
||||
wrapper.find('[data-test-subj="edit-exception-endpoint-text"]').exists()
|
||||
).toBeTruthy();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('when an detection exception with entries is passed', () => {
|
||||
let wrapper: ReactWrapper;
|
||||
beforeEach(() => {
|
||||
wrapper = mount(
|
||||
<ThemeProvider theme={() => ({ eui: euiLightVars, darkMode: false })}>
|
||||
<EditExceptionModal
|
||||
ruleIndices={['filebeat-*']}
|
||||
ruleName={ruleName}
|
||||
exceptionListType={'detection'}
|
||||
onCancel={jest.fn()}
|
||||
onConfirm={jest.fn()}
|
||||
exceptionItem={getExceptionListItemSchemaMock()}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
const callProps = ExceptionBuilderComponent.mock.calls[0][0];
|
||||
act(() => callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }));
|
||||
});
|
||||
it('has the edit exception button enabled', () => {
|
||||
expect(
|
||||
wrapper.find('button[data-test-subj="edit-exception-confirm-button"]').getDOMNode()
|
||||
).not.toBeDisabled();
|
||||
});
|
||||
it('renders the exceptions builder', () => {
|
||||
expect(wrapper.find('[data-test-subj="edit-exception-modal-builder"]').exists()).toBeTruthy();
|
||||
});
|
||||
it('should not contain the endpoint specific documentation text', () => {
|
||||
expect(wrapper.find('[data-test-subj="edit-exception-endpoint-text"]').exists()).toBeFalsy();
|
||||
});
|
||||
it('should have the bulk close checkbox disabled', () => {
|
||||
expect(
|
||||
wrapper
|
||||
.find('input[data-test-subj="close-alert-on-add-edit-exception-checkbox"]')
|
||||
.getDOMNode()
|
||||
).toBeDisabled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('when an exception with no entries is passed', () => {
|
||||
let wrapper: ReactWrapper;
|
||||
beforeEach(() => {
|
||||
const exceptionItemMock = { ...getExceptionListItemSchemaMock(), entries: [] };
|
||||
wrapper = mount(
|
||||
<ThemeProvider theme={() => ({ eui: euiLightVars, darkMode: false })}>
|
||||
<EditExceptionModal
|
||||
ruleIndices={['filebeat-*']}
|
||||
ruleName={ruleName}
|
||||
exceptionListType={'detection'}
|
||||
onCancel={jest.fn()}
|
||||
onConfirm={jest.fn()}
|
||||
exceptionItem={exceptionItemMock}
|
||||
/>
|
||||
</ThemeProvider>
|
||||
);
|
||||
const callProps = ExceptionBuilderComponent.mock.calls[0][0];
|
||||
act(() => callProps.onChange({ exceptionItems: [...callProps.exceptionListItems] }));
|
||||
});
|
||||
it('has the edit exception button disabled', () => {
|
||||
expect(
|
||||
wrapper.find('button[data-test-subj="edit-exception-confirm-button"]').getDOMNode()
|
||||
).toBeDisabled();
|
||||
});
|
||||
it('renders the exceptions builder', () => {
|
||||
expect(wrapper.find('[data-test-subj="edit-exception-modal-builder"]').exists()).toBeTruthy();
|
||||
});
|
||||
it('should have the bulk close checkbox disabled', () => {
|
||||
expect(
|
||||
wrapper
|
||||
.find('input[data-test-subj="close-alert-on-add-edit-exception-checkbox"]')
|
||||
.getDOMNode()
|
||||
).toBeDisabled();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -137,7 +137,7 @@ export const EditExceptionModal = memo(function EditExceptionModal({
|
|||
setShouldDisableBulkClose(
|
||||
entryHasListType(exceptionItemsToAdd) ||
|
||||
entryHasNonEcsType(exceptionItemsToAdd, signalIndexPatterns) ||
|
||||
exceptionItemsToAdd.length === 0
|
||||
exceptionItemsToAdd.every((item) => item.entries.length === 0)
|
||||
);
|
||||
}
|
||||
}, [
|
||||
|
@ -259,7 +259,8 @@ export const EditExceptionModal = memo(function EditExceptionModal({
|
|||
<ModalBodySection>
|
||||
<EuiFormRow fullWidth>
|
||||
<EuiCheckbox
|
||||
id="close-alert-on-add-add-exception-checkbox"
|
||||
data-test-subj="close-alert-on-add-edit-exception-checkbox"
|
||||
id="close-alert-on-add-edit-exception-checkbox"
|
||||
label={
|
||||
shouldDisableBulkClose ? i18n.BULK_CLOSE_LABEL_DISABLED : i18n.BULK_CLOSE_LABEL
|
||||
}
|
||||
|
@ -271,7 +272,7 @@ export const EditExceptionModal = memo(function EditExceptionModal({
|
|||
{exceptionListType === 'endpoint' && (
|
||||
<>
|
||||
<EuiSpacer />
|
||||
<EuiText color="subdued" size="s">
|
||||
<EuiText data-test-subj="edit-exception-endpoint-text" color="subdued" size="s">
|
||||
{i18n.ENDPOINT_QUARANTINE_TEXT}
|
||||
</EuiText>
|
||||
</>
|
||||
|
@ -292,6 +293,7 @@ export const EditExceptionModal = memo(function EditExceptionModal({
|
|||
<EuiButtonEmpty onClick={onCancel}>{i18n.CANCEL}</EuiButtonEmpty>
|
||||
|
||||
<EuiButton
|
||||
data-test-subj="edit-exception-confirm-button"
|
||||
onClick={onEditExceptionConfirm}
|
||||
isLoading={addExceptionIsLoading}
|
||||
isDisabled={isSubmitButtonDisabled}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue