[SIEM] Adds 'Create new rule' Cypress test (#59790)

* adds 'Creates and activates new rule'

* loads data using es_archive

* refactor test
This commit is contained in:
MadameSheema 2020-03-10 21:03:48 +01:00 committed by GitHub
parent 29eda20237
commit 0f71886f83
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 481 additions and 12 deletions

View file

@ -4,10 +4,46 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { ELASTIC_RULES_BTN, RULES_TABLE, RULES_ROW } from '../screens/signal_detection_rules';
import { newRule } from '../objects/rule';
import {
ABOUT_DESCRIPTION,
ABOUT_EXPECTED_URLS,
ABOUT_FALSE_POSITIVES,
ABOUT_MITRE,
ABOUT_RISK,
ABOUT_RULE_DESCRIPTION,
ABOUT_SEVERITY,
ABOUT_TAGS,
ABOUT_TIMELINE,
DEFINITION_CUSTOM_QUERY,
DEFINITION_DESCRIPTION,
DEFINITION_INDEX_PATTERNS,
RULE_NAME_HEADER,
SCHEDULE_DESCRIPTION,
SCHEDULE_LOOPBACK,
SCHEDULE_RUNS,
} from '../screens/rule_details';
import {
CUSTOM_RULES_BTN,
ELASTIC_RULES_BTN,
RISK_SCORE,
RULE_NAME,
RULES_TABLE,
RULES_ROW,
SEVERITY,
} from '../screens/signal_detection_rules';
import {
createAndActivateRule,
fillAboutRuleAndContinue,
fillDefineRuleAndContinue,
} from '../tasks/create_new_rule';
import {
changeToThreeHundredRowsPerPage,
filterByCustomRules,
goToCreateNewRule,
goToRuleDetails,
loadPrebuiltDetectionRules,
waitForLoadElasticPrebuiltDetectionRulesTableToBeLoaded,
waitForPrebuiltDetectionRulesToBeLoaded,
@ -18,19 +54,26 @@ import {
waitForSignalsIndexToBeCreated,
waitForSignalsPanelToBeLoaded,
} from '../tasks/detections';
import { esArchiverLoadEmptyKibana, esArchiverUnloadEmptyKibana } from '../tasks/es_archiver';
import { loginAndWaitForPageWithoutDateRange } from '../tasks/login';
import { DETECTIONS } from '../urls/navigation';
describe('Signal detection rules', () => {
before(() => {
esArchiverLoadEmptyKibana();
loginAndWaitForPageWithoutDateRange(DETECTIONS);
});
it('Loads prebuilt rules', () => {
waitForSignalsPanelToBeLoaded();
waitForSignalsIndexToBeCreated();
goToManageSignalDetectionRules();
waitForLoadElasticPrebuiltDetectionRulesTableToBeLoaded();
});
after(() => {
esArchiverUnloadEmptyKibana();
});
it('Loads prebuilt rules', () => {
loadPrebuiltDetectionRules();
waitForPrebuiltDetectionRulesToBeLoaded();
@ -47,4 +90,128 @@ describe('Signal detection rules', () => {
cy.wrap($table.find(RULES_ROW).length).should('eql', expectedNumberOfRules);
});
});
it('Creates and activates new rule', () => {
goToCreateNewRule();
fillDefineRuleAndContinue(newRule);
fillAboutRuleAndContinue(newRule);
createAndActivateRule();
cy.get(CUSTOM_RULES_BTN)
.invoke('text')
.should('eql', 'Custom rules (1)');
changeToThreeHundredRowsPerPage();
waitForRulesToBeLoaded();
const expectedNumberOfRules = 93;
cy.get(RULES_TABLE).then($table => {
cy.wrap($table.find(RULES_ROW).length).should('eql', expectedNumberOfRules);
});
filterByCustomRules();
cy.get(RULES_TABLE).then($table => {
cy.wrap($table.find(RULES_ROW).length).should('eql', 1);
});
cy.get(RULE_NAME)
.invoke('text')
.should('eql', newRule.name);
cy.get(RISK_SCORE)
.invoke('text')
.should('eql', newRule.riskScore);
cy.get(SEVERITY)
.invoke('text')
.should('eql', newRule.severity);
cy.get('[data-test-subj="rule-switch"]').should('have.attr', 'aria-checked', 'true');
goToRuleDetails();
cy.get(RULE_NAME_HEADER)
.invoke('text')
.should('eql', `${newRule.name} Beta`);
const expectedIndexPatterns = [
'apm-*-transaction*',
'auditbeat-*',
'endgame-*',
'filebeat-*',
'packetbeat-*',
'winlogbeat-*',
];
cy.get(DEFINITION_INDEX_PATTERNS).then(patterns => {
cy.wrap(patterns).each((pattern, index) => {
cy.wrap(pattern)
.invoke('text')
.should('eql', expectedIndexPatterns[index]);
});
});
cy.get(DEFINITION_DESCRIPTION)
.eq(DEFINITION_CUSTOM_QUERY)
.invoke('text')
.should('eql', `${newRule.customQuery} `);
cy.get(ABOUT_DESCRIPTION)
.eq(ABOUT_RULE_DESCRIPTION)
.invoke('text')
.should('eql', newRule.description);
cy.get(ABOUT_DESCRIPTION)
.eq(ABOUT_SEVERITY)
.invoke('text')
.should('eql', newRule.severity);
cy.get(ABOUT_DESCRIPTION)
.eq(ABOUT_RISK)
.invoke('text')
.should('eql', newRule.riskScore);
cy.get(ABOUT_DESCRIPTION)
.eq(ABOUT_TIMELINE)
.invoke('text')
.should('eql', 'Default blank timeline');
let expectedUrls = '';
newRule.referenceUrls.forEach(url => {
expectedUrls = expectedUrls + url;
});
cy.get(ABOUT_DESCRIPTION)
.eq(ABOUT_EXPECTED_URLS)
.invoke('text')
.should('eql', expectedUrls);
let expectedFalsePositives = '';
newRule.falsePositivesExamples.forEach(falsePositive => {
expectedFalsePositives = expectedFalsePositives + falsePositive;
});
cy.get(ABOUT_DESCRIPTION)
.eq(ABOUT_FALSE_POSITIVES)
.invoke('text')
.should('eql', expectedFalsePositives);
let expectedMitre = '';
newRule.mitre.forEach(mitre => {
expectedMitre = expectedMitre + mitre.tactic;
mitre.techniques.forEach(technique => {
expectedMitre = expectedMitre + technique;
});
});
cy.get(ABOUT_DESCRIPTION)
.eq(ABOUT_MITRE)
.invoke('text')
.should('eql', expectedMitre);
let expectedTags = '';
newRule.tags.forEach(tag => {
expectedTags = expectedTags + tag;
});
cy.get(ABOUT_DESCRIPTION)
.eq(ABOUT_TAGS)
.invoke('text')
.should('eql', expectedTags);
cy.get(SCHEDULE_DESCRIPTION)
.eq(SCHEDULE_RUNS)
.invoke('text')
.should('eql', '5m');
cy.get(SCHEDULE_DESCRIPTION)
.eq(SCHEDULE_LOOPBACK)
.invoke('text')
.should('eql', '1m');
});
});

View file

@ -0,0 +1,45 @@
/*
* 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.
*/
interface Mitre {
tactic: string;
techniques: string[];
}
export interface Rule {
customQuery: string;
name: string;
description: string;
severity: string;
riskScore: string;
tags: string[];
timelineTemplate?: string;
referenceUrls: string[];
falsePositivesExamples: string[];
mitre: Mitre[];
}
const mitre1: Mitre = {
tactic: 'Discovery (TA0007)',
techniques: ['Cloud Service Discovery (T1526)', 'File and Directory Discovery (T1083)'],
};
const mitre2: Mitre = {
tactic: 'Execution (TA0002)',
techniques: ['CMSTP (T1191)'],
};
export const newRule: Rule = {
customQuery: 'hosts.name: *',
name: 'New Rule Test',
description: 'The new rule description.',
severity: 'High',
riskScore: '17',
tags: ['test', 'newRule'],
referenceUrls: ['https://www.google.com/', 'https://elastic.co/'],
falsePositivesExamples: ['False1', 'False2'],
mitre: [mitre1, mitre2],
};

View file

@ -0,0 +1,49 @@
/*
* 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 ABOUT_CONTINUE_BTN = '[data-test-subj="about-continue"]';
export const ADD_FALSE_POSITIVE_BTN =
'[data-test-subj="detectionEngineStepAboutRuleFalsePositives"] .euiButtonEmpty__text';
export const ADD_REFERENCE_URL_BTN =
'[data-test-subj="detectionEngineStepAboutRuleReferenceUrls"] .euiButtonEmpty__text';
export const MITRE_BTN = '[data-test-subj="addMitre"]';
export const ADVANCED_SETTINGS_BTN = '[data-test-subj="advancedSettings"] .euiAccordion__button';
export const CREATE_AND_ACTIVATE_BTN = '[data-test-subj="create-activate"]';
export const CUSTOM_QUERY_INPUT = '[data-test-subj="queryInput"]';
export const DEFINE_CONTINUE_BUTTON = '[data-test-subj="continue"]';
export const FALSE_POSITIVES_INPUT =
'[data-test-subj="detectionEngineStepAboutRuleFalsePositives"] input';
export const MITRE_TACTIC = '.euiContextMenuItem__text';
export const MITRE_TACTIC_DROPDOWN = '[data-test-subj="mitreTactic"]';
export const MITRE_TECHNIQUES_INPUT =
'[data-test-subj="mitreTechniques"] [data-test-subj="comboBoxSearchInput"]';
export const REFERENCE_URLS_INPUT =
'[data-test-subj="detectionEngineStepAboutRuleReferenceUrls"] input';
export const RISK_INPUT = '.euiRangeInput';
export const RULE_DESCRIPTION_INPUT =
'[data-test-subj="detectionEngineStepAboutRuleDescription"] [data-test-subj="input"]';
export const RULE_NAME_INPUT =
'[data-test-subj="detectionEngineStepAboutRuleName"] [data-test-subj="input"]';
export const SEVERITY_DROPDOWN = '[data-test-subj="select"]';
export const TAGS_INPUT =
'[data-test-subj="detectionEngineStepAboutRuleTags"] [data-test-subj="comboBoxSearchInput"]';

View file

@ -0,0 +1,39 @@
/*
* 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 ABOUT_DESCRIPTION = '[data-test-subj="aboutRule"] .euiDescriptionList__description';
export const ABOUT_EXPECTED_URLS = 4;
export const ABOUT_FALSE_POSITIVES = 5;
export const ABOUT_MITRE = 6;
export const ABOUT_RULE_DESCRIPTION = 0;
export const ABOUT_RISK = 2;
export const ABOUT_SEVERITY = 1;
export const ABOUT_TAGS = 7;
export const ABOUT_TIMELINE = 3;
export const DEFINITION_CUSTOM_QUERY = 1;
export const DEFINITION_DESCRIPTION =
'[data-test-subj="definition"] .euiDescriptionList__description';
export const DEFINITION_INDEX_PATTERNS =
'[data-test-subj="definition"] .euiDescriptionList__description .euiBadge__text';
export const RULE_NAME_HEADER = '[data-test-subj="header-page-title"]';
export const SCHEDULE_DESCRIPTION = '[data-test-subj="schedule"] .euiDescriptionList__description';
export const SCHEDULE_RUNS = 0;
export const SCHEDULE_LOOPBACK = 1;

View file

@ -4,6 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
export const CREATE_NEW_RULE_BTN = '[data-test-subj="create-new-rule"]';
export const CUSTOM_RULES_BTN = '[data-test-subj="show-custom-rules-filter-button"]';
export const ELASTIC_RULES_BTN = '[data-test-subj="show-elastic-rules-filter-button"]';
export const LOAD_PREBUILT_RULES_BTN = '[data-test-subj="load-prebuilt-rules"]';
@ -15,8 +19,14 @@ export const LOADING_SPINNER = '[data-test-subj="loading-spinner"]';
export const PAGINATION_POPOVER_BTN = '[data-test-subj="tablePaginationPopoverButton"]';
export const RISK_SCORE = '[data-test-subj="riskScore"]';
export const RULE_NAME = '[data-test-subj="ruleName"]';
export const RULES_TABLE = '[data-test-subj="rules-table"]';
export const RULES_ROW = '.euiTableRow';
export const SEVERITY = '[data-test-subj="severity"]';
export const THREE_HUNDRED_ROWS = '[data-test-subj="tablePagination-300-rows"]';

View file

@ -0,0 +1,92 @@
/*
* 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 { Rule } from '../objects/rule';
import {
ABOUT_CONTINUE_BTN,
ADD_FALSE_POSITIVE_BTN,
ADD_REFERENCE_URL_BTN,
ADVANCED_SETTINGS_BTN,
CREATE_AND_ACTIVATE_BTN,
CUSTOM_QUERY_INPUT,
DEFINE_CONTINUE_BUTTON,
FALSE_POSITIVES_INPUT,
MITRE_BTN,
MITRE_TACTIC,
MITRE_TACTIC_DROPDOWN,
MITRE_TECHNIQUES_INPUT,
RISK_INPUT,
REFERENCE_URLS_INPUT,
RULE_DESCRIPTION_INPUT,
RULE_NAME_INPUT,
SEVERITY_DROPDOWN,
TAGS_INPUT,
} from '../screens/create_new_rule';
export const createAndActivateRule = () => {
cy.get(CREATE_AND_ACTIVATE_BTN).click({ force: true });
cy.get(CREATE_AND_ACTIVATE_BTN).should('not.exist');
};
export const fillAboutRuleAndContinue = (rule: Rule) => {
cy.get(RULE_NAME_INPUT).type(rule.name, { force: true });
cy.get(RULE_DESCRIPTION_INPUT).type(rule.description, { force: true });
cy.get(SEVERITY_DROPDOWN).click({ force: true });
cy.get(`#${rule.severity.toLowerCase()}`).click();
cy.get(RISK_INPUT)
.clear({ force: true })
.type(`${rule.riskScore}`, { force: true });
rule.tags.forEach(tag => {
cy.get(TAGS_INPUT).type(`${tag}{enter}`, { force: true });
});
cy.get(ADVANCED_SETTINGS_BTN).click({ force: true });
rule.referenceUrls.forEach((url, index) => {
cy.get(REFERENCE_URLS_INPUT)
.eq(index)
.type(url, { force: true });
cy.get(ADD_REFERENCE_URL_BTN).click({ force: true });
});
rule.falsePositivesExamples.forEach((falsePositive, index) => {
cy.get(FALSE_POSITIVES_INPUT)
.eq(index)
.type(falsePositive, { force: true });
cy.get(ADD_FALSE_POSITIVE_BTN).click({ force: true });
});
rule.mitre.forEach((mitre, index) => {
cy.get(MITRE_TACTIC_DROPDOWN)
.eq(index)
.click({ force: true });
cy.contains(MITRE_TACTIC, mitre.tactic).click();
mitre.techniques.forEach(technique => {
cy.get(MITRE_TECHNIQUES_INPUT)
.eq(index)
.type(`${technique}{enter}`, { force: true });
});
cy.get(MITRE_BTN).click({ force: true });
});
cy.get(ABOUT_CONTINUE_BTN)
.should('exist')
.click({ force: true });
};
export const fillDefineRuleAndContinue = (rule: Rule) => {
cy.get(CUSTOM_QUERY_INPUT).type(rule.customQuery);
cy.get(CUSTOM_QUERY_INPUT).should('have.attr', 'value', rule.customQuery);
cy.get(DEFINE_CONTINUE_BUTTON)
.should('exist')
.click({ force: true });
cy.get(CUSTOM_QUERY_INPUT).should('not.exist');
};

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;
* you may not use this file except in compliance with the Elastic License.
*/
export const esArchiverLoadEmptyKibana = () => {
cy.exec(
`node ../../../../scripts/es_archiver empty_kibana load empty--dir ../../../test/siem_cypress/es_archives --config ../../../../test/functional/config.js --es-url ${Cypress.env(
'ELASTICSEARCH_URL'
)} --kibana-url ${Cypress.config().baseUrl}`
);
};
export const esArchiverUnloadEmptyKibana = () => {
cy.exec(
`node ../../../../scripts/es_archiver empty_kibana unload empty--dir ../../../test/siem_cypress/es_archives --config ../../../../test/functional/config.js --es-url ${Cypress.env(
'ELASTICSEARCH_URL'
)} --kibana-url ${Cypress.config().baseUrl}`
);
};
export const esArchiverResetKibana = () => {
cy.exec(
`node ../../../../scripts/es_archiver empty-kibana-index --config ../../../../test/functional/config.js --es-url ${Cypress.env(
'ELASTICSEARCH_URL'
)} --kibana-url ${Cypress.config().baseUrl}`
);
};

View file

@ -5,6 +5,7 @@
*/
import {
CREATE_NEW_RULE_BTN,
LOAD_PREBUILT_RULES_BTN,
LOADING_INITIAL_PREBUILT_RULES_TABLE,
LOADING_SPINNER,
@ -18,6 +19,22 @@ export const changeToThreeHundredRowsPerPage = () => {
cy.get(THREE_HUNDRED_ROWS).click();
};
export const filterByCustomRules = () => {
cy.get('[data-test-subj="show-custom-rules-filter-button"]').click({ force: true });
cy.get('[data-test-subj="loading-spinner"]').should('exist');
cy.get('[data-test-subj="loading-spinner"]').should('not.exist');
};
export const goToCreateNewRule = () => {
cy.get(CREATE_NEW_RULE_BTN).click({ force: true });
};
export const goToRuleDetails = () => {
cy.get('[data-test-subj="ruleName"]').click({ force: true });
cy.get('.euiLoadingSpinner').should('exist');
cy.get('.euiLoadingSpinner').should('not.exist');
};
export const loadPrebuiltDetectionRules = () => {
cy.get(LOAD_PREBUILT_RULES_BTN)
.should('exist')

View file

@ -11,6 +11,7 @@ import {
EuiLink,
EuiBasicTableColumn,
EuiTableActionsColumnType,
EuiText,
EuiHealth,
} from '@elastic/eui';
import * as H from 'history';
@ -99,7 +100,9 @@ export const getColumns = ({
field: 'name',
name: i18n.COLUMN_RULE,
render: (value: Rule['name'], item: Rule) => (
<EuiLink href={getRuleDetailsUrl(item.id)}>{value}</EuiLink>
<EuiLink data-test-subj="ruleName" href={getRuleDetailsUrl(item.id)}>
{value}
</EuiLink>
),
truncateText: true,
width: '24%',
@ -107,6 +110,11 @@ export const getColumns = ({
{
field: 'risk_score',
name: i18n.COLUMN_RISK_SCORE,
render: (value: Rule['risk_score']) => (
<EuiText data-test-subj="riskScore" size="s">
{value}
</EuiText>
),
truncateText: true,
width: '14%',
},
@ -150,7 +158,7 @@ export const getColumns = ({
field: 'tags',
name: i18n.COLUMN_TAGS,
render: (value: Rule['tags']) => (
<TruncatableText>
<TruncatableText data-test-subj="tags">
{value.map((tag, i) => (
<EuiBadge color="hollow" key={`${tag}-${i}`}>
{tag}
@ -167,6 +175,7 @@ export const getColumns = ({
name: i18n.COLUMN_ACTIVATE,
render: (value: Rule['enabled'], item: Rule) => (
<RuleSwitch
data-test-subj="enabled"
dispatch={dispatch}
id={item.id}
enabled={item.enabled}

View file

@ -69,7 +69,7 @@ const StepRuleDescriptionComponent: React.FC<StepRuleDescriptionProps> = ({
return (
<EuiFlexGroup>
<EuiFlexItem key={`description-step-rule`}>
<EuiFlexItem data-test-subj="definition" key={`description-step-rule`}>
<EuiDescriptionList listItems={listItems} />
</EuiFlexItem>
</EuiFlexGroup>

View file

@ -129,6 +129,7 @@ export const AddMitreThreat = ({ dataTestSubj, field, idAria, isDisabled }: AddI
onChange={updateTactic.bind(null, index)}
fullWidth={false}
valueOfSelected={camelCase(tacticName)}
data-test-subj="mitreTactic"
/>
);
@ -144,6 +145,7 @@ export const AddMitreThreat = ({ dataTestSubj, field, idAria, isDisabled }: AddI
<EuiFlexGroup gutterSize="s" alignItems="center">
<EuiFlexItem grow>
<EuiComboBox
data-test-subj="mitreTechniques"
placeholder={item.tactic.name === 'none' ? '' : i18n.TECHNIQUES_PLACEHOLDER}
options={options}
selectedOptions={selectedOptions}
@ -208,7 +210,7 @@ export const AddMitreThreat = ({ dataTestSubj, field, idAria, isDisabled }: AddI
{values.length - 1 !== index && <EuiSpacer size="s" />}
</div>
))}
<MyAddItemButton onClick={addItem} isDisabled={isDisabled}>
<MyAddItemButton data-test-subj="addMitre" onClick={addItem} isDisabled={isDisabled}>
{i18n.ADD_MITRE_ATTACK}
</MyAddItemButton>
</MitreContainer>

View file

@ -15,6 +15,7 @@ interface Props {
const SeverityBadgeComponent: React.FC<Props> = ({ value }) => (
<EuiHealth
data-test-subj="severity"
color={
value === 'low'
? euiLightVars.euiColorVis0

View file

@ -126,7 +126,7 @@ const StepAboutRuleComponent: FC<StepAboutRuleProps> = ({
) : (
<>
<StepContentWrapper addPadding={!isUpdateView}>
<Form form={form} data-test-subj="stepAboutRule">
<Form form={form}>
<CommonUseField
path="name"
componentProps={{
@ -198,6 +198,7 @@ const StepAboutRuleComponent: FC<StepAboutRuleProps> = ({
</TagContainer>
<EuiSpacer size="m" />
<AdvancedSettingsAccordion
data-test-subj="advancedSettings"
id="advancedSettingsAccordion"
buttonContent={AdvancedSettingsAccordionButton}
>
@ -269,7 +270,12 @@ const StepAboutRuleComponent: FC<StepAboutRuleProps> = ({
responsive={false}
>
<EuiFlexItem grow={false}>
<EuiButton fill onClick={onSubmit} isDisabled={isLoading}>
<EuiButton
data-test-subj="about-continue"
fill
onClick={onSubmit}
isDisabled={isLoading}
>
{RuleI18n.CONTINUE}
</EuiButton>
</EuiFlexItem>

View file

@ -238,7 +238,7 @@ const StepDefineRuleComponent: FC<StepDefineRuleProps> = ({
responsive={false}
>
<EuiFlexItem grow={false}>
<EuiButton fill onClick={onSubmit} isDisabled={isLoading}>
<EuiButton fill onClick={onSubmit} isDisabled={isLoading} data-test-subj="continue">
{RuleI18n.CONTINUE}
</EuiButton>
</EuiFlexItem>

View file

@ -133,6 +133,7 @@ const StepScheduleRuleComponent: FC<StepScheduleRuleProps> = ({
isDisabled={isLoading}
isLoading={isLoading}
onClick={onSubmit.bind(null, true)}
data-test-subj="create-activate"
>
{I18n.COMPLETE_WITH_ACTIVATING}
</EuiButton>

View file

@ -309,7 +309,7 @@ const RuleDetailsPageComponent: FC<PropsFromRedux> = ({
</StepPanel>
</EuiFlexItem>
<EuiFlexItem component="section" grow={2}>
<EuiFlexItem data-test-subj="aboutRule" component="section" grow={2}>
<StepPanel loading={isLoading} title={ruleI18n.ABOUT}>
{aboutRuleData != null && (
<StepAboutRule
@ -322,7 +322,7 @@ const RuleDetailsPageComponent: FC<PropsFromRedux> = ({
</StepPanel>
</EuiFlexItem>
<EuiFlexItem component="section" grow={1}>
<EuiFlexItem data-test-subj="schedule" component="section" grow={1}>
<StepPanel loading={isLoading} title={ruleI18n.SCHEDULE}>
{scheduleRuleData != null && (
<StepScheduleRule

View file

@ -147,6 +147,7 @@ const RulesPageComponent: React.FC = () => {
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiButton
data-test-subj="create-new-rule"
fill
href={getCreateRuleUrl()}
iconType="plusInCircle"

View file

@ -27,6 +27,7 @@ export async function SiemCypressTestRunner({ getService }: FtrProviderContext)
env: {
FORCE_COLOR: '1',
CYPRESS_baseUrl: Url.format(config.get('servers.kibana')),
CYPRESS_ELASTICSEARCH_URL: Url.format(config.get('servers.elasticsearch')),
CYPRESS_ELASTICSEARCH_USERNAME: config.get('servers.elasticsearch.username'),
CYPRESS_ELASTICSEARCH_PASSWORD: config.get('servers.elasticsearch.password'),
...process.env,