From 71b45bf422b87ff872a817d36dad1be9ace93f35 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 1 Nov 2024 11:38:03 +0100 Subject: [PATCH 1/8] duplicate timelines need to be marked changed if not, we might lose the duplicated timeline when not saved and trying to reload --- .../timelines/components/open_timeline/use_update_timeline.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_update_timeline.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_update_timeline.tsx index 2d380e700f7d3..a0ea9542e5c74 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_update_timeline.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_update_timeline.tsx @@ -53,7 +53,8 @@ export const useUpdateTimeline = () => { }: UpdateTimeline) => { let _timeline = timeline; if (duplicate) { - _timeline = { ...timeline, updated: undefined, changed: undefined, version: null }; + // `changed: true` in this case indicates that the timeline hasn't been saved yet + _timeline = { ...timeline, updated: undefined, changed: true, version: null }; } if (!isEmpty(_timeline.indexNames)) { dispatch( From 69e3e94256a3d4ff48ab1adfbc660ac7d4a0a180 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 1 Nov 2024 14:12:45 +0100 Subject: [PATCH 2/8] fix tests --- .../components/open_timeline/use_update_timeline.test.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_update_timeline.test.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_update_timeline.test.tsx index 10088446c045c..b2c990b12eced 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_update_timeline.test.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_update_timeline.test.tsx @@ -116,7 +116,7 @@ describe('dispatchUpdateTimeline', () => { ...mockTimelineModel, version: null, updated: undefined, - changed: undefined, + changed: true, }, }); }); From 6544eef6db852c3e0fe1b2cdc50a2f5dc4e39475 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 1 Nov 2024 19:08:57 +0100 Subject: [PATCH 3/8] update comment --- .../timelines/components/open_timeline/use_update_timeline.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_update_timeline.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_update_timeline.tsx index a0ea9542e5c74..2927b2365221d 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_update_timeline.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/use_update_timeline.tsx @@ -53,7 +53,8 @@ export const useUpdateTimeline = () => { }: UpdateTimeline) => { let _timeline = timeline; if (duplicate) { - // `changed: true` in this case indicates that the timeline hasn't been saved yet + // Reset the `updated` and `version` fields because a duplicated timeline has not been saved yet. + // The `changed` field is set to true because the duplicated timeline needs to be saved. _timeline = { ...timeline, updated: undefined, changed: true, version: null }; } if (!isEmpty(_timeline.indexNames)) { From 20588a80804af89ddfb3ad46d3c96df7b7bd5e58 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Fri, 1 Nov 2024 19:59:15 +0100 Subject: [PATCH 4/8] add integration test --- .../timelines/unsaved_timeline.cy.ts | 31 +++++++++++++++---- .../cypress/screens/timelines.ts | 2 ++ .../cypress/tasks/timeline.ts | 19 ++++++++++-- 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts index 1c46f8491f986..8eef7b45d30ef 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts @@ -32,16 +32,17 @@ import { } from '../../../tasks/serverless/navigation'; import { addNameToTimelineAndSave, + closeTimeline, createNewTimeline, + duplicateFirstTimeline, populateTimeline, } from '../../../tasks/timeline'; -import { EXPLORE_URL, hostsUrl, MANAGE_URL } from '../../../urls/navigation'; +import { EXPLORE_URL, TIMELINES_URL, MANAGE_URL } from '../../../urls/navigation'; -// FLAKY: https://github.com/elastic/kibana/issues/174068 -describe.skip('[ESS] Save Timeline Prompts', { tags: ['@ess'] }, () => { +describe('[ESS] Save Timeline Prompts', { tags: ['@ess'] }, () => { beforeEach(() => { login(); - visitWithTimeRange(hostsUrl('allHosts')); + visitWithTimeRange(TIMELINES_URL); openTimelineUsingToggle(); createNewTimeline(); /* @@ -58,7 +59,7 @@ describe.skip('[ESS] Save Timeline Prompts', { tags: ['@ess'] }, () => { it('should NOT prompt when navigating with an unchanged & unsaved timeline', () => { openKibanaNavigation(); navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE); - cy.url().should('not.contain', hostsUrl('allHosts')); + cy.url().should('not.contain', TIMELINES_URL); }); it('should prompt when navigating away from security solution with a changed & unsaved timeline', () => { @@ -119,13 +120,22 @@ describe.skip('[ESS] Save Timeline Prompts', { tags: ['@ess'] }, () => { cy.get(TIMELINE_SAVE_MODAL).should('not.exist'); cy.url().should('not.contain', MANAGE_URL); }); + + it('should prompt when a timeline is duplicated but not saved', () => { + addNameToTimelineAndSave('Original'); + closeTimeline(); + duplicateFirstTimeline(); + openKibanaNavigation(); + navigateFromKibanaCollapsibleTo(MANAGE_PAGE); + cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); + }); }); // In serverless it is not possible to use the navigation menu without closing the timeline describe('[serverless] Save Timeline Prompts', { tags: ['@serverless'] }, () => { beforeEach(() => { login(); - visitWithTimeRange(hostsUrl('allHosts')); + visitWithTimeRange(TIMELINES_URL); openTimelineUsingToggle(); createNewTimeline(); /* @@ -201,4 +211,13 @@ describe('[serverless] Save Timeline Prompts', { tags: ['@serverless'] }, () => navigateToExploreUsingBreadcrumb(); // explore has timelines disabled cy.get(APP_LEAVE_CONFIRM_MODAL).should('not.exist'); }); + + it('should prompt when a timeline is duplicated but not saved', () => { + addNameToTimelineAndSave('Original'); + closeTimeline(); + duplicateFirstTimeline(); + openKibanaNavigation(); + navigateFromKibanaCollapsibleTo(MANAGE_PAGE); + cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); + }); }); diff --git a/x-pack/test/security_solution_cypress/cypress/screens/timelines.ts b/x-pack/test/security_solution_cypress/cypress/screens/timelines.ts index f0435a0fa4950..df5c975b21290 100644 --- a/x-pack/test/security_solution_cypress/cypress/screens/timelines.ts +++ b/x-pack/test/security_solution_cypress/cypress/screens/timelines.ts @@ -38,6 +38,8 @@ export const TIMELINES_PINNED_EVENT_COUNT = '[data-test-subj="pinned-event-count export const TIMELINES_TABLE = '[data-test-subj="timelines-table"]'; +export const DUPLICATE_TIMELINE = '[data-test-subj="open-duplicate"]'; + export const TIMELINES_USERNAME = '[data-test-subj="username"]'; export const REFRESH_BUTTON = '[data-test-subj="refreshButton-linkIcon"]'; 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 5866011ec1cbf..56a1214a90529 100644 --- a/x-pack/test/security_solution_cypress/cypress/tasks/timeline.ts +++ b/x-pack/test/security_solution_cypress/cypress/tasks/timeline.ts @@ -91,15 +91,22 @@ import { QUERY_EVENT_COUNT, TIMELINE_ENABLE_DISABLE_ALL_ROW_RENDERER, TIMELINE_DISCOVER_FIELDS_BUTTON, + TIMELINE_TITLE, } from '../screens/timeline'; -import { REFRESH_BUTTON, TIMELINE, TIMELINES_TAB_TEMPLATE } from '../screens/timelines'; +import { + DUPLICATE_TIMELINE, + REFRESH_BUTTON, + TIMELINE, + TIMELINES_TABLE, + TIMELINES_TAB_TEMPLATE, +} from '../screens/timelines'; import { waitForTabToBeLoaded } from './common'; import { closeFieldsBrowser, filterFieldsBrowser } from './fields_browser'; import { TIMELINE_CONTEXT_MENU_BTN } from '../screens/alerts'; import { LOADING_INDICATOR } from '../screens/security_header'; -import { TOASTER } from '../screens/alerts_detection_rules'; +import { COLLAPSED_ACTION_BTN, TOASTER } from '../screens/alerts_detection_rules'; import { RUNTIME_FIELD_INPUT, SAVE_FIELD_BUTTON } from '../screens/create_runtime_field'; const hostExistsQuery = 'host.name: *'; @@ -150,6 +157,14 @@ export const addNameAndDescriptionToTimeline = ( cy.get(TIMELINE_TITLE_INPUT).should('not.exist'); }; +export const duplicateFirstTimeline = () => { + cy.get(TIMELINES_TABLE).within(() => { + cy.get(COLLAPSED_ACTION_BTN).first().click(); + }); + cy.get(DUPLICATE_TIMELINE).click(); + cy.get(TIMELINE_TITLE).should('be.visible'); +}; + export const goToNotesTab = () => { cy.get(NOTES_TAB_BUTTON).click(); cy.get(NOTES_TEXT_AREA).should('be.visible'); From f6ec5c9c4c932cb6a607c9f9c8dc7a622a84858d Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Mon, 4 Nov 2024 14:00:49 +0100 Subject: [PATCH 5/8] fix tests --- .../timelines/unsaved_timeline.cy.ts | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts index 8eef7b45d30ef..08ddc2fb50075 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts @@ -18,7 +18,7 @@ import { openKibanaNavigation, } from '../../../tasks/kibana_navigation'; import { login } from '../../../tasks/login'; -import { visitWithTimeRange } from '../../../tasks/navigation'; +import { visit, visitWithTimeRange } from '../../../tasks/navigation'; import { closeTimelineUsingCloseButton, openTimelineUsingToggle, @@ -37,12 +37,12 @@ import { duplicateFirstTimeline, populateTimeline, } from '../../../tasks/timeline'; -import { EXPLORE_URL, TIMELINES_URL, MANAGE_URL } from '../../../urls/navigation'; +import { EXPLORE_URL, hostsUrl, MANAGE_URL, TIMELINES_URL } from '../../../urls/navigation'; describe('[ESS] Save Timeline Prompts', { tags: ['@ess'] }, () => { beforeEach(() => { login(); - visitWithTimeRange(TIMELINES_URL); + visitWithTimeRange(hostsUrl('allHosts')); openTimelineUsingToggle(); createNewTimeline(); /* @@ -59,7 +59,7 @@ describe('[ESS] Save Timeline Prompts', { tags: ['@ess'] }, () => { it('should NOT prompt when navigating with an unchanged & unsaved timeline', () => { openKibanaNavigation(); navigateFromKibanaCollapsibleTo(OBSERVABILITY_ALERTS_PAGE); - cy.url().should('not.contain', TIMELINES_URL); + cy.url().should('not.contain', hostsUrl('allHosts')); }); it('should prompt when navigating away from security solution with a changed & unsaved timeline', () => { @@ -121,10 +121,12 @@ describe('[ESS] Save Timeline Prompts', { tags: ['@ess'] }, () => { cy.url().should('not.contain', MANAGE_URL); }); - it('should prompt when a timeline is duplicated but not saved', () => { + it.only('should prompt when a timeline is duplicated but not saved', () => { addNameToTimelineAndSave('Original'); closeTimeline(); + visit(TIMELINES_URL); duplicateFirstTimeline(); + closeTimeline(); openKibanaNavigation(); navigateFromKibanaCollapsibleTo(MANAGE_PAGE); cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); @@ -135,7 +137,7 @@ describe('[ESS] Save Timeline Prompts', { tags: ['@ess'] }, () => { describe('[serverless] Save Timeline Prompts', { tags: ['@serverless'] }, () => { beforeEach(() => { login(); - visitWithTimeRange(TIMELINES_URL); + visitWithTimeRange(hostsUrl('allHosts')); openTimelineUsingToggle(); createNewTimeline(); /* @@ -215,9 +217,10 @@ describe('[serverless] Save Timeline Prompts', { tags: ['@serverless'] }, () => it('should prompt when a timeline is duplicated but not saved', () => { addNameToTimelineAndSave('Original'); closeTimeline(); + visit(TIMELINES_URL); duplicateFirstTimeline(); - openKibanaNavigation(); - navigateFromKibanaCollapsibleTo(MANAGE_PAGE); + closeTimeline(); + navigateToExplorePageInServerless(); // security page with timelines disabled cy.get(APP_LEAVE_CONFIRM_MODAL).should('be.visible'); }); }); From 7d5a3d15426c9eab706493f2b36e8b398fb432d6 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Mon, 4 Nov 2024 14:49:39 +0100 Subject: [PATCH 6/8] remove `.only` --- .../cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts index 08ddc2fb50075..0d938a00ac4f3 100644 --- a/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts +++ b/x-pack/test/security_solution_cypress/cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts @@ -121,7 +121,7 @@ describe('[ESS] Save Timeline Prompts', { tags: ['@ess'] }, () => { cy.url().should('not.contain', MANAGE_URL); }); - it.only('should prompt when a timeline is duplicated but not saved', () => { + it('should prompt when a timeline is duplicated but not saved', () => { addNameToTimelineAndSave('Original'); closeTimeline(); visit(TIMELINES_URL); From d774ff40ebbd2d7c3aa09652d9d075294509676d Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Tue, 5 Nov 2024 16:41:14 +0100 Subject: [PATCH 7/8] narrow down tests temporarily --- x-pack/test/security_solution_cypress/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/test/security_solution_cypress/package.json b/x-pack/test/security_solution_cypress/package.json index c7bc7fe1d94a0..bbd912061177d 100644 --- a/x-pack/test/security_solution_cypress/package.json +++ b/x-pack/test/security_solution_cypress/package.json @@ -16,7 +16,7 @@ "cypress:detection_engine:exceptions:run:ess": "yarn cypress:ess --spec './cypress/e2e/detection_response/detection_engine/exceptions/**/*.cy.ts'", "cypress:ai_assistant:run:ess":"yarn cypress:ess --spec './cypress/e2e/ai_assistant/**/*.cy.ts'", "cypress:run:respops:ess": "yarn cypress:ess --spec './cypress/e2e/detection_response/**/*.cy.ts'", - "cypress:investigations:run:ess": "yarn cypress:ess --spec './cypress/e2e/investigations/**/*.cy.ts'", + "cypress:investigations:run:ess": "yarn cypress:ess --spec './cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts'", "cypress:explore:run:ess": "yarn cypress:ess --spec './cypress/e2e/explore/**/*.cy.ts'", "cypress:changed-specs-only:ess": "yarn cypress:ess --changed-specs-only --env burn=5", "cypress:cloud_security_posture:run:ess": "yarn cypress:ess --spec './cypress/e2e/cloud_security_posture/**/*.cy.ts'", @@ -33,7 +33,7 @@ "cypress:detection_engine:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/detection_response/detection_engine/!(exceptions)/**/*.cy.ts'", "cypress:detection_engine:exceptions:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/detection_response/detection_engine/exceptions/**/*.cy.ts'", "cypress:ai_assistant:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/ai_assistant/**/*.cy.ts'", - "cypress:investigations:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/investigations/**/*.cy.ts'", + "cypress:investigations:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/investigations/timelines/unsaved_timline.cy.ts'", "cypress:explore:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/explore/**/*.cy.ts'", "cypress:changed-specs-only:serverless": "yarn cypress:serverless --changed-specs-only --env burn=5", "cypress:cloud_security_posture:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/cloud_security_posture/**/*.cy.ts'", From 720be330ab643b49caaf9ceed1926bce8f970ab6 Mon Sep 17 00:00:00 2001 From: Jan Monschke Date: Tue, 5 Nov 2024 18:25:18 +0100 Subject: [PATCH 8/8] Revert "narrow down tests temporarily" This reverts commit d774ff40ebbd2d7c3aa09652d9d075294509676d. --- x-pack/test/security_solution_cypress/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/x-pack/test/security_solution_cypress/package.json b/x-pack/test/security_solution_cypress/package.json index bbd912061177d..c7bc7fe1d94a0 100644 --- a/x-pack/test/security_solution_cypress/package.json +++ b/x-pack/test/security_solution_cypress/package.json @@ -16,7 +16,7 @@ "cypress:detection_engine:exceptions:run:ess": "yarn cypress:ess --spec './cypress/e2e/detection_response/detection_engine/exceptions/**/*.cy.ts'", "cypress:ai_assistant:run:ess":"yarn cypress:ess --spec './cypress/e2e/ai_assistant/**/*.cy.ts'", "cypress:run:respops:ess": "yarn cypress:ess --spec './cypress/e2e/detection_response/**/*.cy.ts'", - "cypress:investigations:run:ess": "yarn cypress:ess --spec './cypress/e2e/investigations/timelines/unsaved_timeline.cy.ts'", + "cypress:investigations:run:ess": "yarn cypress:ess --spec './cypress/e2e/investigations/**/*.cy.ts'", "cypress:explore:run:ess": "yarn cypress:ess --spec './cypress/e2e/explore/**/*.cy.ts'", "cypress:changed-specs-only:ess": "yarn cypress:ess --changed-specs-only --env burn=5", "cypress:cloud_security_posture:run:ess": "yarn cypress:ess --spec './cypress/e2e/cloud_security_posture/**/*.cy.ts'", @@ -33,7 +33,7 @@ "cypress:detection_engine:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/detection_response/detection_engine/!(exceptions)/**/*.cy.ts'", "cypress:detection_engine:exceptions:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/detection_response/detection_engine/exceptions/**/*.cy.ts'", "cypress:ai_assistant:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/ai_assistant/**/*.cy.ts'", - "cypress:investigations:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/investigations/timelines/unsaved_timline.cy.ts'", + "cypress:investigations:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/investigations/**/*.cy.ts'", "cypress:explore:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/explore/**/*.cy.ts'", "cypress:changed-specs-only:serverless": "yarn cypress:serverless --changed-specs-only --env burn=5", "cypress:cloud_security_posture:run:serverless": "yarn cypress:serverless --spec './cypress/e2e/cloud_security_posture/**/*.cy.ts'",