[SIEM] Refactor to make Cypress tests more readable (#54907)
* extracts methods to tasks * uses cypress api for assertions * updates readme
This commit is contained in:
parent
838d7ba213
commit
14269faa3a
|
@ -22,29 +22,29 @@ automatically when you submit a PR.
|
|||
|
||||
Smoke Tests are located in `siem/cypress/integration/smoke_tests`
|
||||
|
||||
## Test Helpers
|
||||
## Structure
|
||||
|
||||
_Test helpers_ are functions that may be re-used across tests.
|
||||
### Tasks
|
||||
|
||||
- Reusable code and CSS selectors should be added to
|
||||
`siem/cypress/integration/lib`, as described below.
|
||||
_Tasks_ are functions that my be re-used across tests. Inside the _tasks_ folder there are some other folders that represents
|
||||
the page to which we will perform the actions. For each folder we are going to create a file for each one of the sections that
|
||||
has the page.
|
||||
|
||||
### Reusable Test Helper Functions and CSS Selectors
|
||||
i.e.
|
||||
- tasks
|
||||
- hosts
|
||||
- events.ts
|
||||
|
||||
The `cypress/integration/lib` directory contains code intended to be re-used
|
||||
across many different tests. Add reusable test helper functions and CSS
|
||||
selectors to directories under `cypress/integration/lib`.
|
||||
### Screens
|
||||
|
||||
- Files named `helpers.ts` (e.g. `siem/cypress/integration/lib/login/helpers.ts`)
|
||||
contain functions (e.g. `login`) that may be imported and invoked from multiple tests.
|
||||
In _screens_ folder we are going to find all the elements we want to interact in our tests. Inside _screens_ fonder there
|
||||
are some other folders that represents the page that contains the elements the tests are going to interact with. For each
|
||||
folder we are going to create a file for each one of the sections that the page has.
|
||||
|
||||
- Files named `selectors.ts` export CSS selectors for re-use. For example,
|
||||
`siem/cypress/integration/lib/login/selectors.ts` exports the following selector
|
||||
that matches the Username text area in the Kibana login page:
|
||||
|
||||
```sh
|
||||
export const USERNAME = '[data-test-subj="loginUsername"]';
|
||||
```
|
||||
i.e.
|
||||
- tasks
|
||||
- hosts
|
||||
- events.ts
|
||||
|
||||
## Mock Data
|
||||
|
||||
|
|
|
@ -9,25 +9,31 @@ import {
|
|||
FIELDS_BROWSER_CONTAINER,
|
||||
FIELDS_BROWSER_SELECTED_CATEGORY_TITLE,
|
||||
FIELDS_BROWSER_TITLE,
|
||||
} from '../../lib/fields_browser/selectors';
|
||||
FIELDS_BROWSER_CHECKBOX,
|
||||
} from '../../../screens/hosts/fields_browser';
|
||||
import { HOSTS_PAGE } from '../../lib/urls';
|
||||
import { loginAndWaitForPage, DEFAULT_TIMEOUT } from '../../lib/util/helpers';
|
||||
import { loginAndWaitForPage } from '../../../tasks/login';
|
||||
import { openEventsViewerFieldsBrowser, filterSearchBar } from '../../lib/events_viewer/helpers';
|
||||
import { closeFieldsBrowser } from '../../../tasks/hosts/fields_browsers';
|
||||
import { openEvents } from '../../../tasks/hosts/main';
|
||||
import {
|
||||
clickOutsideFieldsBrowser,
|
||||
openEventsViewerFieldsBrowser,
|
||||
filterSearchBar,
|
||||
} from '../../lib/events_viewer/helpers';
|
||||
closeModal,
|
||||
opensInspectQueryModal,
|
||||
waitsForEventsToBeLoaded,
|
||||
addsHostGeoCityNameToHeader,
|
||||
addsHostGeoCountryNameToHeader,
|
||||
resetFields,
|
||||
} from '../../../tasks/hosts/events';
|
||||
|
||||
import {
|
||||
CLOSE_MODAL,
|
||||
EVENTS_VIEWER_PANEL,
|
||||
HEADER_SUBTITLE,
|
||||
INSPECT_MODAL,
|
||||
INSPECT_QUERY,
|
||||
LOAD_MORE,
|
||||
LOCAL_EVENTS_COUNT,
|
||||
} from '../../lib/events_viewer/selectors';
|
||||
import { SERVER_SIDE_EVENT_COUNT } from '../../lib/timeline/selectors';
|
||||
import { clickEventsTab } from '../../lib/hosts/helpers';
|
||||
HOST_GEO_CITY_NAME_HEADER,
|
||||
HOST_GEO_COUNTRY_NAME_HEADER,
|
||||
} from '../../../screens/hosts/events';
|
||||
import { DEFAULT_TIMEOUT } from '../../lib/util/helpers';
|
||||
|
||||
const defaultHeadersInDefaultEcsCategory = [
|
||||
{ id: '@timestamp' },
|
||||
|
@ -43,7 +49,7 @@ describe('Events Viewer', () => {
|
|||
context('Fields rendering', () => {
|
||||
before(() => {
|
||||
loginAndWaitForPage(HOSTS_PAGE);
|
||||
clickEventsTab();
|
||||
openEvents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -51,7 +57,7 @@ describe('Events Viewer', () => {
|
|||
});
|
||||
|
||||
afterEach(() => {
|
||||
clickOutsideFieldsBrowser();
|
||||
closeFieldsBrowser();
|
||||
cy.get(FIELDS_BROWSER_CONTAINER).should('not.exist');
|
||||
});
|
||||
|
||||
|
@ -69,7 +75,7 @@ describe('Events Viewer', () => {
|
|||
|
||||
it('displays a checked checkbox for all of the default events viewer columns that are also in the default ECS category', () => {
|
||||
defaultHeadersInDefaultEcsCategory.forEach(header =>
|
||||
cy.get(`[data-test-subj="field-${header.id}-checkbox"]`).should('be.checked')
|
||||
cy.get(FIELDS_BROWSER_CHECKBOX(header.id)).should('be.checked')
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -77,26 +83,17 @@ describe('Events Viewer', () => {
|
|||
context('Events viewer query modal', () => {
|
||||
before(() => {
|
||||
loginAndWaitForPage(HOSTS_PAGE);
|
||||
clickEventsTab();
|
||||
openEvents();
|
||||
});
|
||||
|
||||
after(() => {
|
||||
cy.get(CLOSE_MODAL).click();
|
||||
closeModal();
|
||||
cy.get(INSPECT_MODAL, { timeout: DEFAULT_TIMEOUT }).should('not.exist');
|
||||
});
|
||||
|
||||
it('launches the inspect query modal when the inspect button is clicked', () => {
|
||||
// wait for data to load
|
||||
cy.get(SERVER_SIDE_EVENT_COUNT, { timeout: DEFAULT_TIMEOUT })
|
||||
.should('exist')
|
||||
.invoke('text', { timeout: DEFAULT_TIMEOUT })
|
||||
.should('not.equal', '0');
|
||||
|
||||
cy.get(INSPECT_QUERY, { timeout: DEFAULT_TIMEOUT })
|
||||
.should('exist')
|
||||
.trigger('mousemove', { force: true })
|
||||
.click({ force: true });
|
||||
|
||||
waitsForEventsToBeLoaded();
|
||||
opensInspectQueryModal();
|
||||
cy.get(INSPECT_MODAL, { timeout: DEFAULT_TIMEOUT }).should('exist');
|
||||
});
|
||||
});
|
||||
|
@ -104,7 +101,7 @@ describe('Events Viewer', () => {
|
|||
context('Events viewer fields behaviour', () => {
|
||||
before(() => {
|
||||
loginAndWaitForPage(HOSTS_PAGE);
|
||||
clickEventsTab();
|
||||
openEvents();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
|
@ -113,89 +110,55 @@ describe('Events Viewer', () => {
|
|||
|
||||
it('adds a field to the events viewer when the user clicks the checkbox', () => {
|
||||
const filterInput = 'host.geo.c';
|
||||
const toggleField = 'host.geo.city_name';
|
||||
|
||||
filterFieldsBrowser(filterInput);
|
||||
|
||||
cy.get(`${EVENTS_VIEWER_PANEL} [data-test-subj="header-text-${toggleField}"]`).should(
|
||||
'not.exist'
|
||||
);
|
||||
|
||||
cy.get(`${EVENTS_VIEWER_PANEL} [data-test-subj="field-${toggleField}-checkbox"]`).check({
|
||||
force: true,
|
||||
});
|
||||
|
||||
clickOutsideFieldsBrowser();
|
||||
|
||||
cy.get(`${EVENTS_VIEWER_PANEL} [data-test-subj="header-text-${toggleField}"]`).should(
|
||||
'exist'
|
||||
);
|
||||
cy.get(HOST_GEO_CITY_NAME_HEADER).should('not.exist');
|
||||
addsHostGeoCityNameToHeader();
|
||||
closeFieldsBrowser();
|
||||
cy.get(HOST_GEO_CITY_NAME_HEADER).should('exist');
|
||||
});
|
||||
|
||||
it('resets all fields in the events viewer when `Reset Fields` is clicked', () => {
|
||||
const filterInput = 'host.geo.c';
|
||||
const toggleField = 'host.geo.country_name';
|
||||
|
||||
filterFieldsBrowser(filterInput);
|
||||
|
||||
cy.get(`${EVENTS_VIEWER_PANEL} [data-test-subj="header-text-${toggleField}"]`).should(
|
||||
'not.exist'
|
||||
);
|
||||
|
||||
cy.get(`${EVENTS_VIEWER_PANEL} [data-test-subj="field-${toggleField}-checkbox"]`).check({
|
||||
force: true,
|
||||
});
|
||||
|
||||
cy.get(`${EVENTS_VIEWER_PANEL} [data-test-subj="reset-fields"]`).click({ force: true });
|
||||
|
||||
cy.get(`${EVENTS_VIEWER_PANEL} [data-test-subj="header-text-${toggleField}"]`).should(
|
||||
'not.exist'
|
||||
);
|
||||
cy.get(HOST_GEO_COUNTRY_NAME_HEADER).should('not.exist');
|
||||
addsHostGeoCountryNameToHeader();
|
||||
resetFields();
|
||||
cy.get(HOST_GEO_COUNTRY_NAME_HEADER).should('not.exist');
|
||||
});
|
||||
});
|
||||
|
||||
context('Events behaviour', () => {
|
||||
before(() => {
|
||||
loginAndWaitForPage(HOSTS_PAGE);
|
||||
clickEventsTab();
|
||||
openEvents();
|
||||
});
|
||||
|
||||
it('filters the events by applying filter criteria from the search bar at the top of the page', () => {
|
||||
const filterInput = '4bf34c1c-eaa9-46de-8921-67a4ccc49829'; // this will never match real data
|
||||
|
||||
waitsForEventsToBeLoaded();
|
||||
cy.get(HEADER_SUBTITLE)
|
||||
.invoke('text')
|
||||
.then(text1 => {
|
||||
cy.get(HEADER_SUBTITLE)
|
||||
.invoke('text', { timeout: DEFAULT_TIMEOUT })
|
||||
.should('not.equal', 'Showing: 0 events');
|
||||
|
||||
.then(initialNumberOfEvents => {
|
||||
filterSearchBar(filterInput);
|
||||
|
||||
cy.get(HEADER_SUBTITLE)
|
||||
.invoke('text')
|
||||
.should(text2 => {
|
||||
expect(text1).not.to.eq(text2);
|
||||
});
|
||||
.should('not.equal', initialNumberOfEvents);
|
||||
});
|
||||
});
|
||||
|
||||
it('loads more events when the load more button is clicked', () => {
|
||||
cy.get(LOCAL_EVENTS_COUNT, { timeout: DEFAULT_TIMEOUT })
|
||||
const defaultNumberOfLoadedEvents = '25';
|
||||
cy.get(LOCAL_EVENTS_COUNT)
|
||||
.invoke('text')
|
||||
.then(text1 => {
|
||||
cy.get(LOCAL_EVENTS_COUNT)
|
||||
.invoke('text')
|
||||
.should('equal', '25');
|
||||
.should('equal', defaultNumberOfLoadedEvents);
|
||||
|
||||
cy.get(LOAD_MORE).click({ force: true });
|
||||
cy.get(LOAD_MORE).click({ force: true });
|
||||
|
||||
cy.get(LOCAL_EVENTS_COUNT)
|
||||
.invoke('text')
|
||||
.should(text2 => {
|
||||
expect(text1).not.to.eq(text2);
|
||||
});
|
||||
});
|
||||
cy.get(LOCAL_EVENTS_COUNT)
|
||||
.invoke('text')
|
||||
.should('not.equal', defaultNumberOfLoadedEvents);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
36
x-pack/legacy/plugins/siem/cypress/screens/hosts/events.ts
Normal file
36
x-pack/legacy/plugins/siem/cypress/screens/hosts/events.ts
Normal file
|
@ -0,0 +1,36 @@
|
|||
/*
|
||||
* 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 EVENTS_VIEWER_PANEL = '[data-test-subj="events-viewer-panel"]';
|
||||
|
||||
export const CLOSE_MODAL = '[data-test-subj="modal-inspect-close"]';
|
||||
|
||||
export const HEADER_SUBTITLE = `${EVENTS_VIEWER_PANEL} [data-test-subj="header-panel-subtitle"]`;
|
||||
|
||||
export const INSPECT_MODAL = '[data-test-subj="modal-inspect-euiModal"]';
|
||||
|
||||
export const INSPECT_QUERY = `${EVENTS_VIEWER_PANEL} [data-test-subj="inspect-icon-button"]`;
|
||||
|
||||
export const LOAD_MORE = `${EVENTS_VIEWER_PANEL} [data-test-subj="TimelineMoreButton"]`;
|
||||
|
||||
export const LOCAL_EVENTS_COUNT = `${EVENTS_VIEWER_PANEL} [data-test-subj="local-events-count"]`;
|
||||
|
||||
export const SERVER_SIDE_EVENT_COUNT = '[data-test-subj="server-side-event-count"]';
|
||||
|
||||
export const HOST_GEO_CITY_NAME_HEADER = '[data-test-subj="header-text-host.geo.city_name"]';
|
||||
|
||||
export const HOST_GEO_CITY_NAME_CHECKBOX = '[data-test-subj="field-host.geo.city_name-checkbox"]';
|
||||
|
||||
export const HOST_GEO_COUNTRY_NAME_HEADER = '[data-test-subj="header-text-host.geo.country_name"]';
|
||||
|
||||
export const HOST_GEO_COUNTRY_NAME_CHECKBOX =
|
||||
'[data-test-subj="field-host.geo.country_name-checkbox"]';
|
||||
|
||||
export const FIELDS_BROWSER_CONTAINER = '[data-test-subj="fields-browser-container"]';
|
||||
|
||||
export const EVENTS_VIEWER_FIELDS_BUTTON = `${EVENTS_VIEWER_PANEL} [data-test-subj="show-field-browser-gear"]`;
|
||||
|
||||
export const RESET_FIELDS = `${EVENTS_VIEWER_PANEL} [data-test-subj="reset-fields"]`;
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
/** Clicking this button in the timeline opens the Fields browser */
|
||||
export const TIMELINE_FIELDS_BUTTON =
|
||||
'[data-test-subj="timeline"] [data-test-subj="show-field-browser"]';
|
||||
|
||||
/** The title displayed in the fields browser (i.e. Customize Columns) */
|
||||
export const FIELDS_BROWSER_TITLE = '[data-test-subj="field-browser-title"]';
|
||||
|
||||
/** Contains the body of the fields browser */
|
||||
export const FIELDS_BROWSER_CONTAINER = '[data-test-subj="fields-browser-container"]';
|
||||
|
||||
/** The title of the selected category in the right-hand side of the fields browser */
|
||||
export const FIELDS_BROWSER_SELECTED_CATEGORY_TITLE = '[data-test-subj="selected-category-title"]';
|
||||
|
||||
export const FIELDS_BROWSER_CHECKBOX = (id: string) => {
|
||||
return `[data-test-subj="field-${id}-checkbox`;
|
||||
};
|
9
x-pack/legacy/plugins/siem/cypress/screens/hosts/main.ts
Normal file
9
x-pack/legacy/plugins/siem/cypress/screens/hosts/main.ts
Normal file
|
@ -0,0 +1,9 @@
|
|||
/*
|
||||
* 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 EVENTS_TAB = '[data-test-subj="navigation-events"]';
|
||||
|
||||
export const KQL_SEARCH_BAR = '[data-test-subj="queryInput"]';
|
66
x-pack/legacy/plugins/siem/cypress/tasks/hosts/events.ts
Normal file
66
x-pack/legacy/plugins/siem/cypress/tasks/hosts/events.ts
Normal file
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* 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 { DEFAULT_TIMEOUT } from '../../integration/lib/util/helpers';
|
||||
import {
|
||||
EVENTS_VIEWER_FIELDS_BUTTON,
|
||||
CLOSE_MODAL,
|
||||
INSPECT_QUERY,
|
||||
SERVER_SIDE_EVENT_COUNT,
|
||||
HOST_GEO_CITY_NAME_CHECKBOX,
|
||||
HOST_GEO_COUNTRY_NAME_CHECKBOX,
|
||||
FIELDS_BROWSER_CONTAINER,
|
||||
RESET_FIELDS,
|
||||
LOAD_MORE,
|
||||
} from '../../screens/hosts/events';
|
||||
|
||||
export const closeModal = () => {
|
||||
cy.get(CLOSE_MODAL, { timeout: DEFAULT_TIMEOUT }).click();
|
||||
};
|
||||
|
||||
export const opensInspectQueryModal = () => {
|
||||
cy.get(INSPECT_QUERY, { timeout: DEFAULT_TIMEOUT })
|
||||
.should('exist')
|
||||
.trigger('mousemove', { force: true })
|
||||
.click({ force: true });
|
||||
};
|
||||
|
||||
export const waitsForEventsToBeLoaded = () => {
|
||||
cy.get(SERVER_SIDE_EVENT_COUNT, { timeout: DEFAULT_TIMEOUT })
|
||||
.should('exist')
|
||||
.invoke('text', { timeout: DEFAULT_TIMEOUT })
|
||||
.should('not.equal', '0');
|
||||
};
|
||||
|
||||
export const addsHostGeoCityNameToHeader = () => {
|
||||
cy.get(HOST_GEO_CITY_NAME_CHECKBOX).check({
|
||||
force: true,
|
||||
});
|
||||
};
|
||||
|
||||
export const addsHostGeoCountryNameToHeader = () => {
|
||||
cy.get(HOST_GEO_COUNTRY_NAME_CHECKBOX).check({
|
||||
force: true,
|
||||
});
|
||||
};
|
||||
|
||||
export const resetFields = () => {
|
||||
cy.get(RESET_FIELDS).click({ force: true });
|
||||
};
|
||||
|
||||
export const openEventsViewerFieldsBrowser = () => {
|
||||
cy.get(EVENTS_VIEWER_FIELDS_BUTTON, { timeout: DEFAULT_TIMEOUT }).click({ force: true });
|
||||
|
||||
cy.get(SERVER_SIDE_EVENT_COUNT, { timeout: DEFAULT_TIMEOUT })
|
||||
.invoke('text')
|
||||
.should('not.equal', '0');
|
||||
|
||||
cy.get(FIELDS_BROWSER_CONTAINER).should('exist');
|
||||
};
|
||||
|
||||
export const loadMoreEvents = () => {
|
||||
cy.get(LOAD_MORE).click({ force: true });
|
||||
};
|
|
@ -0,0 +1,12 @@
|
|||
/*
|
||||
* 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 { DEFAULT_TIMEOUT } from '../../integration/lib/util/helpers';
|
||||
import { KQL_SEARCH_BAR } from '../../screens/hosts/main';
|
||||
|
||||
export const closeFieldsBrowser = () => {
|
||||
cy.get(KQL_SEARCH_BAR, { timeout: DEFAULT_TIMEOUT }).click();
|
||||
};
|
13
x-pack/legacy/plugins/siem/cypress/tasks/hosts/main.ts
Normal file
13
x-pack/legacy/plugins/siem/cypress/tasks/hosts/main.ts
Normal file
|
@ -0,0 +1,13 @@
|
|||
/*
|
||||
* 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 { DEFAULT_TIMEOUT } from '../../integration/lib/util/helpers';
|
||||
|
||||
import { EVENTS_TAB } from '../../screens/hosts/main';
|
||||
|
||||
/** Clicks the Events tab on the hosts page */
|
||||
export const openEvents = () =>
|
||||
cy.get(EVENTS_TAB, { timeout: DEFAULT_TIMEOUT }).click({ force: true });
|
24
x-pack/legacy/plugins/siem/cypress/tasks/login.ts
Normal file
24
x-pack/legacy/plugins/siem/cypress/tasks/login.ts
Normal file
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* 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 { login } from '../integration/lib/login/helpers';
|
||||
|
||||
/** The default time in ms to wait for a Cypress command to complete */
|
||||
export const DEFAULT_TIMEOUT = 30 * 1000;
|
||||
|
||||
/**
|
||||
* Authenticates with Kibana, visits the specified `url`, and waits for the
|
||||
* Kibana logo to be displayed before continuing
|
||||
*/
|
||||
export const loginAndWaitForPage = (url: string) => {
|
||||
login();
|
||||
|
||||
cy.visit(`${Cypress.config().baseUrl}${url}`);
|
||||
|
||||
cy.viewport('macbook-15');
|
||||
|
||||
cy.contains('a', 'SIEM', { timeout: DEFAULT_TIMEOUT });
|
||||
};
|
Loading…
Reference in a new issue