[Security Solution] Adds "Creates timeline" Cypress test (#76836)

* adds "Creates timeline" test

* deletes timeline events spec

* completes assertions

* comments assertion

* fixes typecheck error

* waits for all the changes in the timeline to be performed before creating a new timeline and closing the toggle

* fixes failing problem

* fixes loop script

* makes test realiable on visual mode

* fixes merge issue

* makes test more reliable

* fixes typecheck issue

* fixes typecheck

* opens timeline from timeline settings

Co-authored-by: Elastic Machine <elasticmachine@users.noreply.github.com>
This commit is contained in:
MadameSheema 2020-09-18 12:59:45 +02:00 committed by GitHub
parent 63bb3bf309
commit 6408fa54ed
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
27 changed files with 307 additions and 95 deletions

View file

@ -154,6 +154,7 @@
"color": "1.0.3",
"commander": "3.0.2",
"core-js": "^3.6.4",
"cypress-promise": "^1.1.0",
"deep-freeze-strict": "^1.1.1",
"del": "^5.1.0",
"elastic-apm-node": "^3.7.0",

View file

@ -160,6 +160,7 @@
"cronstrue": "^1.51.0",
"cypress": "5.0.0",
"cypress-multi-reporters": "^1.2.3",
"cypress-promise": "^1.1.0",
"d3": "3.5.17",
"d3-scale": "1.0.7",
"dragselect": "1.13.1",

View file

@ -2,5 +2,8 @@
"plugins": ["cypress"],
"env": {
"cypress/globals": true
},
"rules": {
"import/no-extraneous-dependencies": "off"
}
}

View file

@ -28,7 +28,7 @@ import {
resetFields,
} from '../tasks/fields_browser';
import { loginAndWaitForPage } from '../tasks/login';
import { openTimeline } from '../tasks/security_main';
import { openTimelineUsingToggle } from '../tasks/security_main';
import { openTimelineFieldsBrowser, populateTimeline } from '../tasks/timeline';
import { HOSTS_URL } from '../urls/navigation';
@ -48,7 +48,7 @@ describe('Fields Browser', () => {
context('Fields Browser rendering', () => {
before(() => {
loginAndWaitForPage(HOSTS_URL);
openTimeline();
openTimelineUsingToggle();
populateTimeline();
openTimelineFieldsBrowser();
});
@ -111,7 +111,7 @@ describe('Fields Browser', () => {
context('Editing the timeline', () => {
before(() => {
loginAndWaitForPage(HOSTS_URL);
openTimeline();
openTimelineUsingToggle();
populateTimeline();
openTimelineFieldsBrowser();
});

View file

@ -12,7 +12,7 @@ import {
import { closesModal, openStatsAndTables } from '../tasks/inspect';
import { loginAndWaitForPage } from '../tasks/login';
import { openTimeline } from '../tasks/security_main';
import { openTimelineUsingToggle } from '../tasks/security_main';
import {
executeTimelineKQL,
openTimelineInspectButton,
@ -58,7 +58,7 @@ describe('Inspect', () => {
it('inspects the timeline', () => {
const hostExistsQuery = 'host.name: *';
loginAndWaitForPage(HOSTS_URL);
openTimeline();
openTimelineUsingToggle();
executeTimelineKQL(hostExistsQuery);
openTimelineSettings();
openTimelineInspectButton();

View file

@ -0,0 +1,99 @@
/*
* 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 { timeline } from '../objects/timeline';
import {
FAVORITE_TIMELINE,
LOCKED_ICON,
NOTES,
NOTES_BUTTON,
NOTES_COUNT,
NOTES_TEXT_AREA,
PIN_EVENT,
TIMELINE_DESCRIPTION,
// TIMELINE_FILTER,
TIMELINE_QUERY,
TIMELINE_TITLE,
} from '../screens/timeline';
import {
TIMELINES_DESCRIPTION,
TIMELINES_PINNED_EVENT_COUNT,
TIMELINES_NOTES_COUNT,
TIMELINES_FAVORITE,
} from '../screens/timelines';
import { loginAndWaitForPage } from '../tasks/login';
import { openTimelineUsingToggle } from '../tasks/security_main';
import {
addDescriptionToTimeline,
addFilter,
addNameToTimeline,
addNotesToTimeline,
closeNotes,
closeTimeline,
createNewTimeline,
markAsFavorite,
openTimelineFromSettings,
pinFirstEvent,
populateTimeline,
waitForTimelineChanges,
} from '../tasks/timeline';
import { openTimeline } from '../tasks/timelines';
import { OVERVIEW_URL } from '../urls/navigation';
describe('Timelines', () => {
before(() => {
cy.server();
cy.route('PATCH', '**/api/timeline').as('timeline');
});
it('Creates a timeline', async () => {
loginAndWaitForPage(OVERVIEW_URL);
openTimelineUsingToggle();
populateTimeline();
addFilter(timeline.filter);
pinFirstEvent();
cy.get(PIN_EVENT).should('have.attr', 'aria-label', 'Pinned event');
cy.get(LOCKED_ICON).should('be.visible');
addNameToTimeline(timeline.title);
const response = await cy.wait('@timeline').promisify();
const timelineId = JSON.parse(response.xhr.responseText).data.persistTimeline.timeline
.savedObjectId;
addDescriptionToTimeline(timeline.description);
addNotesToTimeline(timeline.notes);
closeNotes();
markAsFavorite();
waitForTimelineChanges();
createNewTimeline();
closeTimeline();
openTimelineFromSettings();
cy.contains(timeline.title).should('exist');
cy.get(TIMELINES_DESCRIPTION).first().should('have.text', timeline.description);
cy.get(TIMELINES_PINNED_EVENT_COUNT).first().should('have.text', '1');
cy.get(TIMELINES_NOTES_COUNT).first().should('have.text', '1');
cy.get(TIMELINES_FAVORITE).first().should('exist');
openTimeline(timelineId);
cy.get(FAVORITE_TIMELINE).should('exist');
cy.get(TIMELINE_TITLE).should('have.attr', 'value', timeline.title);
cy.get(TIMELINE_DESCRIPTION).should('have.attr', 'value', timeline.description);
cy.get(TIMELINE_QUERY).should('have.text', timeline.query);
// Comments this assertion until we agreed what to do with the filters.
// cy.get(TIMELINE_FILTER(timeline.filter)).should('exist');
cy.get(NOTES_COUNT).should('have.text', '1');
cy.get(PIN_EVENT).should('have.attr', 'aria-label', 'Pinned event');
cy.get(NOTES_BUTTON).click();
cy.get(NOTES_TEXT_AREA).should('have.attr', 'placeholder', 'Add a Note');
cy.get(NOTES).should('have.text', timeline.notes);
});
});

View file

@ -19,7 +19,7 @@ import {
} from '../tasks/hosts/all_hosts';
import { loginAndWaitForPage } from '../tasks/login';
import { openTimeline } from '../tasks/security_main';
import { openTimelineUsingToggle } from '../tasks/security_main';
import { createNewTimeline } from '../tasks/timeline';
import { HOSTS_URL } from '../urls/navigation';
@ -31,7 +31,7 @@ describe('timeline data providers', () => {
});
beforeEach(() => {
openTimeline();
openTimelineUsingToggle();
});
afterEach(() => {

View file

@ -1,39 +0,0 @@
/*
* 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 { PIN_EVENT } from '../screens/timeline';
import { loginAndWaitForPage } from '../tasks/login';
import { openTimeline } from '../tasks/security_main';
import { pinFirstEvent, populateTimeline, unpinFirstEvent } from '../tasks/timeline';
import { HOSTS_URL } from '../urls/navigation';
describe('timeline events', () => {
before(() => {
loginAndWaitForPage(HOSTS_URL);
openTimeline();
populateTimeline();
});
after(() => {
unpinFirstEvent();
});
it('pins the first event to the timeline', () => {
cy.server();
cy.route('POST', '**/api/solutions/security/graphql').as('persistTimeline');
pinFirstEvent();
cy.wait('@persistTimeline', { timeout: 10000 }).then((response) => {
cy.wrap(response.status).should('eql', 200);
cy.wrap(response.xhr.responseText).should('include', 'persistPinnedEventOnTimeline');
});
cy.get(PIN_EVENT).should('have.attr', 'aria-label', 'Pinned event');
});
});

View file

@ -8,7 +8,7 @@ import { TIMELINE_FLYOUT_HEADER, TIMELINE_NOT_READY_TO_DROP_BUTTON } from '../sc
import { dragFirstHostToTimeline, waitForAllHostsToBeLoaded } from '../tasks/hosts/all_hosts';
import { loginAndWaitForPage } from '../tasks/login';
import { openTimeline, openTimelineIfClosed } from '../tasks/security_main';
import { openTimelineUsingToggle, openTimelineIfClosed } from '../tasks/security_main';
import { createNewTimeline } from '../tasks/timeline';
import { HOSTS_URL } from '../urls/navigation';
@ -25,7 +25,7 @@ describe('timeline flyout button', () => {
});
it('toggles open the timeline', () => {
openTimeline();
openTimelineUsingToggle();
cy.get(TIMELINE_FLYOUT_HEADER).should('have.css', 'visibility', 'visible');
});

View file

@ -7,7 +7,7 @@
import { SERVER_SIDE_EVENT_COUNT } from '../screens/timeline';
import { loginAndWaitForPage } from '../tasks/login';
import { openTimeline } from '../tasks/security_main';
import { openTimelineUsingToggle } from '../tasks/security_main';
import { executeTimelineKQL } from '../tasks/timeline';
import { HOSTS_URL } from '../urls/navigation';
@ -19,7 +19,7 @@ describe('timeline search or filter KQL bar', () => {
it('executes a KQL query', () => {
const hostExistsQuery = 'host.name: *';
openTimeline();
openTimelineUsingToggle();
executeTimelineKQL(hostExistsQuery);
cy.get(SERVER_SIDE_EVENT_COUNT)

View file

@ -12,7 +12,7 @@ import {
} from '../screens/timeline';
import { loginAndWaitForPage } from '../tasks/login';
import { openTimeline } from '../tasks/security_main';
import { openTimelineUsingToggle } from '../tasks/security_main';
import {
checkIdToggleField,
createNewTimeline,
@ -30,7 +30,7 @@ describe('toggle column in timeline', () => {
});
beforeEach(() => {
openTimeline();
openTimelineUsingToggle();
populateTimeline();
});

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { exportTimeline, waitForTimelinesPanelToBeLoaded } from '../tasks/timeline';
import { exportTimeline, waitForTimelinesPanelToBeLoaded } from '../tasks/timelines';
import { esArchiverLoad, esArchiverUnload } from '../tasks/es_archiver';
import { loginAndWaitForPageWithoutDateRange } from '../tasks/login';

View file

@ -30,7 +30,7 @@ import { openAllHosts } from '../tasks/hosts/main';
import { waitForIpsTableToBeLoaded } from '../tasks/network/flows';
import { clearSearchBar, kqlSearch, navigateFromHeaderTo } from '../tasks/security_header';
import { openTimeline } from '../tasks/security_main';
import { openTimelineUsingToggle } from '../tasks/security_main';
import {
addDescriptionToTimeline,
addNameToTimeline,
@ -82,7 +82,7 @@ describe('url state', () => {
it('sets the timeline start and end dates from the url when locked to global time', () => {
loginAndWaitForPageWithoutDateRange(ABSOLUTE_DATE_RANGE.url);
openTimeline();
openTimelineUsingToggle();
cy.get(DATE_PICKER_START_DATE_POPOVER_BUTTON_TIMELINE).should(
'have.attr',
@ -105,7 +105,7 @@ describe('url state', () => {
);
cy.get(DATE_PICKER_END_DATE_POPOVER_BUTTON).should('have.attr', 'title', ABSOLUTE_DATE.endTime);
openTimeline();
openTimelineUsingToggle();
cy.get(DATE_PICKER_START_DATE_POPOVER_BUTTON_TIMELINE).should(
'have.attr',
@ -121,7 +121,7 @@ describe('url state', () => {
it('sets the url state when timeline/global date pickers are unlinked and timeline start and end date are set', () => {
loginAndWaitForPageWithoutDateRange(ABSOLUTE_DATE_RANGE.urlUnlinked);
openTimeline();
openTimelineUsingToggle();
setTimelineStartDate(ABSOLUTE_DATE.newStartTimeTyped);
updateTimelineDates();
setTimelineEndDate(ABSOLUTE_DATE.newEndTimeTyped);
@ -220,7 +220,7 @@ describe('url state', () => {
it('sets and reads the url state for timeline by id', () => {
loginAndWaitForPage(HOSTS_URL);
openTimeline();
openTimelineUsingToggle();
executeTimelineKQL('host.name: *');
cy.get(SERVER_SIDE_EVENT_COUNT)

View file

@ -10,6 +10,30 @@ export interface Timeline {
query: string;
}
export interface CompleteTimeline extends Timeline {
notes: string;
filter: TimelineFilter;
}
export interface TimelineFilter {
field: string;
operator: string;
value?: string;
}
export interface TimelineWithId extends Timeline {
id: string;
}
export const filter: TimelineFilter = {
field: 'host.name',
operator: 'exists',
};
export const timeline: CompleteTimeline = {
title: 'Security Timeline',
description: 'This is the best timeline',
query: 'host.name: * ',
notes: 'Yes, the best timeline',
filter,
};

View file

@ -4,6 +4,12 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { TimelineFilter } from '../objects/timeline';
export const ADD_NOTE_BUTTON = '[data-test-subj="add-note"]';
export const ADD_FILTER = '[data-test-subj="timeline"] [data-test-subj="addFilter"]';
export const ATTACH_TIMELINE_TO_NEW_CASE_ICON = '[data-test-subj="attach-timeline-case"]';
export const ATTACH_TIMELINE_TO_EXISTING_CASE_ICON =
@ -15,14 +21,18 @@ export const CASE = (id: string) => {
return `[data-test-subj="cases-table-row-${id}"]`;
};
export const CLOSE_NOTES_BTN = '[data-test-subj="notesModal"] .euiButtonIcon';
export const CLOSE_TIMELINE_BTN = '[data-test-subj="close-timeline"]';
export const COMBO_BOX = '.euiComboBoxOption__content';
export const CREATE_NEW_TIMELINE = '[data-test-subj="timeline-new"]';
export const DRAGGABLE_HEADER =
'[data-test-subj="events-viewer-panel"] [data-test-subj="headers-group"] [data-test-subj="draggable-header"]';
export const EXPORT_TIMELINE_ACTION = '[data-test-subj="export-timeline-action"]';
export const FAVORITE_TIMELINE = '[data-test-subj="timeline-favorite-filled-star"]';
export const HEADER = '[data-test-subj="header"]';
@ -34,6 +44,16 @@ export const ID_FIELD = '[data-test-subj="timeline"] [data-test-subj="field-name
export const ID_TOGGLE_FIELD = '[data-test-subj="toggle-field-_id"]';
export const LOCKED_ICON = '[data-test-subj="timeline-date-picker-lock-button"]';
export const NOTES = '[data-test-subj="markdown-root"]';
export const NOTES_TEXT_AREA = '[data-test-subj="add-a-note"]';
export const NOTES_BUTTON = '[data-test-subj="timeline-notes-button-large"]';
export const NOTES_COUNT = '[data-test-subj="timeline-notes-count"]';
export const OPEN_TIMELINE_ICON = '[data-test-subj="open-timeline-button"]';
export const PIN_EVENT = '[data-test-subj="pin"]';
@ -45,21 +65,17 @@ export const REMOVE_COLUMN = '[data-test-subj="remove-column"]';
export const RESET_FIELDS =
'[data-test-subj="events-viewer-panel"] [data-test-subj="reset-fields"]';
export const SAVE_FILTER_BTN = '[data-test-subj="saveFilter"]';
export const SEARCH_OR_FILTER_CONTAINER =
'[data-test-subj="timeline-search-or-filter-search-container"]';
export const SERVER_SIDE_EVENT_COUNT = '[data-test-subj="server-side-event-count"]';
export const TIMELINE = (id: string) => {
return `[data-test-subj="title-${id}"]`;
};
export const STAR_ICON = '[data-test-subj="timeline-favorite-empty-star"]';
export const TIMELINE_CHANGES_IN_PROGRESS = '[data-test-subj="timeline"] .euiProgress';
export const TIMELINE_CHECKBOX = (id: string) => {
return `[data-test-subj="checkboxSelectRow-${id}"]`;
};
export const TIMELINE_COLUMN_SPINNER = '[data-test-subj="timeline-loading-spinner"]';
export const TIMELINE_DATA_PROVIDERS = '[data-test-subj="dataProviders"]';
@ -74,6 +90,17 @@ export const TIMELINE_DROPPED_DATA_PROVIDERS = '[data-test-subj="providerContain
export const TIMELINE_FIELDS_BUTTON =
'[data-test-subj="timeline"] [data-test-subj="show-field-browser"]';
export const TIMELINE_FILTER = (filter: TimelineFilter) => {
return `[data-test-subj="filter filter-enabled filter-key-${filter.field} filter-value-${filter.value} filter-unpinned"]`;
};
export const TIMELINE_FILTER_FIELD = '[data-test-subj="filterFieldSuggestionList"]';
export const TIMELINE_FILTER_OPERATOR = '[data-test-subj="filterOperatorList"]';
export const TIMELINE_FILTER_VALUE =
'[data-test-subj="filterParamsComboBox phraseParamsComboxBox"]';
export const TIMELINE_FLYOUT_HEADER = '[data-test-subj="eui-flyout-header"]';
export const TIMELINE_FLYOUT_BODY = '[data-test-subj="eui-flyout-body"]';
@ -89,8 +116,6 @@ export const TIMELINE_SETTINGS_ICON = '[data-test-subj="settings-gear"]';
export const TIMELINE_TITLE = '[data-test-subj="timeline-title"]';
export const TIMELINES_TABLE = '[data-test-subj="timelines-table"]';
export const TIMESTAMP_HEADER_FIELD = '[data-test-subj="header-text-@timestamp"]';
export const TIMESTAMP_TOGGLE_FIELD = '[data-test-subj="toggle-field-@timestamp"]';

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 BULK_ACTIONS = '[data-test-subj="utility-bar-action-button"]';
export const EXPORT_TIMELINE_ACTION = '[data-test-subj="export-timeline-action"]';
export const TIMELINE = (id: string) => {
return `[data-test-subj="title-${id}"]`;
};
export const TIMELINE_CHECKBOX = (id: string) => {
return `[data-test-subj="checkboxSelectRow-${id}"]`;
};
export const TIMELINES_FAVORITE = '[data-test-subj="favorite-starFilled-star"]';
export const TIMELINES_DESCRIPTION = '[data-test-subj="description"]';
export const TIMELINES_NOTES_COUNT = '[data-test-subj="notes-count"]';
export const TIMELINES_PINNED_EVENT_COUNT = '[data-test-subj="pinned-event-count"]';
export const TIMELINES_TABLE = '[data-test-subj="timelines-table"]';
export const TIMELINES_USERNAME = '[data-test-subj="username"]';

View file

@ -6,6 +6,7 @@
declare namespace Cypress {
interface Chainable<Subject> {
promisify(): Promise<Subject>;
stubSecurityApi(dataFileName: string): Chainable<Subject>;
stubSearchStrategyApi(dataFileName: string): Chainable<Subject>;
attachFile(fileName: string, fileType?: string): Chainable<JQuery>;

View file

@ -21,6 +21,7 @@
// Import commands.js using ES2015 syntax:
import './commands';
import 'cypress-promise/register';
Cypress.Cookies.defaults({
preserve: 'sid',

View file

@ -55,7 +55,7 @@ import {
EQL_TYPE,
EQL_QUERY_INPUT,
} from '../screens/create_new_rule';
import { TIMELINE } from '../screens/timeline';
import { TIMELINE } from '../screens/timelines';
export const createAndActivateRule = () => {
cy.get(SCHEDULE_CONTINUE_BUTTON).click({ force: true });

View file

@ -6,14 +6,14 @@
import { MAIN_PAGE, TIMELINE_TOGGLE_BUTTON } from '../screens/security_main';
export const openTimeline = () => {
export const openTimelineUsingToggle = () => {
cy.get(TIMELINE_TOGGLE_BUTTON).click();
};
export const openTimelineIfClosed = () => {
cy.get(MAIN_PAGE).then(($page) => {
if ($page.find(TIMELINE_TOGGLE_BUTTON).length === 1) {
openTimeline();
openTimelineUsingToggle();
}
});
};

View file

@ -4,36 +4,47 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { TimelineFilter } from '../objects/timeline';
import { ALL_CASES_CREATE_NEW_CASE_TABLE_BTN } from '../screens/all_cases';
import {
BULK_ACTIONS,
ADD_FILTER,
ADD_NOTE_BUTTON,
ATTACH_TIMELINE_TO_EXISTING_CASE_ICON,
ATTACH_TIMELINE_TO_NEW_CASE_ICON,
CASE,
CLOSE_TIMELINE_BTN,
CLOSE_NOTES_BTN,
COMBO_BOX,
CREATE_NEW_TIMELINE,
EXPORT_TIMELINE_ACTION,
TIMELINE_CHECKBOX,
HEADER,
ID_FIELD,
ID_HEADER_FIELD,
ID_TOGGLE_FIELD,
NOTES_BUTTON,
NOTES_TEXT_AREA,
OPEN_TIMELINE_ICON,
PIN_EVENT,
REMOVE_COLUMN,
RESET_FIELDS,
SAVE_FILTER_BTN,
SEARCH_OR_FILTER_CONTAINER,
SERVER_SIDE_EVENT_COUNT,
STAR_ICON,
TIMELINE_CHANGES_IN_PROGRESS,
TIMELINE_DESCRIPTION,
TIMELINE_FIELDS_BUTTON,
TIMELINE_FILTER_FIELD,
TIMELINE_FILTER_OPERATOR,
TIMELINE_FILTER_VALUE,
TIMELINE_INSPECT_BUTTON,
TIMELINE_SETTINGS_ICON,
TIMELINE_TITLE,
TIMELINES_TABLE,
TIMESTAMP_TOGGLE_FIELD,
TOGGLE_TIMELINE_EXPAND_EVENT,
REMOVE_COLUMN,
RESET_FIELDS,
ATTACH_TIMELINE_TO_NEW_CASE_ICON,
OPEN_TIMELINE_ICON,
ATTACH_TIMELINE_TO_EXISTING_CASE_ICON,
CASE,
} from '../screens/timeline';
import { TIMELINES_TABLE } from '../screens/timelines';
import { drag, drop } from '../tasks/common';
@ -49,6 +60,24 @@ export const addNameToTimeline = (name: string) => {
cy.get(TIMELINE_TITLE).should('have.attr', 'value', name);
};
export const addNotesToTimeline = (notes: string) => {
cy.get(NOTES_BUTTON).click();
cy.get(NOTES_TEXT_AREA).type(notes);
cy.get(ADD_NOTE_BUTTON).click();
};
export const addFilter = (filter: TimelineFilter) => {
cy.get(ADD_FILTER).click();
cy.get(TIMELINE_FILTER_FIELD).type(filter.field);
cy.get(COMBO_BOX).contains(filter.field).click();
cy.get(TIMELINE_FILTER_OPERATOR).type(filter.operator);
cy.get(COMBO_BOX).contains(filter.operator).click();
if (filter.operator !== 'exists') {
cy.get(TIMELINE_FILTER_VALUE).type(`${filter.value}{enter}`);
}
cy.get(SAVE_FILTER_BTN).click();
};
export const addNewCase = () => {
cy.get(ALL_CASES_CREATE_NEW_CASE_TABLE_BTN).click();
};
@ -71,6 +100,10 @@ export const checkIdToggleField = () => {
});
};
export const closeNotes = () => {
cy.get(CLOSE_NOTES_BTN).click();
};
export const closeTimeline = () => {
cy.get(CLOSE_TIMELINE_BTN).click({ force: true });
};
@ -89,10 +122,8 @@ export const expandFirstTimelineEventDetails = () => {
cy.get(TOGGLE_TIMELINE_EXPAND_EVENT).first().click({ force: true });
};
export const exportTimeline = (timelineId: string) => {
cy.get(TIMELINE_CHECKBOX(timelineId)).click({ force: true });
cy.get(BULK_ACTIONS).click({ force: true });
cy.get(EXPORT_TIMELINE_ACTION).click();
export const markAsFavorite = () => {
cy.get(STAR_ICON).click();
};
export const openTimelineFieldsBrowser = () => {
@ -160,11 +191,11 @@ export const selectCase = (caseId: string) => {
cy.get(CASE(caseId)).click();
};
export const waitForTimelinesPanelToBeLoaded = () => {
cy.get(TIMELINES_TABLE).should('exist');
};
export const waitForTimelineChanges = () => {
cy.get(TIMELINE_CHANGES_IN_PROGRESS).should('exist');
cy.get(TIMELINE_CHANGES_IN_PROGRESS).should('not.exist');
};
export const waitForTimelinesPanelToBeLoaded = () => {
cy.get(TIMELINES_TABLE).should('exist');
};

View file

@ -0,0 +1,27 @@
/*
* 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 {
TIMELINE_CHECKBOX,
BULK_ACTIONS,
EXPORT_TIMELINE_ACTION,
TIMELINES_TABLE,
TIMELINE,
} from '../screens/timelines';
export const exportTimeline = (timelineId: string) => {
cy.get(TIMELINE_CHECKBOX(timelineId)).click({ force: true });
cy.get(BULK_ACTIONS).click({ force: true });
cy.get(EXPORT_TIMELINE_ACTION).click();
};
export const openTimeline = (id: string) => {
cy.get(TIMELINE(id)).click();
};
export const waitForTimelinesPanelToBeLoaded = () => {
cy.get(TIMELINES_TABLE).should('exist');
};

View file

@ -1,4 +1,4 @@
{
{
"author": "Elastic",
"name": "security_solution",
"version": "8.0.0",

View file

@ -146,7 +146,7 @@ const AddDataProviderPopoverComponent: React.FC<AddDataProviderPopoverProps> = (
<EuiButton
size="s"
onClick={handleOpenPopover}
data-test-subj="addFilter"
data-test-subj="addField"
iconType="arrowDown"
fill
iconSide="right"
@ -160,7 +160,7 @@ const AddDataProviderPopoverComponent: React.FC<AddDataProviderPopoverProps> = (
<EuiButtonEmpty
size="s"
onClick={handleOpenPopover}
data-test-subj="addFilter"
data-test-subj="addField"
iconSide="right"
>
<EuiText size="s">{`+ ${ADD_FIELD_LABEL}`}</EuiText>

View file

@ -376,7 +376,11 @@ const NotesButtonComponent = React.memo<NotesButtonProps>(
)}
{size === 'l' && showNotes ? (
<EuiOverlayMask>
<EuiModal maxWidth={NOTES_PANEL_WIDTH} onClose={toggleShowNotes}>
<EuiModal
data-test-subj="notesModal"
maxWidth={NOTES_PANEL_WIDTH}
onClose={toggleShowNotes}
>
<Notes
associateNote={associateNote}
getNewNoteId={getNewNoteId}

View file

@ -34,7 +34,7 @@ const exitIfIncorrectWorkingDir = () => {
const exitIfTimesToRunIsInvalid = (timesToRun) => {
if (!timesToRun > 0) {
console.error(
'\nERROR: You must specify a valid number of times to run the SIEM Cypress tests.'
'\nERROR: You must specify a valid number of times to run the Security Solution Cypress tests.'
);
showUsage();
process.exit(1);
@ -44,7 +44,7 @@ const spawnChild = async () => {
const child = spawn('node', [
'scripts/functional_tests',
'--config',
'x-pack/test/security_solution_cypress/config.ts',
'x-pack/test/security_solution_cypress/cli_config.ts',
]);
for await (const chunk of child.stdout) {
console.log(chunk.toString());

View file

@ -9941,6 +9941,11 @@ cypress-multi-reporters@^1.2.3:
debug "^4.1.1"
lodash "^4.17.11"
cypress-promise@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/cypress-promise/-/cypress-promise-1.1.0.tgz#f2d66965945fe198431aaf692d5157cea9d47b25"
integrity sha512-DhIf5PJ/a0iY+Yii6n7Rbwq+9TJxU4pupXYzf9mZd8nPG0AzQrj9i+pqINv4xbI2EV1p+PKW3maCkR7oPG4GrA==
cypress@5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/cypress/-/cypress-5.0.0.tgz#6957e299b790af8b1cd7bea68261b8935646f72e"