mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Security Solution][Detections] Adds ip_range and text types to value list upload form (#73109)
* Adds two more types to the value lists form * Adds `ip_range` and `text` types * Replaces radio group with select * Add custom command for attaching a file to an input This will be used to excercise value list uploads. * Add some missing test subjects for our value lists modal * Add cypress test for value lists modal This exercises the happy path: opening the modal, uploading a list, and asserting that it subsequently appears in the table. Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
parent
6d4bb9dc0d
commit
b15a0a97f7
10 changed files with 156 additions and 26 deletions
|
@ -0,0 +1,6 @@
|
|||
these
|
||||
are
|
||||
keywords
|
||||
for
|
||||
a
|
||||
list
|
|
@ -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;
|
||||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import { loginAndWaitForPageWithoutDateRange } from '../tasks/login';
|
||||
import { DETECTIONS_URL } from '../urls/navigation';
|
||||
import {
|
||||
waitForAlertsPanelToBeLoaded,
|
||||
waitForAlertsIndexToBeCreated,
|
||||
goToManageAlertsDetectionRules,
|
||||
} from '../tasks/alerts';
|
||||
import {
|
||||
waitForListsIndexToBeCreated,
|
||||
waitForValueListsModalToBeLoaded,
|
||||
openValueListsModal,
|
||||
selectValueListsFile,
|
||||
uploadValueList,
|
||||
} from '../tasks/lists';
|
||||
import { VALUE_LISTS_TABLE, VALUE_LISTS_ROW } from '../screens/lists';
|
||||
|
||||
describe('value lists', () => {
|
||||
describe('management modal', () => {
|
||||
it('creates a keyword list from an uploaded file', () => {
|
||||
loginAndWaitForPageWithoutDateRange(DETECTIONS_URL);
|
||||
waitForAlertsPanelToBeLoaded();
|
||||
waitForAlertsIndexToBeCreated();
|
||||
waitForListsIndexToBeCreated();
|
||||
goToManageAlertsDetectionRules();
|
||||
waitForValueListsModalToBeLoaded();
|
||||
openValueListsModal();
|
||||
selectValueListsFile();
|
||||
uploadValueList();
|
||||
|
||||
cy.get(VALUE_LISTS_TABLE)
|
||||
.find(VALUE_LISTS_ROW)
|
||||
.should(($row) => {
|
||||
expect($row.text()).to.contain('value_list.txt');
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
11
x-pack/plugins/security_solution/cypress/screens/lists.ts
Normal file
11
x-pack/plugins/security_solution/cypress/screens/lists.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
export const VALUE_LISTS_MODAL_ACTIVATOR = '[data-test-subj="open-value-lists-modal-button"]';
|
||||
export const VALUE_LISTS_TABLE = '[data-test-subj="value-lists-table"]';
|
||||
export const VALUE_LISTS_ROW = '.euiTableRow';
|
||||
export const VALUE_LIST_FILE_PICKER = '[data-test-subj="value-list-file-picker"]';
|
||||
export const VALUE_LIST_FILE_UPLOAD_BUTTON = '[data-test-subj="value-lists-form-import-action"]';
|
|
@ -39,3 +39,22 @@ Cypress.Commands.add('stubSecurityApi', function (dataFileName) {
|
|||
cy.fixture(dataFileName).as(`${dataFileName}JSON`);
|
||||
cy.route('POST', 'api/solutions/security/graphql', `@${dataFileName}JSON`);
|
||||
});
|
||||
|
||||
Cypress.Commands.add(
|
||||
'attachFile',
|
||||
{
|
||||
prevSubject: 'element',
|
||||
},
|
||||
(input, fileName, fileType = 'text/plain') => {
|
||||
cy.fixture(fileName)
|
||||
.then((content) => Cypress.Blob.base64StringToBlob(content, fileType))
|
||||
.then((blob) => {
|
||||
const testFile = new File([blob], fileName, { type: fileType });
|
||||
const dataTransfer = new DataTransfer();
|
||||
|
||||
dataTransfer.items.add(testFile);
|
||||
input[0].files = dataTransfer.files;
|
||||
return input;
|
||||
});
|
||||
}
|
||||
);
|
||||
|
|
|
@ -7,5 +7,6 @@
|
|||
declare namespace Cypress {
|
||||
interface Chainable<Subject> {
|
||||
stubSecurityApi(dataFileName: string): Chainable<Subject>;
|
||||
attachFile(fileName: string, fileType?: string): Chainable<JQuery>;
|
||||
}
|
||||
}
|
||||
|
|
36
x-pack/plugins/security_solution/cypress/tasks/lists.ts
Normal file
36
x-pack/plugins/security_solution/cypress/tasks/lists.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 {
|
||||
VALUE_LISTS_MODAL_ACTIVATOR,
|
||||
VALUE_LIST_FILE_PICKER,
|
||||
VALUE_LIST_FILE_UPLOAD_BUTTON,
|
||||
} from '../screens/lists';
|
||||
|
||||
export const waitForListsIndexToBeCreated = () => {
|
||||
cy.request({ url: '/api/lists/index', retryOnStatusCodeFailure: true }).then((response) => {
|
||||
if (response.status !== 200) {
|
||||
cy.wait(7500);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
export const waitForValueListsModalToBeLoaded = () => {
|
||||
cy.get(VALUE_LISTS_MODAL_ACTIVATOR).should('exist');
|
||||
cy.get(VALUE_LISTS_MODAL_ACTIVATOR).should('not.be.disabled');
|
||||
};
|
||||
|
||||
export const openValueListsModal = () => {
|
||||
cy.get(VALUE_LISTS_MODAL_ACTIVATOR).click();
|
||||
};
|
||||
|
||||
export const selectValueListsFile = () => {
|
||||
cy.get(VALUE_LIST_FILE_PICKER).attachFile('value_list.txt').trigger('change', { force: true });
|
||||
};
|
||||
|
||||
export const uploadValueList = () => {
|
||||
cy.get(VALUE_LIST_FILE_UPLOAD_BUTTON).click();
|
||||
};
|
|
@ -4,8 +4,7 @@
|
|||
* you may not use this file except in compliance with the Elastic License.
|
||||
*/
|
||||
|
||||
import React, { useCallback, useState, ReactNode, useEffect, useRef } from 'react';
|
||||
import styled from 'styled-components';
|
||||
import React, { useCallback, useState, useEffect, useRef } from 'react';
|
||||
import {
|
||||
EuiButton,
|
||||
EuiButtonEmpty,
|
||||
|
@ -14,34 +13,30 @@ import {
|
|||
EuiFilePicker,
|
||||
EuiFlexGroup,
|
||||
EuiFlexItem,
|
||||
EuiRadioGroup,
|
||||
EuiSelect,
|
||||
EuiSelectOption,
|
||||
} from '@elastic/eui';
|
||||
|
||||
import { useImportList, ListSchema, Type } from '../../../shared_imports';
|
||||
import * as i18n from './translations';
|
||||
import { useKibana } from '../../../common/lib/kibana';
|
||||
|
||||
const InlineRadioGroup = styled(EuiRadioGroup)`
|
||||
display: flex;
|
||||
|
||||
.euiRadioGroup__item + .euiRadioGroup__item {
|
||||
margin: 0 0 0 12px;
|
||||
}
|
||||
`;
|
||||
|
||||
interface ListTypeOptions {
|
||||
id: Type;
|
||||
label: ReactNode;
|
||||
}
|
||||
|
||||
const options: ListTypeOptions[] = [
|
||||
const options: EuiSelectOption[] = [
|
||||
{
|
||||
id: 'keyword',
|
||||
label: i18n.KEYWORDS_RADIO,
|
||||
value: 'keyword',
|
||||
text: i18n.KEYWORDS_RADIO,
|
||||
},
|
||||
{
|
||||
id: 'ip',
|
||||
label: i18n.IP_RADIO,
|
||||
value: 'ip',
|
||||
text: i18n.IP_RADIO,
|
||||
},
|
||||
{
|
||||
value: 'ip_range',
|
||||
text: i18n.IP_RANGE_RADIO,
|
||||
},
|
||||
{
|
||||
value: 'text',
|
||||
text: i18n.TEXT_RADIO,
|
||||
},
|
||||
];
|
||||
|
||||
|
@ -63,8 +58,10 @@ export const ValueListsFormComponent: React.FC<ValueListsFormProps> = ({ onError
|
|||
|
||||
const fileIsValid = !file || validFileTypes.some((fileType) => file.type === fileType);
|
||||
|
||||
// EuiRadioGroup's onChange only infers 'string' from our options
|
||||
const handleRadioChange = useCallback((t: string) => setType(t as Type), [setType]);
|
||||
const handleRadioChange = useCallback(
|
||||
(event: React.ChangeEvent<HTMLSelectElement>) => setType(event.target.value as Type),
|
||||
[setType]
|
||||
);
|
||||
|
||||
const handleFileChange = useCallback((files: FileList | null) => {
|
||||
setFile(files?.item(0) ?? null);
|
||||
|
@ -133,6 +130,7 @@ export const ValueListsFormComponent: React.FC<ValueListsFormProps> = ({ onError
|
|||
>
|
||||
<EuiFilePicker
|
||||
accept={validFileTypes.join()}
|
||||
data-test-subj="value-list-file-picker"
|
||||
id="value-list-file-picker"
|
||||
initialPromptText={i18n.FILE_PICKER_PROMPT}
|
||||
ref={filePickerRef}
|
||||
|
@ -146,16 +144,16 @@ export const ValueListsFormComponent: React.FC<ValueListsFormProps> = ({ onError
|
|||
<EuiFlexGroup>
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow label={i18n.LIST_TYPES_RADIO_LABEL}>
|
||||
<InlineRadioGroup
|
||||
<EuiSelect
|
||||
options={options}
|
||||
idSelected={type}
|
||||
value={type}
|
||||
onChange={handleRadioChange}
|
||||
name="valueListType"
|
||||
/>
|
||||
</EuiFormRow>
|
||||
</EuiFlexItem>
|
||||
<EuiFlexItem>
|
||||
<EuiFormRow>
|
||||
<EuiFormRow hasEmptyLabelSpace={true}>
|
||||
<EuiFlexGroup alignItems="flexEnd">
|
||||
<EuiFlexItem>
|
||||
{importState.loading && (
|
||||
|
|
|
@ -35,6 +35,7 @@ export const ValueListsTableComponent: React.FC<ValueListsTableProps> = ({
|
|||
<h2>{i18n.TABLE_TITLE}</h2>
|
||||
</EuiText>
|
||||
<EuiBasicTable
|
||||
data-test-subj="value-lists-table"
|
||||
columns={columns}
|
||||
items={items}
|
||||
loading={loading}
|
||||
|
|
|
@ -142,3 +142,17 @@ export const KEYWORDS_RADIO = i18n.translate(
|
|||
defaultMessage: 'Keywords',
|
||||
}
|
||||
);
|
||||
|
||||
export const IP_RANGE_RADIO = i18n.translate(
|
||||
'xpack.securitySolution.lists.valueListsForm.ipRangesRadioLabel',
|
||||
{
|
||||
defaultMessage: 'IP ranges',
|
||||
}
|
||||
);
|
||||
|
||||
export const TEXT_RADIO = i18n.translate(
|
||||
'xpack.securitySolution.lists.valueListsForm.textRadioLabel',
|
||||
{
|
||||
defaultMessage: 'Text',
|
||||
}
|
||||
);
|
||||
|
|
|
@ -205,6 +205,7 @@ const RulesPageComponent: React.FC = () => {
|
|||
)}
|
||||
<EuiFlexItem grow={false}>
|
||||
<EuiButton
|
||||
data-test-subj="open-value-lists-modal-button"
|
||||
iconType="importAction"
|
||||
isDisabled={userHasNoPermissions(canUserCRUD) || loading}
|
||||
onClick={showValueListsModal}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue