[Security Solutions] Fixes flake with cypress tests (#97329)

## Summary

Fixes some recent flakeyness with Cypress tests
* Adds cypress.pipe() on button clicks around the area of flakes
* Adds an alerting threshold to the utilities so we can wait for when an exact number of alerts are available on a page
* Changes the alerts to not run again with 10 seconds, because if a test takes longer than 10 seconds, the rule can run a second time which can invalidate some of the text when running checks when timeline or other components update on their button clicks.

### Checklist

- [x] [Unit or functional tests](https://www.elastic.co/guide/en/kibana/master/development-tests.html) were updated or added to match the most common scenarios
This commit is contained in:
Frank Hassanabad 2021-04-16 13:52:35 -06:00 committed by GitHub
parent 1cbdb26cea
commit 721f4b55f5
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 38 additions and 21 deletions

View file

@ -32,7 +32,7 @@ describe('Alerts timeline', () => {
waitForAlertsIndexToBeCreated();
createCustomRuleActivated(newRule);
refreshPage();
waitForAlertsToPopulate();
waitForAlertsToPopulate(500);
// Then we login as read-only user to test.
login(ROLES.reader);

View file

@ -39,9 +39,9 @@ describe('Closing alerts', () => {
loginAndWaitForPage(DETECTIONS_URL);
waitForAlertsPanelToBeLoaded();
waitForAlertsIndexToBeCreated();
createCustomRuleActivated(newRule);
createCustomRuleActivated(newRule, '1', '100m', 100);
refreshPage();
waitForAlertsToPopulate();
waitForAlertsToPopulate(100);
deleteCustomRule();
});

View file

@ -38,7 +38,7 @@ describe('Marking alerts as in-progress', () => {
waitForAlertsIndexToBeCreated();
createCustomRuleActivated(newRule);
refreshPage();
waitForAlertsToPopulate();
waitForAlertsToPopulate(500);
});
it('Mark one alert in progress when more than one open alerts are selected', () => {

View file

@ -29,7 +29,7 @@ describe('Alerts timeline', () => {
waitForAlertsIndexToBeCreated();
createCustomRuleActivated(newRule);
refreshPage();
waitForAlertsToPopulate();
waitForAlertsToPopulate(500);
});
it('Investigate alert in default timeline', () => {

View file

@ -39,7 +39,7 @@ describe('Opening alerts', () => {
waitForAlertsIndexToBeCreated();
createCustomRuleActivated(newRule);
refreshPage();
waitForAlertsToPopulate();
waitForAlertsToPopulate(500);
selectNumberOfAlerts(5);
cy.get(SELECTED_ALERTS).should('have.text', `Selected 5 alerts`);

View file

@ -43,7 +43,7 @@ describe('From alert', () => {
cleanKibana();
loginAndWaitForPageWithoutDateRange(DETECTIONS_URL);
waitForAlertsIndexToBeCreated();
createCustomRule(newRule);
createCustomRule(newRule, 'rule_testing', '10s');
goToManageAlertsDetectionRules();
goToRuleDetails();

View file

@ -41,7 +41,7 @@ describe('From rule', () => {
cleanKibana();
loginAndWaitForPageWithoutDateRange(DETECTIONS_URL);
waitForAlertsIndexToBeCreated();
createCustomRule(newRule);
createCustomRule(newRule, 'rule_testing', '10s');
goToManageAlertsDetectionRules();
goToRuleDetails();

View file

@ -185,7 +185,7 @@ export const existingRule: CustomRule = {
name: 'Rule 1',
description: 'Description for Rule 1',
index: ['auditbeat-*'],
interval: '10s',
interval: '100m',
severity: 'High',
riskScore: '19',
tags: ['rule1'],
@ -332,5 +332,5 @@ export const editedRule = {
export const expectedExportedRule = (ruleResponse: Cypress.Response) => {
const jsonrule = ruleResponse.body;
return `{"id":"${jsonrule.id}","updated_at":"${jsonrule.updated_at}","updated_by":"elastic","created_at":"${jsonrule.created_at}","created_by":"elastic","name":"${jsonrule.name}","tags":[],"interval":"10s","enabled":false,"description":"${jsonrule.description}","risk_score":${jsonrule.risk_score},"severity":"${jsonrule.severity}","output_index":".siem-signals-default","author":[],"false_positives":[],"from":"now-17520h","rule_id":"rule_testing","max_signals":100,"risk_score_mapping":[],"severity_mapping":[],"threat":[],"to":"now","references":[],"version":1,"exceptions_list":[],"immutable":false,"type":"query","language":"kuery","index":["exceptions-*"],"query":"${jsonrule.query}","throttle":"no_actions","actions":[]}\n{"exported_count":1,"missing_rules":[],"missing_rules_count":0}\n`;
return `{"id":"${jsonrule.id}","updated_at":"${jsonrule.updated_at}","updated_by":"elastic","created_at":"${jsonrule.created_at}","created_by":"elastic","name":"${jsonrule.name}","tags":[],"interval":"100m","enabled":false,"description":"${jsonrule.description}","risk_score":${jsonrule.risk_score},"severity":"${jsonrule.severity}","output_index":".siem-signals-default","author":[],"false_positives":[],"from":"now-17520h","rule_id":"rule_testing","max_signals":100,"risk_score_mapping":[],"severity_mapping":[],"threat":[],"to":"now","references":[],"version":1,"exceptions_list":[],"immutable":false,"type":"query","language":"kuery","index":["exceptions-*"],"query":"${jsonrule.query}","throttle":"no_actions","actions":[]}\n{"exported_count":1,"missing_rules":[],"missing_rules_count":0}\n`;
};

View file

@ -35,13 +35,25 @@ export const addExceptionFromFirstAlert = () => {
};
export const closeFirstAlert = () => {
cy.get(TIMELINE_CONTEXT_MENU_BTN).first().click({ force: true });
cy.get(CLOSE_ALERT_BTN).click();
cy.get(TIMELINE_CONTEXT_MENU_BTN)
.first()
.pipe(($el) => $el.trigger('click'))
.should('be.visible');
cy.get(CLOSE_ALERT_BTN)
.pipe(($el) => $el.trigger('click'))
.should('not.be.visible');
};
export const closeAlerts = () => {
cy.get(TAKE_ACTION_POPOVER_BTN).click({ force: true });
cy.get(CLOSE_SELECTED_ALERTS_BTN).click();
cy.get(TAKE_ACTION_POPOVER_BTN)
.first()
.pipe(($el) => $el.trigger('click'))
.should('be.visible');
cy.get(CLOSE_SELECTED_ALERTS_BTN)
.pipe(($el) => $el.trigger('click'))
.should('not.be.visible');
};
export const expandFirstAlert = () => {

View file

@ -7,7 +7,7 @@
import { CustomRule, ThreatIndicatorRule } from '../../objects/rule';
export const createCustomRule = (rule: CustomRule, ruleId = 'rule_testing') =>
export const createCustomRule = (rule: CustomRule, ruleId = 'rule_testing', interval = '100m') =>
cy.request({
method: 'POST',
url: 'api/detection_engine/rules',
@ -15,7 +15,7 @@ export const createCustomRule = (rule: CustomRule, ruleId = 'rule_testing') =>
rule_id: ruleId,
risk_score: parseInt(rule.riskScore, 10),
description: rule.description,
interval: '10s',
interval,
name: rule.name,
severity: rule.severity.toLocaleLowerCase(),
type: 'query',
@ -67,7 +67,12 @@ export const createCustomIndicatorRule = (rule: ThreatIndicatorRule, ruleId = 'r
failOnStatusCode: false,
});
export const createCustomRuleActivated = (rule: CustomRule, ruleId = '1') =>
export const createCustomRuleActivated = (
rule: CustomRule,
ruleId = '1',
interval = '100m',
maxSignals = 500
) =>
cy.request({
method: 'POST',
url: 'api/detection_engine/rules',
@ -75,7 +80,7 @@ export const createCustomRuleActivated = (rule: CustomRule, ruleId = '1') =>
rule_id: ruleId,
risk_score: parseInt(rule.riskScore, 10),
description: rule.description,
interval: '10s',
interval,
name: rule.name,
severity: rule.severity.toLocaleLowerCase(),
type: 'query',
@ -85,7 +90,7 @@ export const createCustomRuleActivated = (rule: CustomRule, ruleId = '1') =>
language: 'kuery',
enabled: true,
tags: ['rule1'],
max_signals: 500,
max_signals: maxSignals,
},
headers: { 'kbn-xsrf': 'cypress-creds' },
failOnStatusCode: false,

View file

@ -479,7 +479,7 @@ export const selectThresholdRuleType = () => {
cy.get(THRESHOLD_TYPE).click({ force: true });
};
export const waitForAlertsToPopulate = async () => {
export const waitForAlertsToPopulate = async (alertCountThreshold = 1) => {
cy.waitUntil(
() => {
refreshPage();
@ -488,7 +488,7 @@ export const waitForAlertsToPopulate = async () => {
.invoke('text')
.then((countText) => {
const alertCount = parseInt(countText, 10) || 0;
return alertCount > 0;
return alertCount >= alertCountThreshold;
});
},
{ interval: 500, timeout: 12000 }