[SecuritySolution] Fix flaky timeline creation tests (#172799)

## Summary

Fixes the flakiness in the timeline creation cypress tests. The cause
for the flakiness was the extra save operation that is happening in the
background for the saved search. Awaiting that operation removed the
flakiness.

[Flaky test runner
result](https://buildkite.com/elastic/kibana-flaky-test-suite-runner/builds/4329)

Fixes: https://github.com/elastic/kibana/issues/172304,
https://github.com/elastic/kibana/issues/172031
This commit is contained in:
Jan Monschke 2023-12-13 15:43:07 +01:00 committed by GitHub
parent 3fbd25ba3d
commit 29f762b4d4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 78 additions and 109 deletions

View file

@ -21,6 +21,7 @@ import {
SAVE_TIMELINE_ACTION_BTN,
SAVE_TIMELINE_TOOLTIP,
} from '../../../screens/timeline';
import { LOADING_INDICATOR } from '../../../screens/security_header';
import { ROWS } from '../../../screens/timelines';
import { createTimelineTemplate } from '../../../tasks/api_calls/timelines';
@ -48,20 +49,15 @@ import { createTimeline } from '../../../tasks/timelines';
import { OVERVIEW_URL, TIMELINE_TEMPLATES_URL, TIMELINES_URL } from '../../../urls/navigation';
// Failing: See https://github.com/elastic/kibana/issues/172304
describe.skip('Create a timeline from a template', { tags: ['@ess', '@serverless'] }, () => {
before(() => {
deleteTimelines();
login();
createTimelineTemplate(getTimeline());
});
describe('Timelines', { tags: ['@ess', '@serverless'] }, (): void => {
beforeEach(() => {
login();
visit(TIMELINE_TEMPLATES_URL);
deleteTimelines();
});
it('Should have the same query and open the timeline modal', () => {
it('creates a timeline from a template and should have the same query and open the timeline modal', () => {
createTimelineTemplate(getTimeline());
visit(TIMELINE_TEMPLATES_URL);
selectCustomTemplates();
expandEventAction();
clickingOnCreateTimelineFormTemplateBtn();
@ -69,15 +65,9 @@ describe.skip('Create a timeline from a template', { tags: ['@ess', '@serverless
cy.get(TIMELINE_QUERY).should('have.text', getTimeline().query);
closeTimeline();
});
});
describe('Timelines', (): void => {
before(() => {
deleteTimelines();
});
describe('Toggle create timeline from "New" btn', () => {
context('Privileges: CRUD', { tags: '@ess' }, () => {
context('Privileges: CRUD', () => {
beforeEach(() => {
login();
visitWithTimeRange(OVERVIEW_URL);
@ -91,7 +81,7 @@ describe('Timelines', (): void => {
});
});
context('Privileges: READ', { tags: '@ess' }, () => {
context('Privileges: READ', () => {
beforeEach(() => {
login(ROLES.t1_analyst);
visitWithTimeRange(OVERVIEW_URL);
@ -112,99 +102,80 @@ describe('Timelines', (): void => {
});
});
describe(
'Creates a timeline by clicking untitled timeline from bottom bar',
{ tags: ['@ess', '@serverless'] },
() => {
beforeEach(() => {
login();
visitWithTimeRange(OVERVIEW_URL);
openTimelineUsingToggle();
addNameAndDescriptionToTimeline(getTimeline());
populateTimeline();
goToQueryTab();
});
it('creates a timeline by clicking untitled timeline from bottom bar', () => {
visitWithTimeRange(OVERVIEW_URL);
openTimelineUsingToggle();
addNameAndDescriptionToTimeline(getTimeline());
populateTimeline();
goToQueryTab();
it.skip('can be added filter', () => {
addFilter(getTimeline().filter);
cy.get(TIMELINE_FILTER(getTimeline().filter)).should('exist');
});
addFilter(getTimeline().filter);
cy.get(TIMELINE_FILTER(getTimeline().filter)).should('exist');
it('pins an event', () => {
pinFirstEvent();
cy.get(PIN_EVENT)
.should('have.attr', 'aria-label')
.and('match', /Unpin the event in row 2/);
});
pinFirstEvent();
cy.get(PIN_EVENT)
.should('have.attr', 'aria-label')
.and('match', /Unpin the event in row 2/);
it('has a lock icon', () => {
cy.get(LOCKED_ICON).should('be.visible');
});
cy.get(LOCKED_ICON).should('be.visible');
// TO-DO: Issue 163398
it.skip('can be added notes', () => {
addNotesToTimeline(getTimeline().notes);
cy.get(TIMELINE_TAB_CONTENT_GRAPHS_NOTES)
.find(NOTES_TEXT)
.should('have.text', getTimeline().notes);
});
}
);
// FLAKY: https://github.com/elastic/kibana/issues/172031
describe.skip('shows the different timeline states', () => {
before(() => {
login();
visitWithTimeRange(OVERVIEW_URL);
openTimelineUsingToggle();
createNewTimeline();
});
it('should show the correct timeline status', { tags: ['@ess', '@serverless'] }, () => {
// Unsaved
cy.get(TIMELINE_PANEL).should('be.visible');
cy.get(TIMELINE_STATUS).should('be.visible');
cy.get(TIMELINE_STATUS).should('have.text', 'Unsaved');
addNameToTimelineAndSave('Test');
// Saved
cy.get(TIMELINE_STATUS).should('be.visible');
cy.get(TIMELINE_STATUS)
.invoke('text')
.should('match', /^Saved/);
executeTimelineKQL('agent.name : *');
// Saved but has unsaved changes
cy.get(TIMELINE_STATUS).should('be.visible');
cy.get(TIMELINE_STATUS)
.invoke('text')
.should('match', /^Has unsaved changes/);
});
addNotesToTimeline(getTimeline().notes);
cy.get(TIMELINE_TAB_CONTENT_GRAPHS_NOTES)
.find(NOTES_TEXT)
.should('have.text', getTimeline().notes);
});
describe('saves timeline as new', () => {
before(() => {
deleteTimelines();
login();
visitWithTimeRange(TIMELINES_URL);
});
it('shows the different timeline states', () => {
visitWithTimeRange(TIMELINES_URL);
createTimeline();
it('should save timelines as new', { tags: ['@ess', '@serverless'] }, () => {
cy.get(ROWS).should('have.length', '0');
// Unsaved
cy.get(TIMELINE_PANEL).should('be.visible');
cy.get(TIMELINE_STATUS).should('be.visible');
cy.get(TIMELINE_STATUS).should('have.text', 'Unsaved');
createTimeline();
addNameToTimelineAndSave('First');
addNameToTimelineAndSaveAsNew('Second');
closeTimeline();
addNameToTimelineAndSave('Test');
cy.get(ROWS).should('have.length', '2');
cy.get(ROWS)
.first()
.invoke('text')
.should('match', /Second/);
cy.get(ROWS).last().invoke('text').should('match', /First/);
});
// Saved
cy.get(TIMELINE_STATUS).should('be.visible');
cy.get(TIMELINE_STATUS)
.invoke('text')
.should('match', /^Saved/);
// Offsetting the extra save that is happening in the background
// for the saved search object.
cy.get(LOADING_INDICATOR).should('be.visible');
cy.get(LOADING_INDICATOR).should('not.exist');
executeTimelineKQL('agent.name : *');
// Saved but has unsaved changes
cy.get(TIMELINE_STATUS).should('be.visible');
cy.get(TIMELINE_STATUS)
.invoke('text')
.should('match', /^Has unsaved changes/);
});
it('should save timelines as new', () => {
visitWithTimeRange(TIMELINES_URL);
cy.get(ROWS).should('have.length', '0');
createTimeline();
addNameToTimelineAndSave('First');
// Offsetting the extra save that is happening in the background
// for the saved search object.
cy.get(LOADING_INDICATOR).should('be.visible');
cy.get(LOADING_INDICATOR).should('not.exist');
addNameToTimelineAndSaveAsNew('Second');
closeTimeline();
cy.get(ROWS).should('have.length', '2');
cy.get(ROWS)
.first()
.invoke('text')
.should('match', /Second/);
cy.get(ROWS).last().invoke('text').should('match', /First/);
});
});

View file

@ -29,8 +29,6 @@ export const CORRELATION_EVENT_TABLE_CELL =
export const CLOSE_TIMELINE_BTN = '[data-test-subj="close-timeline"]';
export const COMBO_BOX = 'button.euiFilterSelectItem[role="option"]';
export const COMBO_BOX_INPUT = '[data-test-subj="comboBoxInput"]';
export const CREATE_NEW_TIMELINE = '[data-test-subj="timeline-new"]';

View file

@ -21,7 +21,6 @@ import {
ATTACH_TIMELINE_TO_EXISTING_CASE_ICON,
ATTACH_TIMELINE_TO_NEW_CASE_ICON,
CLOSE_TIMELINE_BTN,
COMBO_BOX,
COMBO_BOX_INPUT,
CREATE_NEW_TIMELINE,
DELETE_TIMELINE_BTN,
@ -211,8 +210,8 @@ export const addEqlToTimeline = (eql: string) => {
export const addFilter = (filter: TimelineFilter): Cypress.Chainable<JQuery<HTMLElement>> => {
cy.get(ADD_FILTER).click();
cy.get(TIMELINE_FILTER_FIELD).type(`${filter.field}{downarrow}{enter}`);
cy.get(TIMELINE_FILTER_OPERATOR).type(filter.operator);
cy.get(COMBO_BOX).contains(filter.operator).trigger('click');
cy.get(TIMELINE_FILTER_OPERATOR).type(`${filter.operator}{downarrow}{enter}`);
if (filter.operator !== 'exists') {
cy.get(TIMELINE_FILTER_VALUE).type(`${filter.value}{enter}`);
}

View file

@ -65,4 +65,5 @@ export const exportSelectedTimelines = () => {
cy.get(EXPORT_TIMELINE_ACTION).click();
};
export const createTimeline = () => cy.get(CREATE_NEW_TIMELINE_WITH_BORDER).click();
export const createTimeline = () =>
cy.get(CREATE_NEW_TIMELINE_WITH_BORDER).should('be.visible').click();