From 2c843df140c2996793d64840758492853e37d176 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Tue, 9 Jan 2024 22:47:50 +0100 Subject: [PATCH] [SecuritySolution] Fix flaky timeline creation tests (role-based issues) (#173413) --- .../alerts/ransomware_detection.cy.ts | 4 +- .../investigations/timelines/creation.cy.ts | 82 +++++++++---------- .../cypress/screens/timeline.ts | 4 +- .../cypress/tasks/security_main.ts | 16 +++- .../cypress/tasks/timeline.ts | 11 +-- .../cypress/tasks/timelines.ts | 4 - 6 files changed, 59 insertions(+), 62 deletions(-) diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/ransomware_detection.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/ransomware_detection.cy.ts index 3d51fb2f595be..c8da8308b76a4 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/ransomware_detection.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/alerts/ransomware_detection.cy.ts @@ -13,7 +13,7 @@ import { ALERTS_URL, TIMELINES_URL } from '../../../urls/navigation'; import { ALERTS_HISTOGRAM_SERIES, ALERT_RULE_NAME, MESSAGE } from '../../../screens/alerts'; import { TIMELINE_QUERY, TIMELINE_VIEW_IN_ANALYZER } from '../../../screens/timeline'; import { selectAlertsHistogram } from '../../../tasks/alerts'; -import { createTimeline } from '../../../tasks/timelines'; +import { openTimelineUsingToggle } from '../../../tasks/security_main'; import { deleteTimelines } from '../../../tasks/api_calls/common'; describe('Ransomware Detection Alerts', { tags: ['@ess', '@serverless'] }, () => { @@ -53,10 +53,10 @@ describe('Ransomware Detection Alerts', { tags: ['@ess', '@serverless'] }, () => deleteTimelines(); login(); visitWithTimeRange(TIMELINES_URL); - createTimeline(); }); it('should show ransomware entries in timelines table', () => { + openTimelineUsingToggle(); cy.get(TIMELINE_QUERY).type('event.code: "ransomware"{enter}'); // Wait for grid to load, it should have an analyzer icon diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/creation.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/creation.cy.ts index d048eb2155ef6..fe47cf3a538cb 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/creation.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/creation.cy.ts @@ -45,18 +45,17 @@ import { addNameToTimelineAndSave, addNameToTimelineAndSaveAsNew, } from '../../../tasks/timeline'; -import { createTimeline } from '../../../tasks/timelines'; +import { waitForTimelinesPanelToBeLoaded } from '../../../tasks/timelines'; import { OVERVIEW_URL, TIMELINE_TEMPLATES_URL, TIMELINES_URL } from '../../../urls/navigation'; -// FLAKY: https://github.com/elastic/kibana/issues/173339 -describe.skip('Timelines', { tags: ['@ess', '@serverless'] }, (): void => { +describe('Timelines', { tags: ['@ess', '@serverless'] }, (): void => { beforeEach(() => { - login(); deleteTimelines(); }); - it('creates a timeline from a template and should have the same query and open the timeline modal', () => { + it('should create a timeline from a template and should have the same query and open the timeline modal', () => { + login(); createTimelineTemplate(getTimeline()); visit(TIMELINE_TEMPLATES_URL); selectCustomTemplates(); @@ -64,46 +63,35 @@ describe.skip('Timelines', { tags: ['@ess', '@serverless'] }, (): void => { clickingOnCreateTimelineFormTemplateBtn(); cy.get(TIMELINE_FLYOUT_WRAPPER).should('have.css', 'visibility', 'visible'); cy.get(TIMELINE_QUERY).should('have.text', getTimeline().query); - closeTimeline(); }); - describe('Toggle create timeline from "New" btn', () => { - context('Privileges: CRUD', () => { - beforeEach(() => { - login(); - visitWithTimeRange(OVERVIEW_URL); - }); - - it('toggle create timeline ', () => { - openTimelineUsingToggle(); - createNewTimeline(); - addNameAndDescriptionToTimeline(getTimeline()); - cy.get(TIMELINE_PANEL).should('be.visible'); - }); - }); - - context('Privileges: READ', () => { - beforeEach(() => { - login(ROLES.t1_analyst); - visitWithTimeRange(OVERVIEW_URL); - }); - - it('should not be able to create/update timeline ', () => { - openTimelineUsingToggle(); - createNewTimeline(); - cy.get(TIMELINE_PANEL).should('be.visible'); - cy.get(SAVE_TIMELINE_ACTION_BTN).should('be.disabled'); - cy.get(SAVE_TIMELINE_ACTION_BTN).first().realHover(); - cy.get(SAVE_TIMELINE_TOOLTIP).should('be.visible'); - cy.get(SAVE_TIMELINE_TOOLTIP).should( - 'have.text', - 'You can use Timeline to investigate events, but you do not have the required permissions to save timelines for future use. If you need to save timelines, contact your Kibana administrator.' - ); - }); - }); + it('should be able to create timeline with crud privileges', () => { + login(); + visitWithTimeRange(OVERVIEW_URL); + openTimelineUsingToggle(); + createNewTimeline(); + addNameAndDescriptionToTimeline(getTimeline()); + cy.get(TIMELINE_PANEL).should('be.visible'); + }); + + it('should not be able to create/update timeline with only read privileges', () => { + login(ROLES.t1_analyst); + visitWithTimeRange(TIMELINES_URL); + waitForTimelinesPanelToBeLoaded(); + openTimelineUsingToggle(); + createNewTimeline(); + cy.get(TIMELINE_PANEL).should('be.visible'); + cy.get(SAVE_TIMELINE_ACTION_BTN).should('be.disabled'); + cy.get(SAVE_TIMELINE_ACTION_BTN).first().realHover(); + cy.get(SAVE_TIMELINE_TOOLTIP).should('be.visible'); + cy.get(SAVE_TIMELINE_TOOLTIP).should( + 'have.text', + 'You can use Timeline to investigate events, but you do not have the required permissions to save timelines for future use. If you need to save timelines, contact your Kibana administrator.' + ); }); - it('creates a timeline by clicking untitled timeline from bottom bar', () => { + it('should create a timeline by clicking untitled timeline from bottom bar', () => { + login(); visitWithTimeRange(OVERVIEW_URL); openTimelineUsingToggle(); addNameAndDescriptionToTimeline(getTimeline()); @@ -126,14 +114,17 @@ describe.skip('Timelines', { tags: ['@ess', '@serverless'] }, (): void => { .should('have.text', getTimeline().notes); }); - it('shows the different timeline states', () => { + it('should show the different timeline states', () => { + login(); visitWithTimeRange(TIMELINES_URL); - createTimeline(); + openTimelineUsingToggle(); // Unsaved cy.get(TIMELINE_PANEL).should('be.visible'); cy.get(TIMELINE_STATUS).should('be.visible'); - cy.get(TIMELINE_STATUS).should('have.text', 'Unsaved'); + cy.get(TIMELINE_STATUS) + .invoke('text') + .should('match', /^Unsaved/); addNameToTimelineAndSave('Test'); @@ -155,10 +146,11 @@ describe.skip('Timelines', { tags: ['@ess', '@serverless'] }, (): void => { }); it('should save timelines as new', () => { + login(); visitWithTimeRange(TIMELINES_URL); cy.get(ROWS).should('have.length', '0'); - createTimeline(); + openTimelineUsingToggle(); addNameToTimelineAndSave('First'); // Offsetting the extra save that is happening in the background diff --git a/x-pack/test/security_solution_cypress/cypress/screens/timeline.ts b/x-pack/test/security_solution_cypress/cypress/screens/timeline.ts index 2794a111e94c2..c6d6b14fcdfd1 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/timeline.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/timeline.ts @@ -30,8 +30,6 @@ export const COMBO_BOX_INPUT = '[data-test-subj="comboBoxInput"]'; export const CREATE_NEW_TIMELINE = '[data-test-subj="timeline-new"]'; -export const CREATE_NEW_TIMELINE_WITH_BORDER = '[data-test-subj="timeline-new-with-border"]'; - export const CREATE_NEW_TIMELINE_TEMPLATE = '[data-test-subj="template-timeline-new"]'; export const DATA_PROVIDERS = '.field-value'; @@ -218,6 +216,8 @@ export const TIMELINE_EXIT_FULL_SCREEN_BUTTON = '[data-test-subj="exit-full-scre export const TIMELINE_FLYOUT_WRAPPER = '[data-test-subj="flyout-pane"]'; +export const TIMELINE_WRAPPER = '[data-test-subj="timeline-wrapper"]'; + export const TIMELINE_FULL_SCREEN_BUTTON = '[data-test-subj="full-screen-active"]'; export const TIMELINE_PROGRESS_BAR = '[data-test-subj="progress-bar"]'; diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/security_main.ts b/x-pack/test/security_solution_cypress/cypress/tasks/security_main.ts index 15c171676c958..5b034b0ae4b0e 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/security_main.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/security_main.ts @@ -5,11 +5,23 @@ * 2.0. */ +import { recurse } from 'cypress-recurse'; import { CLOSE_TIMELINE_BUTTON, TIMELINE_BOTTOM_BAR_TOGGLE_BUTTON } from '../screens/security_main'; -import { TIMELINE_EXIT_FULL_SCREEN_BUTTON, TIMELINE_FULL_SCREEN_BUTTON } from '../screens/timeline'; +import { + TIMELINE_EXIT_FULL_SCREEN_BUTTON, + TIMELINE_FULL_SCREEN_BUTTON, + TIMELINE_WRAPPER, +} from '../screens/timeline'; export const openTimelineUsingToggle = () => { - cy.get(TIMELINE_BOTTOM_BAR_TOGGLE_BUTTON).click(); + recurse( + () => { + cy.get(TIMELINE_BOTTOM_BAR_TOGGLE_BUTTON).click(); + return cy.get(TIMELINE_WRAPPER); + }, + // Retry if somehow the timeline wrapper is still hidden + ($timelineWrapper) => !$timelineWrapper.hasClass('timeline-wrapper--hidden') + ); }; export const closeTimelineUsingCloseButton = () => { diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/timeline.ts b/x-pack/test/security_solution_cypress/cypress/tasks/timeline.ts index d9db1f7debcfa..767123c9875b6 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/timeline.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/timeline.ts @@ -180,9 +180,6 @@ export const addNotesToTimeline = (notes: string) => { cy.get(`${NOTES_TAB_BUTTON} .euiBadge`).should('have.text', `${notesCount + 1}`); }); - - goToQueryTab(); - goToNotesTab(); }; export const addEqlToTimeline = (eql: string) => { @@ -303,7 +300,7 @@ export const clickIdToggleField = () => { }; export const closeTimeline = () => { - cy.get(CLOSE_TIMELINE_BTN).filter(':visible').click(); + cy.get(CLOSE_TIMELINE_BTN).click(); cy.get(QUERY_TAB_BUTTON).should('not.be.visible'); }; @@ -409,7 +406,7 @@ export const openActiveTimeline = () => { }; export const pinFirstEvent = (): Cypress.Chainable> => { - return cy.get(PIN_EVENT).first().click({ force: true }); + return cy.get(PIN_EVENT).first().click(); }; export const populateTimeline = () => { @@ -470,11 +467,11 @@ export const refreshTimelinesUntilTimeLinePresent = ( }; export const clickingOnCreateTimelineFormTemplateBtn = () => { - cy.get(TIMELINE_CREATE_TIMELINE_FROM_TEMPLATE_BTN).click({ force: true }); + cy.get(TIMELINE_CREATE_TIMELINE_FROM_TEMPLATE_BTN).click(); }; export const clickingOnCreateTemplateFromTimelineBtn = () => { - cy.get(TIMELINE_CREATE_TEMPLATE_FROM_TIMELINE_BTN).click({ force: true }); + cy.get(TIMELINE_CREATE_TEMPLATE_FROM_TIMELINE_BTN).click(); }; export const expandEventAction = () => { diff --git a/x-pack/test/security_solution_cypress/cypress/tasks/timelines.ts b/x-pack/test/security_solution_cypress/cypress/tasks/timelines.ts index 607b1d3e67978..338017829e9f0 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/timelines.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/timelines.ts @@ -21,7 +21,6 @@ import { } from '../screens/timelines'; import { SELECT_ALL_CHECKBOX } from '../screens/shared'; import { - CREATE_NEW_TIMELINE_WITH_BORDER, TIMELINE_COLLAPSED_ITEMS_BTN, TIMELINE_CREATE_TIMELINE_FROM_TEMPLATE_BTN, } from '../screens/timeline'; @@ -68,9 +67,6 @@ export const exportSelectedTimelines = () => { cy.get(EXPORT_TIMELINE_ACTION).click(); }; -export const createTimeline = () => - cy.get(CREATE_NEW_TIMELINE_WITH_BORDER).should('be.visible').click(); - export const createTimelineFromFirstTemplateInList = () => { cy.get(TIMELINE_COLLAPSED_ITEMS_BTN).first().click(); cy.get(TIMELINE_CREATE_TIMELINE_FROM_TEMPLATE_BTN).click();