[Security Solution] Sourcerer Redesign Cypress tests (#118271) (#121148)

Co-authored-by: Steph Milovic <stephanie.milovic@elastic.co>
This commit is contained in:
Kibana Machine 2021-12-13 21:25:41 -05:00 committed by GitHub
parent 87f7fd0027
commit 6af011eb8b
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
14 changed files with 401 additions and 210 deletions

View file

@ -20,6 +20,7 @@ import { getNewRule } from '../../objects/rule';
import { refreshPage } from '../../tasks/security_header';
import { waitForAlertsToPopulate } from '../../tasks/create_new_rule';
import { openEventsViewerFieldsBrowser } from '../../tasks/hosts/events';
import { assertFieldDisplayed, createField } from '../../tasks/create_runtime_field';
describe('Create DataView runtime field', () => {
before(() => {
@ -36,13 +37,8 @@ describe('Create DataView runtime field', () => {
waitForAlertsToPopulate(500);
openEventsViewerFieldsBrowser();
cy.get('[data-test-subj="create-field"]').click();
cy.get('.indexPatternFieldEditorMaskOverlay').find('[data-test-subj="input"]').type(fieldName);
cy.get('[data-test-subj="fieldSaveButton"]').click();
cy.get(
`[data-test-subj="events-viewer-panel"] [data-test-subj="dataGridHeaderCell-${fieldName}"]`
).should('exist');
createField(fieldName);
assertFieldDisplayed(fieldName, 'alerts');
});
it('adds field to timeline', () => {
@ -53,12 +49,7 @@ describe('Create DataView runtime field', () => {
populateTimeline();
openTimelineFieldsBrowser();
cy.get('[data-test-subj="create-field"]').click();
cy.get('.indexPatternFieldEditorMaskOverlay').find('[data-test-subj="input"]').type(fieldName);
cy.get('[data-test-subj="fieldSaveButton"]').click();
cy.get(`[data-test-subj="timeline"] [data-test-subj="header-text-${fieldName}"]`).should(
'exist'
);
createField(fieldName);
assertFieldDisplayed(fieldName);
});
});

View file

@ -10,37 +10,43 @@ import {
loginWithUserAndWaitForPageWithoutDateRange,
} from '../../tasks/login';
import { HOSTS_URL } from '../../urls/navigation';
import { waitForAllHostsToBeLoaded } from '../../tasks/hosts/all_hosts';
import { HOSTS_URL, TIMELINES_URL } from '../../urls/navigation';
import {
clickOutOfSourcererTimeline,
clickTimelineRadio,
addIndexToDefault,
clickAlertCheckbox,
deleteAlertsIndex,
deselectSourcererOptions,
isCustomRadio,
isDataViewSelection,
isHostsStatValue,
isNotCustomRadio,
isKibanaDataViewOption,
isNotSourcererOption,
isNotSourcererSelection,
isSourcererOptions,
isSourcererSelection,
openAdvancedSettings,
openDataViewSelection,
openSourcerer,
resetSourcerer,
setSourcererOption,
unsetSourcererOption,
saveSourcerer,
waitForAlertsIndexToExist,
} from '../../tasks/sourcerer';
import { cleanKibana, postDataView } from '../../tasks/common';
import { openTimelineUsingToggle } from '../../tasks/security_main';
import { populateTimeline } from '../../tasks/timeline';
import { SERVER_SIDE_EVENT_COUNT } from '../../screens/timeline';
import { cleanKibana } from '../../tasks/common';
import { createUsersAndRoles, secReadCasesAll, secReadCasesAllUser } from '../../tasks/privileges';
import { TOASTER } from '../../screens/configure_cases';
import { DEFAULT_ALERTS_INDEX, DEFAULT_INDEX_PATTERN } from '../../../common/constants';
import { SOURCERER } from '../../screens/sourcerer';
const usersToCreate = [secReadCasesAllUser];
const rolesToCreate = [secReadCasesAll];
// Skipped at the moment as this has flake due to click handler issues. This has been raised with team members
// and the code is being re-worked and then these tests will be unskipped
const siemDataViewTitle = 'Security Default Data View';
const dataViews = ['auditbeat-*,fakebeat-*', 'auditbeat-*,beats*,siem-read*,.kibana*,fakebeat-*'];
describe('Sourcerer', () => {
beforeEach(() => {
before(() => {
cleanKibana();
deleteAlertsIndex();
dataViews.forEach((dataView: string) => postDataView(dataView));
});
describe('permissions', () => {
before(() => {
@ -51,88 +57,175 @@ describe('Sourcerer', () => {
cy.get(TOASTER).should('have.text', 'Write role required to generate data');
});
});
// Originially written in December 2020, flakey from day1
// has always been skipped with intentions to fix, see note at top of file
describe.skip('Default scope', () => {
describe('Default scope', () => {
beforeEach(() => {
cy.clearLocalStorage();
loginAndWaitForPage(HOSTS_URL);
});
it('has SIEM index patterns selected on initial load', () => {
it('correctly loads SIEM data view', () => {
openSourcerer();
isDataViewSelection(siemDataViewTitle);
openAdvancedSettings();
isSourcererSelection(`auditbeat-*`);
isSourcererOptions(DEFAULT_INDEX_PATTERN.filter((pattern) => pattern !== 'auditbeat-*'));
});
describe('Modified badge', () => {
it('Selecting new data view does not add a modified badge', () => {
cy.get(SOURCERER.badgeModified).should(`not.exist`);
openSourcerer();
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
openDataViewSelection();
isKibanaDataViewOption(dataViews);
cy.get(SOURCERER.selectListDefaultOption).should(`contain`, siemDataViewTitle);
cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
isDataViewSelection(dataViews[1]);
saveSourcerer();
cy.get(SOURCERER.badgeModified).should(`not.exist`);
openSourcerer();
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
});
it('shows modified badge when index patterns change and removes when reset', () => {
openSourcerer();
openDataViewSelection();
cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
isDataViewSelection(dataViews[1]);
openAdvancedSettings();
const patterns = dataViews[1].split(',');
deselectSourcererOptions([patterns[0]]);
saveSourcerer();
cy.get(SOURCERER.badgeModified).should(`exist`);
openSourcerer();
cy.get(SOURCERER.badgeModifiedOption).should(`exist`);
resetSourcerer();
saveSourcerer();
cy.get(SOURCERER.badgeModified).should(`not.exist`);
openSourcerer();
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
isDataViewSelection(siemDataViewTitle);
});
});
it('disables save when no patterns are selected', () => {
openSourcerer();
openAdvancedSettings();
cy.get(SOURCERER.saveButton).should('be.enabled');
deselectSourcererOptions(['auditbeat-*']);
cy.get(SOURCERER.saveButton).should('be.disabled');
});
it('adds a pattern to the default index and correctly filters out auditbeat-*', () => {
openSourcerer();
isSourcererSelection(`auditbeat-*`);
});
it('has Kibana index patterns in the options', () => {
openSourcerer();
isSourcererOptions([`metrics-*`, `logs-*`]);
});
it('selected DATA_VIEW gets added to sourcerer', () => {
setSourcererOption(`metrics-*`);
openSourcerer();
isSourcererSelection(`metrics-*`);
});
it('does not return data without correct pattern selected', () => {
waitForAllHostsToBeLoaded();
isNotSourcererSelection('beats*');
addIndexToDefault('beats*');
isHostsStatValue('4 ');
setSourcererOption(`metrics-*`);
unsetSourcererOption(`auditbeat-*`);
isHostsStatValue('0 ');
});
it('reset button restores to original state', () => {
setSourcererOption(`metrics-*`);
openSourcerer();
isSourcererSelection(`metrics-*`);
resetSourcerer();
openSourcerer();
isNotSourcererSelection(`metrics-*`);
openAdvancedSettings();
isSourcererSelection(`auditbeat-*`);
isSourcererSelection('beats*');
});
});
// Originially written in December 2020, flakey from day1
// has always been skipped with intentions to fix
describe.skip('Timeline scope', () => {
describe('Timeline scope', () => {
beforeEach(() => {
cy.clearLocalStorage();
loginAndWaitForPage(HOSTS_URL);
loginAndWaitForPage(TIMELINES_URL);
});
const alertPatterns = ['.siem-signals-default'];
const rawPatterns = ['auditbeat-*'];
const allPatterns = [...alertPatterns, ...rawPatterns];
it('Radio buttons select correct sourcerer patterns', () => {
it('correctly loads SIEM data view before and after signals index exists', () => {
openTimelineUsingToggle();
openSourcerer('timeline');
allPatterns.forEach((ss) => isSourcererSelection(ss, 'timeline'));
clickTimelineRadio('raw');
rawPatterns.forEach((ss) => isSourcererSelection(ss, 'timeline'));
alertPatterns.forEach((ss) => isNotSourcererSelection(ss, 'timeline'));
clickTimelineRadio('alert');
alertPatterns.forEach((ss) => isSourcererSelection(ss, 'timeline'));
rawPatterns.forEach((ss) => isNotSourcererSelection(ss, 'timeline'));
isDataViewSelection(siemDataViewTitle);
openAdvancedSettings();
isSourcererSelection(`auditbeat-*`);
isNotSourcererSelection(`${DEFAULT_ALERTS_INDEX}-default`);
isSourcererOptions(
[...DEFAULT_INDEX_PATTERN, `${DEFAULT_ALERTS_INDEX}-default`].filter(
(pattern) => pattern !== 'auditbeat-*'
)
);
waitForAlertsIndexToExist();
isSourcererOptions(DEFAULT_INDEX_PATTERN.filter((pattern) => pattern !== 'auditbeat-*'));
isNotSourcererOption(`${DEFAULT_ALERTS_INDEX}-default`);
});
it('Adding an option results in the custom radio becoming active', () => {
openTimelineUsingToggle();
openSourcerer('timeline');
isNotCustomRadio();
clickOutOfSourcererTimeline();
const luckyOption = 'logs-*';
setSourcererOption(luckyOption, 'timeline');
openSourcerer('timeline');
isCustomRadio();
});
describe('Modified badge', () => {
it('Selecting new data view does not add a modified badge', () => {
openTimelineUsingToggle();
cy.get(SOURCERER.badgeModified).should(`not.exist`);
openSourcerer('timeline');
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
openDataViewSelection();
isKibanaDataViewOption(dataViews);
cy.get(SOURCERER.selectListDefaultOption).should(`contain`, siemDataViewTitle);
cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
isDataViewSelection(dataViews[1]);
saveSourcerer();
cy.get(SOURCERER.badgeModified).should(`not.exist`);
openSourcerer('timeline');
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
});
it('Selected index patterns are properly queried', () => {
openTimelineUsingToggle();
populateTimeline();
openSourcerer('timeline');
deselectSourcererOptions(rawPatterns, 'timeline');
cy.get(SERVER_SIDE_EVENT_COUNT).should(($count) => expect(+$count.text()).to.eql(0));
it('shows modified badge when index patterns change and removes when reset', () => {
openTimelineUsingToggle();
openSourcerer('timeline');
openDataViewSelection();
cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
isDataViewSelection(dataViews[1]);
openAdvancedSettings();
const patterns = dataViews[1].split(',');
deselectSourcererOptions([patterns[0]]);
saveSourcerer();
cy.get(SOURCERER.badgeModified).should(`exist`);
openSourcerer('timeline');
cy.get(SOURCERER.badgeModifiedOption).should(`exist`);
resetSourcerer();
saveSourcerer();
cy.get(SOURCERER.badgeModified).should(`not.exist`);
openSourcerer('timeline');
cy.get(SOURCERER.badgeModifiedOption).should(`not.exist`);
isDataViewSelection(siemDataViewTitle);
});
});
describe('Alerts checkbox', () => {
beforeEach(() => {
waitForAlertsIndexToExist();
});
const defaultPatterns = [`auditbeat-*`, `${DEFAULT_ALERTS_INDEX}-default`];
it('alerts checkbox behaves as expected', () => {
isDataViewSelection(siemDataViewTitle);
defaultPatterns.forEach((pattern) => isSourcererSelection(pattern));
openDataViewSelection();
cy.get(SOURCERER.selectListOption).contains(dataViews[1]).click();
isDataViewSelection(dataViews[1]);
dataViews[1]
.split(',')
.filter((pattern) => pattern !== 'fakebeat-*')
.forEach((pattern) => isSourcererSelection(pattern));
clickAlertCheckbox();
isNotSourcererSelection(`auditbeat-*`);
isSourcererSelection(`${DEFAULT_ALERTS_INDEX}-default`);
cy.get(SOURCERER.alertCheckbox).uncheck({ force: true });
defaultPatterns.forEach((pattern) => isSourcererSelection(pattern));
});
it('shows alerts badge when index patterns change and removes when reset', () => {
clickAlertCheckbox();
saveSourcerer();
cy.get(SOURCERER.badgeAlerts).should(`exist`);
openSourcerer('timeline');
cy.get(SOURCERER.badgeAlertsOption).should(`exist`);
resetSourcerer();
saveSourcerer();
cy.get(SOURCERER.badgeAlerts).should(`not.exist`);
openSourcerer('timeline');
cy.get(SOURCERER.badgeAlertsOption).should(`not.exist`);
});
});
});
});

View file

@ -0,0 +1,12 @@
/*
* 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.
*/
export const CREATE_FIELD_BUTTON = '[data-test-subj="create-field"]';
export const RUNTIME_FIELD_INPUT = '.indexPatternFieldEditorMaskOverlay [data-test-subj="input"]';
export const SAVE_FIELD_BUTTON = '[data-test-subj="fieldSaveButton"]';

View file

@ -5,26 +5,28 @@
* 2.0.
*/
export const SOURCERER_TRIGGER = '[data-test-subj="sourcerer-trigger"]';
export const SOURCERER_INPUT =
'[data-test-subj="sourcerer-combo-box"] [data-test-subj="comboBoxInput"]';
export const SOURCERER_OPTIONS =
'[data-test-subj="comboBoxOptionsList sourcerer-combo-box-optionsList"]';
export const SOURCERER_SAVE_BUTTON = 'button[data-test-subj="sourcerer-save"]';
export const SOURCERER_RESET_BUTTON = 'button[data-test-subj="sourcerer-reset"]';
export const SOURCERER_POPOVER_TITLE = '.euiPopoverTitle';
export const HOSTS_STAT = '[data-test-subj="stat-hosts"] [data-test-subj="stat-title"]';
export const SOURCERER_TIMELINE = {
trigger: '[data-test-subj="sourcerer-timeline-trigger"]',
advancedSettings: '[data-test-subj="advanced-settings"]',
sourcerer: '[data-test-subj="timeline-sourcerer"]',
sourcererInput: '[data-test-subj="timeline-sourcerer"] [data-test-subj="comboBoxInput"]',
sourcererOptions: '[data-test-subj="comboBoxOptionsList timeline-sourcerer-optionsList"]',
radioRaw: '[data-test-subj="timeline-sourcerer-radio"] label.euiRadio__label[for="raw"]',
radioAlert: '[data-test-subj="timeline-sourcerer-radio"] label.euiRadio__label[for="alert"]',
radioAll: '[data-test-subj="timeline-sourcerer-radio"] label.euiRadio__label[for="all"]',
radioCustom: '[data-test-subj="timeline-sourcerer-radio"] input.euiRadio__input[id="custom"]',
radioCustomLabel:
'[data-test-subj="timeline-sourcerer-radio"] label.euiRadio__label[for="custom"]',
export const SOURCERER = {
alertCheckbox: '[data-test-subj="sourcerer-alert-only-checkbox"]',
advancedSettings: '[data-test-subj="sourcerer-advanced-options-toggle"]',
comboBoxInput: '[data-test-subj="sourcerer-combo-box"] [data-test-subj="comboBoxInput"]',
comboBoxOptions: '[data-test-subj="sourcerer-combo-option"]',
badgeModified: '[data-test-subj="sourcerer-modified-badge"]',
badgeModifiedOption: '[data-test-subj="security-modified-option-badge"]',
badgeAlerts: '[data-test-subj="sourcerer-alerts-badge"]',
badgeAlertsOption: '[data-test-subj="security-alerts-option-badge"]',
siemDefaultIndexInput:
'[data-test-subj="advancedSetting-editField-securitySolution:defaultIndex"]',
popoverTitle: '[data-test-subj="sourcerer-title"]',
resetButton: 'button[data-test-subj="sourcerer-reset"]',
saveButton: 'button[data-test-subj="sourcerer-save"]',
selectActiveOption: 'button[data-test-subj="sourcerer-select"]',
selectListOption: '.euiSuperSelect__item [data-test-subj="dataView-option-super"]',
selectListDefaultOption: '.euiSuperSelect__item [data-test-subj="security-option-super"]',
tooltip: '[data-test-subj="sourcerer-tooltip"]',
triggerTimeline: '[data-test-subj="timeline-sourcerer-trigger"]',
trigger: '[data-test-subj="sourcerer-trigger"]',
wrapper: '[data-test-subj="sourcerer-popover"]',
wrapperTimeline: '[data-test-subj="timeline-sourcerer-popover"]',
};
export const HOSTS_STAT = '[data-test-subj="stat-hosts"] [data-test-subj="stat-title"]';

View file

@ -136,15 +136,3 @@ export const createSignalsIndex = () => {
headers: { 'kbn-xsrf': 'cypress-creds' },
});
};
export const removeSignalsIndex = () => {
cy.request({ url: '/api/detection_engine/index', failOnStatusCode: false }).then((response) => {
if (response.status === 200) {
cy.request({
method: 'DELETE',
url: `api/detection_engine/index`,
headers: { 'kbn-xsrf': 'delete-signals' },
});
}
});
};

View file

@ -155,6 +155,22 @@ export const deleteCases = () => {
});
};
export const postDataView = (indexPattern: string) => {
cy.request({
method: 'POST',
url: `/api/index_patterns/index_pattern`,
body: {
index_pattern: {
fieldAttrs: '{}',
title: indexPattern,
timeFieldName: '@timestamp',
fields: '{}',
},
},
headers: { 'kbn-xsrf': 'cypress-creds-via-config' },
});
};
export const scrollToBottom = () => cy.scrollTo('bottom');
export const waitForPageToBeLoaded = () => {

View file

@ -0,0 +1,29 @@
/*
* 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 {
CREATE_FIELD_BUTTON,
RUNTIME_FIELD_INPUT,
SAVE_FIELD_BUTTON,
} from '../screens/create_runtime_field';
export const createField = (fieldName: string): Cypress.Chainable<JQuery<HTMLElement>> => {
cy.get(CREATE_FIELD_BUTTON).click();
cy.get(RUNTIME_FIELD_INPUT).type(fieldName);
return cy.get(SAVE_FIELD_BUTTON).click();
};
export const assertFieldDisplayed = (fieldName: string, view: 'alerts' | 'timeline' = 'timeline') =>
view === 'alerts'
? cy
.get(
`[data-test-subj="events-viewer-panel"] [data-test-subj="dataGridHeaderCell-${fieldName}"]`
)
.should('exist')
: cy
.get(`[data-test-subj="timeline"] [data-test-subj="header-text-${fieldName}"]`)
.should('exist');

View file

@ -295,6 +295,12 @@ export const loginAndWaitForPage = (url: string, role?: ROLES) => {
);
cy.get('[data-test-subj="headerGlobalNav"]');
};
export const waitForPage = (url: string) => {
cy.visit(
`${url}?timerange=(global:(linkTo:!(timeline),timerange:(from:1547914976217,fromStr:'2019-01-19T16:22:56.217Z',kind:relative,to:1579537385745,toStr:now)),timeline:(linkTo:!(global),timerange:(from:1547914976217,fromStr:'2019-01-19T16:22:56.217Z',kind:relative,to:1579537385745,toStr:now)))`
);
cy.get('[data-test-subj="headerGlobalNav"]');
};
export const loginAndWaitForPageWithoutDateRange = (url: string, role?: ROLES) => {
login(role);

View file

@ -5,133 +5,179 @@
* 2.0.
*/
import {
HOSTS_STAT,
SOURCERER_INPUT,
SOURCERER_OPTIONS,
SOURCERER_POPOVER_TITLE,
SOURCERER_RESET_BUTTON,
SOURCERER_SAVE_BUTTON,
SOURCERER_TIMELINE,
SOURCERER_TRIGGER,
} from '../screens/sourcerer';
import { HOSTS_STAT, SOURCERER } from '../screens/sourcerer';
import { TIMELINE_TITLE } from '../screens/timeline';
import { HOSTS_URL } from '../urls/navigation';
import { waitForPage } from './login';
import { openTimelineUsingToggle } from './security_main';
import { DEFAULT_ALERTS_INDEX } from '../../common/constants';
import { waitForAlertsIndexToBeCreated } from './alerts';
import { createCustomRuleActivated } from './api_calls/rules';
import { getNewRule } from '../objects/rule';
export const openSourcerer = (sourcererScope?: string) => {
if (sourcererScope != null && sourcererScope === 'timeline') {
return openTimelineSourcerer();
}
cy.get(SOURCERER_TRIGGER).should('be.enabled');
cy.get(SOURCERER_TRIGGER).should('be.visible');
cy.get(SOURCERER_TRIGGER).click();
cy.get(SOURCERER.trigger).should('be.enabled');
cy.get(SOURCERER.trigger).should('be.visible');
cy.get(SOURCERER.trigger).click();
cy.get(SOURCERER.wrapper).should('be.visible');
};
export const openTimelineSourcerer = () => {
cy.get(SOURCERER_TIMELINE.trigger).should('be.enabled');
cy.get(SOURCERER_TIMELINE.trigger).should('be.visible');
cy.get(SOURCERER_TIMELINE.trigger).click();
cy.get(SOURCERER_TIMELINE.advancedSettings).should(($div) => {
if ($div.text() === 'Show Advanced') {
$div.click();
}
expect(true).to.eq(true);
});
cy.get(SOURCERER.triggerTimeline).should('be.enabled');
cy.get(SOURCERER.triggerTimeline).should('be.visible');
cy.get(SOURCERER.triggerTimeline).first().click();
cy.get(SOURCERER.wrapperTimeline).should('be.visible');
};
export const openAdvancedSettings = () => {
cy.get(SOURCERER.advancedSettings).should('be.visible');
cy.get(SOURCERER.advancedSettings).click();
};
export const openAdvancedSettings = () => {};
export const clickOutOfSelector = () => {
return cy.get(SOURCERER_POPOVER_TITLE).first().click();
return cy.get(SOURCERER.popoverTitle).first().click();
};
const getScopedSelectors = (sourcererScope?: string): { input: string; options: string } =>
sourcererScope != null && sourcererScope === 'timeline'
? { input: SOURCERER_TIMELINE.sourcererInput, options: SOURCERER_TIMELINE.sourcererOptions }
: { input: SOURCERER_INPUT, options: SOURCERER_OPTIONS };
export const isDataViewSelection = (dataView: string) => {
return cy.get(SOURCERER.selectActiveOption).should('contain', dataView);
};
export const isSourcererSelection = (patternName: string, sourcererScope?: string) => {
const { input } = getScopedSelectors(sourcererScope);
return cy.get(input).find(`span[title="${patternName}"]`).should('exist');
export const openDataViewSelection = () => cy.get(SOURCERER.selectActiveOption).click();
export const isKibanaDataViewOption = (dataViews: string[]) => {
return dataViews.every((dataView) => {
return cy.get(SOURCERER.selectListOption).should(`contain`, dataView);
});
};
export const isSourcererSelection = (patternName: string) => {
return cy.get(SOURCERER.comboBoxInput).find(`span[title="${patternName}"]`).should('exist');
};
export const isHostsStatValue = (value: string) => {
return cy.get(HOSTS_STAT).first().should('have.text', value);
};
export const isNotSourcererSelection = (patternName: string, sourcererScope?: string) => {
const { input } = getScopedSelectors(sourcererScope);
return cy.get(input).find(`span[title="${patternName}"]`).should('not.exist');
export const isNotSourcererSelection = (patternName: string) => {
return cy.get(SOURCERER.comboBoxInput).find(`span[title="${patternName}"]`).should('not.exist');
};
export const isNotSourcererOption = (patternName: string) => {
return cy
.get(SOURCERER.comboBoxOptions)
.find(`button[title="${patternName}"]`)
.should('not.exist');
};
export const isSourcererOptions = (patternNames: string[], sourcererScope?: string) => {
const { input, options } = getScopedSelectors(sourcererScope);
cy.get(input).click();
export const isSourcererOptions = (patternNames: string[]) => {
cy.get(SOURCERER.comboBoxInput).click();
return patternNames.every((patternName) => {
return cy
.get(options)
.find(`button.euiFilterSelectItem[title="${patternName}"]`)
.its('length')
.should('eq', 1);
return cy.get(SOURCERER.comboBoxOptions).should(`contain`, patternName);
});
};
export const selectSourcererOption = (patternName: string, sourcererScope?: string) => {
const { input, options } = getScopedSelectors(sourcererScope);
cy.get(input).click();
cy.get(options).find(`button.euiFilterSelectItem[title="${patternName}"]`).click();
export const selectSourcererOption = (patternName: string) => {
cy.get(SOURCERER.comboBoxInput).click();
cy.get(SOURCERER.comboBoxOptions)
.find(`button.euiFilterSelectItem[title="${patternName}"]`)
.click();
clickOutOfSelector();
return cy.get(SOURCERER_SAVE_BUTTON).click({ force: true });
return cy.get(SOURCERER.saveButton).click({ force: true });
};
export const deselectSourcererOption = (patternName: string, sourcererScope?: string) => {
const { input } = getScopedSelectors(sourcererScope);
cy.get(input).find(`span[title="${patternName}"] button`).click();
export const deselectSourcererOption = (patternName: string) => {
cy.get(SOURCERER.comboBoxInput).find(`span[title="${patternName}"] button`).click();
clickOutOfSelector();
return cy.get(SOURCERER_SAVE_BUTTON).click({ force: true });
return cy.get(SOURCERER.saveButton).click({ force: true });
};
export const deselectSourcererOptions = (patternNames: string[], sourcererScope?: string) => {
const { input } = getScopedSelectors(sourcererScope);
export const deselectSourcererOptions = (patternNames: string[]) => {
patternNames.forEach((patternName) =>
cy.get(input).find(`span[title="${patternName}"] button`).click()
cy.get(SOURCERER.comboBoxInput).find(`span[title="${patternName}"] button`).click()
);
};
export const saveSourcerer = () => {
clickOutOfSelector();
return cy.get(SOURCERER_SAVE_BUTTON).click({ force: true });
return cy.get(SOURCERER.saveButton).click({ force: true });
};
export const resetSourcerer = () => {
cy.get(SOURCERER_RESET_BUTTON).click();
clickOutOfSelector();
return cy.get(SOURCERER_SAVE_BUTTON).click({ force: true });
return cy.get(SOURCERER.resetButton).click();
};
export const setSourcererOption = (patternName: string, sourcererScope?: string) => {
openSourcerer(sourcererScope);
isNotSourcererSelection(patternName, sourcererScope);
selectSourcererOption(patternName, sourcererScope);
isNotSourcererSelection(patternName);
selectSourcererOption(patternName);
};
export const unsetSourcererOption = (patternName: string, sourcererScope?: string) => {
openSourcerer(sourcererScope);
isSourcererSelection(patternName, sourcererScope);
deselectSourcererOption(patternName, sourcererScope);
};
export const clickTimelineRadio = (radioName: string) => {
let theRadio = SOURCERER_TIMELINE.radioAll;
if (radioName === 'alert') {
theRadio = SOURCERER_TIMELINE.radioAlert;
}
if (radioName === 'raw') {
theRadio = SOURCERER_TIMELINE.radioRaw;
}
return cy.get(theRadio).first().click();
};
export const isCustomRadio = () => {
return cy.get(SOURCERER_TIMELINE.radioCustom).should('be.enabled');
};
export const isNotCustomRadio = () => {
return cy.get(SOURCERER_TIMELINE.radioCustom).should('be.disabled');
isSourcererSelection(patternName);
deselectSourcererOption(patternName);
};
export const clickOutOfSourcererTimeline = () => cy.get(TIMELINE_TITLE).first().click();
export const clickAlertCheckbox = () => cy.get(SOURCERER.alertCheckbox).check({ force: true });
export const addIndexToDefault = (index: string) => {
cy.visit(`/app/management/kibana/settings?query=category:(securitySolution)`);
cy.get(SOURCERER.siemDefaultIndexInput)
.invoke('val')
.then((patterns) => {
cy.get(SOURCERER.siemDefaultIndexInput).type(`${patterns},${index}`);
cy.get('body').then(($body) => {
if ($body.find('[data-test-subj="toastCloseButton]"').length > 0) {
cy.get('[data-test-subj="toastCloseButton]"').click();
}
});
cy.get('button[data-test-subj="advancedSetting-saveButton"]').click();
cy.get('.euiToast .euiButton--primary').click();
waitForPage(HOSTS_URL);
});
};
export const deleteAlertsIndex = () => {
const alertsIndexUrl = `${Cypress.env(
'ELASTICSEARCH_URL'
)}/.internal.alerts-security.alerts-default-000001`;
cy.request({
url: alertsIndexUrl,
method: 'GET',
headers: { 'kbn-xsrf': 'cypress-creds' },
failOnStatusCode: false,
}).then((response) => {
if (response.status === 200) {
cy.request({
url: alertsIndexUrl,
method: 'DELETE',
headers: { 'kbn-xsrf': 'cypress-creds' },
});
}
});
};
export const refreshUntilAlertsIndexExists = async () => {
cy.waitUntil(
() => {
cy.reload();
openTimelineUsingToggle();
openSourcerer('timeline');
openAdvancedSettings();
return cy
.get(SOURCERER.comboBoxInput)
.invoke('text')
.then((txt) => txt.includes(`${DEFAULT_ALERTS_INDEX}-default`));
},
{ interval: 500, timeout: 12000 }
);
};
export const waitForAlertsIndexToExist = () => {
waitForAlertsIndexToBeCreated();
createCustomRuleActivated(getNewRule(), '1', '100m', 100);
refreshUntilAlertsIndexExists();
};

View file

@ -101,14 +101,18 @@ export const getDataViewSelectOptions = ({
<span data-test-subj="security-option-super">
<EuiIcon type="logoSecurity" size="s" /> {i18n.SECURITY_DEFAULT_DATA_VIEW_LABEL}
{isModified && id === dataViewId && (
<StyledBadge>{i18n.MODIFIED_BADGE_TITLE}</StyledBadge>
<StyledBadge data-test-subj="security-modified-option-badge">
{i18n.MODIFIED_BADGE_TITLE}
</StyledBadge>
)}
</span>
) : (
<span data-test-subj="dataView-option-super">
<EuiIcon type="logoKibana" size="s" /> {title}
{isModified && id === dataViewId && (
<StyledBadge>{i18n.MODIFIED_BADGE_TITLE}</StyledBadge>
<StyledBadge data-test-subj="security-modified-option-badge">
{i18n.MODIFIED_BADGE_TITLE}
</StyledBadge>
)}
</span>
),

View file

@ -29,7 +29,7 @@ import { useUpdateDataView } from './use_update_data_view';
import { Trigger } from './trigger';
import { AlertsCheckbox, SaveButtons, SourcererCallout } from './sub_components';
interface SourcererComponentProps {
export interface SourcererComponentProps {
scope: sourcererModel.SourcererScopeName;
}

View file

@ -38,7 +38,11 @@ export const TriggerComponent: FC<Props> = ({
const badge = useMemo(() => {
switch (isModified) {
case 'modified':
return <StyledBadge>{i18n.MODIFIED_BADGE_TITLE}</StyledBadge>;
return (
<StyledBadge data-test-subj="sourcerer-modified-badge">
{i18n.MODIFIED_BADGE_TITLE}
</StyledBadge>
);
case 'alerts':
return (
<StyledBadge data-test-subj="sourcerer-alerts-badge">

View file

@ -50,7 +50,6 @@ export const useDataView = (): { indexFieldsSearch: (selectedDataViewId: string)
},
[dispatch]
);
const indexFieldsSearch = useCallback(
(selectedDataViewId: string) => {
const asyncSearch = async () => {

View file

@ -199,6 +199,7 @@ export const QueryTabContentComponent: React.FC<Props> = ({
// in order to include the exclude filters in the search that are not stored in the timeline
selectedPatterns,
} = useSourcererDataView(SourcererScopeName.timeline);
const { uiSettings } = useKibana().services;
const ACTION_BUTTON_COUNT = 5;