Skip to content

Commit

Permalink
[Security Solution] [Sourcerer] Cypress tests (#80410)
Browse files Browse the repository at this point in the history
  • Loading branch information
stephmilovic authored Dec 14, 2020
1 parent 8279c2d commit 59b18a2
Show file tree
Hide file tree
Showing 4 changed files with 281 additions and 7 deletions.
105 changes: 105 additions & 0 deletions x-pack/plugins/security_solution/cypress/integration/sourcerer.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* 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 { loginAndWaitForPage } from '../tasks/login';

import { HOSTS_URL } from '../urls/navigation';
import { waitForAllHostsToBeLoaded } from '../tasks/hosts/all_hosts';
import {
clickOutOfSourcererTimeline,
clickTimelineRadio,
deselectSourcererOptions,
isCustomRadio,
isHostsStatValue,
isNotCustomRadio,
isNotSourcererSelection,
isSourcererOptions,
isSourcererSelection,
openSourcerer,
resetSourcerer,
setSourcererOption,
unsetSourcererOption,
} from '../tasks/sourcerer';
import { openTimelineUsingToggle } from '../tasks/security_main';
import { populateTimeline } from '../tasks/timeline';
import { SERVER_SIDE_EVENT_COUNT } from '../screens/timeline';

describe('Sourcerer', () => {
beforeEach(() => {
loginAndWaitForPage(HOSTS_URL);
});
describe('Default scope', () => {
it('has SIEM index patterns selected on initial load', () => {
openSourcerer();
isSourcererSelection(`auditbeat-*`);
});

it('has Kibana index patterns in the options', () => {
openSourcerer();
isSourcererOptions([`metrics-*`, `logs-*`]);
});
it('selected KIP gets added to sourcerer', () => {
setSourcererOption(`metrics-*`);
openSourcerer();
isSourcererSelection(`metrics-*`);
});

it('does not return data without correct pattern selected', () => {
waitForAllHostsToBeLoaded();
isHostsStatValue('4 ');
setSourcererOption(`metrics-*`);
unsetSourcererOption(`auditbeat-*`);
isHostsStatValue('0 ');
});

it('reset button restores to original state', () => {
setSourcererOption(`metrics-*`);
openSourcerer();
isSourcererSelection(`metrics-*`);
resetSourcerer();
openSourcerer();
isNotSourcererSelection(`metrics-*`);
});
});
describe('Timeline scope', () => {
const alertPatterns = ['.siem-signals-default'];
const rawPatterns = ['auditbeat-*'];
const allPatterns = [...alertPatterns, ...rawPatterns];
it('Radio buttons select correct sourcerer patterns', () => {
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'));
});
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();
});
it('Selected index patterns are properly queried', () => {
openTimelineUsingToggle();
populateTimeline();
openSourcerer('timeline');
deselectSourcererOptions(rawPatterns, 'timeline');
cy.get(SERVER_SIDE_EVENT_COUNT)
.invoke('text')
.then((strCount) => {
const intCount = +strCount;
cy.wrap(intCount).should('eq', 0);
});
});
});
});
30 changes: 30 additions & 0 deletions x-pack/plugins/security_solution/cypress/screens/sourcerer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
/*
* 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 SOURCERER_TRIGGER = '[data-test-subj="sourcerer-trigger"]';
export const SOURCERER_INPUT =
'[data-test-subj="indexPattern-switcher"] [data-test-subj="comboBoxInput"]';
export const SOURCERER_OPTIONS =
'[data-test-subj="comboBoxOptionsList indexPattern-switcher-optionsList"]';
export const SOURCERER_SAVE_BUTTON = 'button[data-test-subj="add-index"]';
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_TIMELINE_ADVANCED = '[data-test-subj="advanced-settings"]';
136 changes: 136 additions & 0 deletions x-pack/plugins/security_solution/cypress/tasks/sourcerer.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
/*
* 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 {
HOSTS_STAT,
SOURCERER_INPUT,
SOURCERER_OPTIONS,
SOURCERER_POPOVER_TITLE,
SOURCERER_RESET_BUTTON,
SOURCERER_SAVE_BUTTON,
SOURCERER_TIMELINE,
SOURCERER_TRIGGER,
} from '../screens/sourcerer';
import { TIMELINE_TITLE } from '../screens/timeline';

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();
};
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);
});
};
export const openAdvancedSettings = () => {};

export const clickOutOfSelector = () => {
return cy.get(SOURCERER_POPOVER_TITLE).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 isSourcererSelection = (patternName: string, sourcererScope?: string) => {
const { input } = getScopedSelectors(sourcererScope);
return cy.get(input).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 isSourcererOptions = (patternNames: string[], sourcererScope?: string) => {
const { input, options } = getScopedSelectors(sourcererScope);
cy.get(input).click();
return patternNames.every((patternName) => {
return cy
.get(options)
.find(`button.euiFilterSelectItem[title="${patternName}"]`)
.its('length')
.should('eq', 1);
});
};

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();
clickOutOfSelector();
return cy.get(SOURCERER_SAVE_BUTTON).click({ force: true });
};

export const deselectSourcererOption = (patternName: string, sourcererScope?: string) => {
const { input } = getScopedSelectors(sourcererScope);
cy.get(input).find(`span[title="${patternName}"] button`).click();
clickOutOfSelector();
return cy.get(SOURCERER_SAVE_BUTTON).click({ force: true });
};

export const deselectSourcererOptions = (patternNames: string[], sourcererScope?: string) => {
const { input } = getScopedSelectors(sourcererScope);
patternNames.forEach((patternName) =>
cy.get(input).find(`span[title="${patternName}"] button`).click()
);
clickOutOfSelector();
return cy.get(SOURCERER_SAVE_BUTTON).click({ force: true });
};

export const resetSourcerer = () => {
cy.get(SOURCERER_RESET_BUTTON).click();
clickOutOfSelector();
return cy.get(SOURCERER_SAVE_BUTTON).click({ force: true });
};

export const setSourcererOption = (patternName: string, sourcererScope?: string) => {
openSourcerer(sourcererScope);
isNotSourcererSelection(patternName, sourcererScope);
selectSourcererOption(patternName, sourcererScope);
};

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');
};

export const clickOutOfSourcererTimeline = () => cy.get(TIMELINE_TITLE).first().click();
Original file line number Diff line number Diff line change
Expand Up @@ -251,12 +251,13 @@ const PickEventTypeComponents: React.FC<PickEventTypeProps> = ({
const comboBox = useMemo(
() => (
<EuiComboBox
placeholder={i18n.PICK_INDEX_PATTERNS}
data-test-subj="timeline-sourcerer"
fullWidth
options={indexesPatternOptions}
selectedOptions={selectedOptions}
onChange={onChangeCombo}
options={indexesPatternOptions}
placeholder={i18n.PICK_INDEX_PATTERNS}
renderOption={renderOption}
selectedOptions={selectedOptions}
/>
),
[onChangeCombo, indexesPatternOptions, renderOption, selectedOptions]
Expand All @@ -269,6 +270,7 @@ const PickEventTypeComponents: React.FC<PickEventTypeProps> = ({
const filter = useMemo(
() => (
<Filter
data-test-subj="timeline-sourcerer-radio"
options={filterOptions}
idSelected={filterEventType}
onChange={onChangeFilter}
Expand All @@ -282,6 +284,7 @@ const PickEventTypeComponents: React.FC<PickEventTypeProps> = ({
const options = getEventTypeOptions();
return (
<MyEuiButton
data-test-subj="sourcerer-timeline-trigger"
iconType="arrowDown"
iconSide="right"
isLoading={sourcererScope.loading}
Expand All @@ -299,7 +302,7 @@ const PickEventTypeComponents: React.FC<PickEventTypeProps> = ({

const ButtonContent = useMemo(
() => (
<AdvancedSettings>
<AdvancedSettings data-test-subj="advanced-settings">
{showAdvanceSettings
? i18n.HIDE_INDEX_PATTERNS_ADVANCED_SETTINGS
: i18n.SHOW_INDEX_PATTERNS_ADVANCED_SETTINGS}
Expand Down Expand Up @@ -330,11 +333,11 @@ const PickEventTypeComponents: React.FC<PickEventTypeProps> = ({
<PickEventContainer>
<EuiToolTip position="top" content={tooltipContent}>
<EuiPopover
id="popover"
ownFocus
button={button}
isOpen={isPopoverOpen}
closePopover={closePopover}
id="popover"
isOpen={isPopoverOpen}
ownFocus
repositionOnScroll
>
<PopoverContent>
Expand Down

0 comments on commit 59b18a2

Please sign in to comment.