diff --git a/package.json b/package.json index 58495c49d295b..ee811b428b87b 100644 --- a/package.json +++ b/package.json @@ -349,7 +349,7 @@ "@babel/traverse": "^7.11.5", "@babel/types": "^7.11.0", "@cypress/snapshot": "^2.1.7", - "@cypress/webpack-preprocessor": "^5.4.11", + "@cypress/webpack-preprocessor": "^5.5.0", "@elastic/apm-rum": "^5.6.1", "@elastic/apm-rum-react": "^1.2.5", "@elastic/charts": "24.4.0", @@ -604,7 +604,7 @@ "cpy": "^8.1.1", "cronstrue": "^1.51.0", "css-loader": "^3.4.2", - "cypress": "^6.1.0", + "cypress": "^6.2.1", "cypress-cucumber-preprocessor": "^2.5.2", "cypress-multi-reporters": "^1.4.0", "d3": "3.5.17", diff --git a/packages/kbn-es-archiver/src/actions/empty_kibana_index.ts b/packages/kbn-es-archiver/src/actions/empty_kibana_index.ts index d61d544deadc4..5f4e37ee35edf 100644 --- a/packages/kbn-es-archiver/src/actions/empty_kibana_index.ts +++ b/packages/kbn-es-archiver/src/actions/empty_kibana_index.ts @@ -20,7 +20,7 @@ import { Client } from 'elasticsearch'; import { ToolingLog, KbnClient } from '@kbn/dev-utils'; -import { migrateKibanaIndex, deleteKibanaIndices, createStats } from '../lib'; +import { migrateKibanaIndex, createStats, cleanKibanaIndices } from '../lib'; export async function emptyKibanaIndexAction({ client, @@ -32,8 +32,9 @@ export async function emptyKibanaIndexAction({ kbnClient: KbnClient; }) { const stats = createStats('emptyKibanaIndex', log); + const kibanaPluginIds = await kbnClient.plugins.getEnabledIds(); - await deleteKibanaIndices({ client, stats, log }); + await cleanKibanaIndices({ client, stats, log, kibanaPluginIds }); await migrateKibanaIndex({ client, kbnClient }); return stats; } diff --git a/packages/kbn-es-archiver/src/lib/index.ts b/packages/kbn-es-archiver/src/lib/index.ts index 960d51e411859..ac7569ba735ac 100644 --- a/packages/kbn-es-archiver/src/lib/index.ts +++ b/packages/kbn-es-archiver/src/lib/index.ts @@ -25,6 +25,7 @@ export { createGenerateIndexRecordsStream, deleteKibanaIndices, migrateKibanaIndex, + cleanKibanaIndices, createDefaultSpace, } from './indices'; diff --git a/packages/kbn-es-archiver/src/lib/indices/index.ts b/packages/kbn-es-archiver/src/lib/indices/index.ts index 289ac87feb9a5..076582ddde8ab 100644 --- a/packages/kbn-es-archiver/src/lib/indices/index.ts +++ b/packages/kbn-es-archiver/src/lib/indices/index.ts @@ -20,4 +20,9 @@ export { createCreateIndexStream } from './create_index_stream'; export { createDeleteIndexStream } from './delete_index_stream'; export { createGenerateIndexRecordsStream } from './generate_index_records_stream'; -export { migrateKibanaIndex, deleteKibanaIndices, createDefaultSpace } from './kibana_index'; +export { + migrateKibanaIndex, + deleteKibanaIndices, + cleanKibanaIndices, + createDefaultSpace, +} from './kibana_index'; diff --git a/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts b/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts index 427771cd77591..be7a19c096931 100644 --- a/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts +++ b/packages/kbn-es-archiver/src/lib/indices/kibana_index.ts @@ -73,6 +73,7 @@ export async function migrateKibanaIndex({ body: { dynamic: true, }, + ignore: [404], } as any); await kbnClient.savedObjects.migrate(); diff --git a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_edit.test.tsx b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_edit.test.tsx index af53c4d81a276..17bf5cf9c6cfc 100644 --- a/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_edit.test.tsx +++ b/x-pack/plugins/index_management/__jest__/client_integration/index_template_wizard/template_edit.test.tsx @@ -71,6 +71,10 @@ describe('', () => { const templateToEdit = fixtures.getTemplate({ name: 'index_template_without_mappings', indexPatterns: ['indexPattern1'], + dataStream: { + hidden: true, + anyUnknownKey: 'should_be_kept', + }, }); beforeAll(() => { @@ -85,7 +89,7 @@ describe('', () => { testBed.component.update(); }); - it('allows you to add mappings', async () => { + test('allows you to add mappings', async () => { const { actions, find } = testBed; // Logistics await actions.completeStepOne(); @@ -123,11 +127,15 @@ describe('', () => { const expected = { name: 'index_template_without_mappings', indexPatterns: ['indexPattern1'], + dataStream: { + hidden: true, + anyUnknownKey: 'should_be_kept', + }, version, _kbnMeta: { type: 'default', isLegacy: templateToEdit._kbnMeta.isLegacy, - hasDatastream: false, + hasDatastream: true, }, }; @@ -152,6 +160,47 @@ describe('', () => { expect(exists('requestTab')).toBe(true); }); + + test('should keep data stream configuration', async () => { + const { actions } = testBed; + // Logistics + await actions.completeStepOne({ + name: 'test', + indexPatterns: ['myPattern*'], + version: 1, + }); + // Component templates + await actions.completeStepTwo(); + // Index settings + await actions.completeStepThree(); + // Mappings + await actions.completeStepFour(); + // Aliases + await actions.completeStepFive(); + + await act(async () => { + actions.clickNextButton(); + }); + + const latestRequest = server.requests[server.requests.length - 1]; + + const expected = { + name: 'test', + indexPatterns: ['myPattern*'], + dataStream: { + hidden: true, + anyUnknownKey: 'should_be_kept', + }, + version: 1, + _kbnMeta: { + type: 'default', + isLegacy: false, + hasDatastream: true, + }, + }; + + expect(JSON.parse(JSON.parse(latestRequest.requestBody).body)).toEqual(expected); + }); }); describe('with mappings', () => { diff --git a/x-pack/plugins/index_management/common/types/templates.ts b/x-pack/plugins/index_management/common/types/templates.ts index d1b51fe5b89bf..7b442b9dd2935 100644 --- a/x-pack/plugins/index_management/common/types/templates.ts +++ b/x-pack/plugins/index_management/common/types/templates.ts @@ -46,7 +46,11 @@ export interface TemplateDeserialized { name: string; }; _meta?: { [key: string]: any }; // Composable template only - dataStream?: {}; // Composable template only + // Composable template only + dataStream?: { + hidden?: boolean; + [key: string]: any; + }; _kbnMeta: { type: TemplateType; hasDatastream: boolean; diff --git a/x-pack/plugins/index_management/public/application/components/template_form/steps/step_logistics.tsx b/x-pack/plugins/index_management/public/application/components/template_form/steps/step_logistics.tsx index 89e857eec0bb3..bbc3656195470 100644 --- a/x-pack/plugins/index_management/public/application/components/template_form/steps/step_logistics.tsx +++ b/x-pack/plugins/index_management/public/application/components/template_form/steps/step_logistics.tsx @@ -55,7 +55,7 @@ function getFieldsMeta(esDocsBase: string) { ), testSubject: 'indexPatternsField', }, - dataStream: { + createDataStream: { title: i18n.translate('xpack.idxMgmt.templateForm.stepLogistics.dataStreamTitle', { defaultMessage: 'Data stream', }), @@ -119,6 +119,7 @@ interface LogisticsForm { interface LogisticsFormInternal extends LogisticsForm { addMeta: boolean; + doCreateDataStream: boolean; } interface Props { @@ -132,12 +133,16 @@ function formDeserializer(formData: LogisticsForm): LogisticsFormInternal { return { ...formData, addMeta: Boolean(formData._meta && Object.keys(formData._meta).length), + doCreateDataStream: Boolean(formData.dataStream), }; } -function formSerializer(formData: LogisticsFormInternal): LogisticsForm { - const { addMeta, ...rest } = formData; - return rest; +function getformSerializer(initialTemplateData: LogisticsForm = {}) { + return (formData: LogisticsFormInternal): LogisticsForm => { + const { addMeta, doCreateDataStream, ...rest } = formData; + const dataStream = doCreateDataStream ? initialTemplateData.dataStream ?? {} : undefined; + return { ...rest, dataStream }; + }; } export const StepLogistics: React.FunctionComponent = React.memo( @@ -146,7 +151,7 @@ export const StepLogistics: React.FunctionComponent = React.memo( schema: schemas.logistics, defaultValue, options: { stripEmptyFields: false }, - serializer: formSerializer, + serializer: getformSerializer(defaultValue), deserializer: formDeserializer, }); const { @@ -178,7 +183,7 @@ export const StepLogistics: React.FunctionComponent = React.memo( }); }, [onChange, isFormValid, validate, getFormData]); - const { name, indexPatterns, dataStream, order, priority, version } = getFieldsMeta( + const { name, indexPatterns, createDataStream, order, priority, version } = getFieldsMeta( documentationService.getEsDocsBase() ); @@ -245,10 +250,10 @@ export const StepLogistics: React.FunctionComponent = React.memo( {/* Create data stream */} {isLegacy !== true && ( - + )} diff --git a/x-pack/plugins/index_management/public/application/components/template_form/template_form_schemas.tsx b/x-pack/plugins/index_management/public/application/components/template_form/template_form_schemas.tsx index c85126f08685e..2bc146c118ba2 100644 --- a/x-pack/plugins/index_management/public/application/components/template_form/template_form_schemas.tsx +++ b/x-pack/plugins/index_management/public/application/components/template_form/template_form_schemas.tsx @@ -129,31 +129,12 @@ export const schemas: Record = { }, ], }, - dataStream: { + doCreateDataStream: { type: FIELD_TYPES.TOGGLE, label: i18n.translate('xpack.idxMgmt.templateForm.stepLogistics.datastreamLabel', { defaultMessage: 'Create data stream', }), defaultValue: false, - serializer: (value) => { - if (value === true) { - // For now, ES expects an empty object when defining a data stream - // https://github.com/elastic/elasticsearch/pull/59317 - return {}; - } - }, - deserializer: (value) => { - if (typeof value === 'boolean') { - return value; - } - - /** - * For now, it is enough to have a "data_stream" declared on the index template - * to assume that the template creates a data stream. In the future, this condition - * might change - */ - return value !== undefined; - }, }, order: { type: FIELD_TYPES.NUMBER, diff --git a/x-pack/plugins/index_management/server/routes/api/templates/validate_schemas.ts b/x-pack/plugins/index_management/server/routes/api/templates/validate_schemas.ts index 18c74716a35b6..3dab4113e6965 100644 --- a/x-pack/plugins/index_management/server/routes/api/templates/validate_schemas.ts +++ b/x-pack/plugins/index_management/server/routes/api/templates/validate_schemas.ts @@ -20,7 +20,14 @@ export const templateSchema = schema.object({ }) ), composedOf: schema.maybe(schema.arrayOf(schema.string())), - dataStream: schema.maybe(schema.object({}, { unknowns: 'allow' })), + dataStream: schema.maybe( + schema.object( + { + hidden: schema.maybe(schema.boolean()), + }, + { unknowns: 'allow' } + ) + ), _meta: schema.maybe(schema.object({}, { unknowns: 'allow' })), ilmPolicy: schema.maybe( schema.object({ diff --git a/x-pack/plugins/index_management/test/fixtures/template.ts b/x-pack/plugins/index_management/test/fixtures/template.ts index 016100faea601..90f556794a5d9 100644 --- a/x-pack/plugins/index_management/test/fixtures/template.ts +++ b/x-pack/plugins/index_management/test/fixtures/template.ts @@ -53,6 +53,7 @@ export const getTemplate = ({ order = getRandomNumber(), indexPatterns = [], template: { settings, aliases, mappings } = {}, + dataStream, hasDatastream = false, isLegacy = false, type = 'default', @@ -73,12 +74,13 @@ export const getTemplate = ({ mappings, settings, }, + dataStream, hasSettings: objHasProperties(settings), hasMappings: objHasProperties(mappings), hasAliases: objHasProperties(aliases), _kbnMeta: { type, - hasDatastream, + hasDatastream: dataStream !== undefined ? true : hasDatastream, isLegacy, }, }; diff --git a/x-pack/plugins/security_solution/cypress/cypress.json b/x-pack/plugins/security_solution/cypress/cypress.json index 6feb9d794740d..6a9a240af5873 100644 --- a/x-pack/plugins/security_solution/cypress/cypress.json +++ b/x-pack/plugins/security_solution/cypress/cypress.json @@ -2,6 +2,7 @@ "baseUrl": "http://localhost:5601", "defaultCommandTimeout": 60000, "execTimeout": 120000, + "pageLoadTimeout": 120000, "nodeVersion": "system", "retries": { "runMode": 2 diff --git a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_callouts_readonly.spec.ts b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_callouts_readonly.spec.ts index 4bf54963a5322..5e501d2d51627 100644 --- a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_callouts_readonly.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_callouts_readonly.spec.ts @@ -39,7 +39,7 @@ describe('Detections > Callouts indicating read-only access to resources', () => const RULES_CALLOUT = 'read-only-access-to-rules'; before(() => { - // First, we have to open the app on behalf of a priviledged user in order to initialize it. + // First, we have to open the app on behalf of a privileged user in order to initialize it. // Otherwise the app will be disabled and show a "welcome"-like page. cleanKibana(); loginAndWaitForPageWithoutDateRange(DETECTIONS_URL, ROLES.platform_engineer); diff --git a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules.spec.ts b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules.spec.ts index 9eb2127acb446..125848c85a84a 100644 --- a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules.spec.ts @@ -31,14 +31,13 @@ import { loginAndWaitForPageWithoutDateRange } from '../tasks/login'; import { DEFAULT_RULE_REFRESH_INTERVAL_VALUE } from '../../common/constants'; import { DETECTIONS_URL } from '../urls/navigation'; -import { createCustomRule, removeSignalsIndex } from '../tasks/api_calls/rules'; +import { createCustomRule } from '../tasks/api_calls/rules'; import { cleanKibana } from '../tasks/common'; import { existingRule, newOverrideRule, newRule, newThresholdRule } from '../objects/rule'; describe('Alerts detection rules', () => { beforeEach(() => { cleanKibana(); - removeSignalsIndex(); loginAndWaitForPageWithoutDateRange(DETECTIONS_URL); waitForAlertsPanelToBeLoaded(); waitForAlertsIndexToBeCreated(); diff --git a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_custom.spec.ts b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_custom.spec.ts index 2de8069870848..dff39567ecacd 100644 --- a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_custom.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_custom.spec.ts @@ -112,35 +112,39 @@ describe('Custom detection rules creation', () => { const expectedMitre = formatMitreAttackDescription(newRule.mitre); const expectedNumberOfRules = 1; - const rule = { ...newRule }; - beforeEach(() => { cleanKibana(); createTimeline(newRule.timeline).then((response) => { - rule.timeline.id = response.body.data.persistTimeline.timeline.savedObjectId; + cy.wrap({ + ...newRule, + timeline: { + ...newRule.timeline, + id: response.body.data.persistTimeline.timeline.savedObjectId, + }, + }).as('rule'); }); }); - it('Creates and activates a new rule', () => { + it('Creates and activates a new rule', function () { loginAndWaitForPageWithoutDateRange(DETECTIONS_URL); waitForAlertsPanelToBeLoaded(); waitForAlertsIndexToBeCreated(); goToManageAlertsDetectionRules(); waitForLoadElasticPrebuiltDetectionRulesTableToBeLoaded(); goToCreateNewRule(); - fillDefineCustomRuleWithImportedQueryAndContinue(rule); - fillAboutRuleAndContinue(rule); - fillScheduleRuleAndContinue(rule); + fillDefineCustomRuleWithImportedQueryAndContinue(this.rule); + fillAboutRuleAndContinue(this.rule); + fillScheduleRuleAndContinue(this.rule); // expect define step to repopulate cy.get(DEFINE_EDIT_BUTTON).click(); - cy.get(CUSTOM_QUERY_INPUT).should('have.value', rule.customQuery); + cy.get(CUSTOM_QUERY_INPUT).should('have.value', this.rule.customQuery); cy.get(DEFINE_CONTINUE_BUTTON).should('exist').click({ force: true }); cy.get(DEFINE_CONTINUE_BUTTON).should('not.exist'); // expect about step to populate cy.get(ABOUT_EDIT_BUTTON).click(); - cy.get(RULE_NAME_INPUT).invoke('val').should('eql', rule.name); + cy.get(RULE_NAME_INPUT).invoke('val').should('eql', this.rule.name); cy.get(ABOUT_CONTINUE_BTN).should('exist').click({ force: true }); cy.get(ABOUT_CONTINUE_BTN).should('not.exist'); @@ -160,18 +164,18 @@ describe('Custom detection rules creation', () => { cy.get(RULES_TABLE).then(($table) => { cy.wrap($table.find(RULES_ROW).length).should('eql', 1); }); - cy.get(RULE_NAME).should('have.text', rule.name); - cy.get(RISK_SCORE).should('have.text', rule.riskScore); - cy.get(SEVERITY).should('have.text', rule.severity); + cy.get(RULE_NAME).should('have.text', this.rule.name); + cy.get(RISK_SCORE).should('have.text', this.rule.riskScore); + cy.get(SEVERITY).should('have.text', this.rule.severity); cy.get(RULE_SWITCH).should('have.attr', 'aria-checked', 'true'); goToRuleDetails(); - cy.get(RULE_NAME_HEADER).should('have.text', `${rule.name}`); - cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', rule.description); + cy.get(RULE_NAME_HEADER).should('have.text', `${this.rule.name}`); + cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', this.rule.description); cy.get(ABOUT_DETAILS).within(() => { - getDetails(SEVERITY_DETAILS).should('have.text', rule.severity); - getDetails(RISK_SCORE_DETAILS).should('have.text', rule.riskScore); + getDetails(SEVERITY_DETAILS).should('have.text', this.rule.severity); + getDetails(RISK_SCORE_DETAILS).should('have.text', this.rule.riskScore); getDetails(REFERENCE_URLS_DETAILS).should((details) => { expect(removeExternalLinkText(details.text())).equal(expectedUrls); }); @@ -185,7 +189,7 @@ describe('Custom detection rules creation', () => { cy.get(ABOUT_INVESTIGATION_NOTES).should('have.text', INVESTIGATION_NOTES_MARKDOWN); cy.get(DEFINITION_DETAILS).within(() => { getDetails(INDEX_PATTERNS_DETAILS).should('have.text', indexPatterns.join('')); - getDetails(CUSTOM_QUERY_DETAILS).should('have.text', rule.customQuery); + getDetails(CUSTOM_QUERY_DETAILS).should('have.text', this.rule.customQuery); getDetails(RULE_TYPE_DETAILS).should('have.text', 'Query'); getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', 'None'); }); @@ -203,12 +207,12 @@ describe('Custom detection rules creation', () => { waitForTheRuleToBeExecuted(); waitForAlertsToPopulate(); - cy.get(NUMBER_OF_ALERTS).invoke('text').then(parseFloat).should('be.above', 0); - cy.get(ALERT_RULE_NAME).first().should('have.text', rule.name); + cy.get(NUMBER_OF_ALERTS).should(($count) => expect(+$count.text()).to.be.gte(1)); + cy.get(ALERT_RULE_NAME).first().should('have.text', this.rule.name); cy.get(ALERT_RULE_VERSION).first().should('have.text', '1'); cy.get(ALERT_RULE_METHOD).first().should('have.text', 'query'); - cy.get(ALERT_RULE_SEVERITY).first().should('have.text', rule.severity.toLowerCase()); - cy.get(ALERT_RULE_RISK_SCORE).first().should('have.text', rule.riskScore); + cy.get(ALERT_RULE_SEVERITY).first().should('have.text', this.rule.severity.toLowerCase()); + cy.get(ALERT_RULE_RISK_SCORE).first().should('have.text', this.rule.riskScore); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_eql.spec.ts b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_eql.spec.ts index 6567ee07c4e3a..b4d39385cd411 100644 --- a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_eql.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_eql.spec.ts @@ -77,7 +77,7 @@ import { loginAndWaitForPageWithoutDateRange } from '../tasks/login'; import { DETECTIONS_URL } from '../urls/navigation'; -describe.skip('Detection rules, EQL', () => { +describe('Detection rules, EQL', () => { const expectedUrls = eqlRule.referenceUrls.join(''); const expectedFalsePositives = eqlRule.falsePositivesExamples.join(''); const expectedTags = eqlRule.tags.join(''); @@ -85,16 +85,20 @@ describe.skip('Detection rules, EQL', () => { const expectedNumberOfRules = 1; const expectedNumberOfAlerts = 7; - const rule = { ...eqlRule }; - beforeEach(() => { cleanKibana(); createTimeline(eqlRule.timeline).then((response) => { - rule.timeline.id = response.body.data.persistTimeline.timeline.savedObjectId; + cy.wrap({ + ...eqlRule, + timeline: { + ...eqlRule.timeline, + id: response.body.data.persistTimeline.timeline.savedObjectId, + }, + }).as('rule'); }); }); - it('Creates and activates a new EQL rule', () => { + it('Creates and activates a new EQL rule', function () { loginAndWaitForPageWithoutDateRange(DETECTIONS_URL); waitForAlertsPanelToBeLoaded(); waitForAlertsIndexToBeCreated(); @@ -102,9 +106,9 @@ describe.skip('Detection rules, EQL', () => { waitForLoadElasticPrebuiltDetectionRulesTableToBeLoaded(); goToCreateNewRule(); selectEqlRuleType(); - fillDefineEqlRuleAndContinue(rule); - fillAboutRuleAndContinue(rule); - fillScheduleRuleAndContinue(rule); + fillDefineEqlRuleAndContinue(this.rule); + fillAboutRuleAndContinue(this.rule); + fillScheduleRuleAndContinue(this.rule); createAndActivateRule(); cy.get(CUSTOM_RULES_BTN).should('have.text', 'Custom rules (1)'); @@ -121,18 +125,18 @@ describe.skip('Detection rules, EQL', () => { cy.get(RULES_TABLE).then(($table) => { cy.wrap($table.find(RULES_ROW).length).should('eql', 1); }); - cy.get(RULE_NAME).should('have.text', rule.name); - cy.get(RISK_SCORE).should('have.text', rule.riskScore); - cy.get(SEVERITY).should('have.text', rule.severity); + cy.get(RULE_NAME).should('have.text', this.rule.name); + cy.get(RISK_SCORE).should('have.text', this.rule.riskScore); + cy.get(SEVERITY).should('have.text', this.rule.severity); cy.get(RULE_SWITCH).should('have.attr', 'aria-checked', 'true'); goToRuleDetails(); - cy.get(RULE_NAME_HEADER).should('have.text', `${rule.name}`); - cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', rule.description); + cy.get(RULE_NAME_HEADER).should('have.text', `${this.rule.name}`); + cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', this.rule.description); cy.get(ABOUT_DETAILS).within(() => { - getDetails(SEVERITY_DETAILS).should('have.text', rule.severity); - getDetails(RISK_SCORE_DETAILS).should('have.text', rule.riskScore); + getDetails(SEVERITY_DETAILS).should('have.text', this.rule.severity); + getDetails(RISK_SCORE_DETAILS).should('have.text', this.rule.riskScore); getDetails(REFERENCE_URLS_DETAILS).should((details) => { expect(removeExternalLinkText(details.text())).equal(expectedUrls); }); @@ -146,18 +150,18 @@ describe.skip('Detection rules, EQL', () => { cy.get(ABOUT_INVESTIGATION_NOTES).should('have.text', INVESTIGATION_NOTES_MARKDOWN); cy.get(DEFINITION_DETAILS).within(() => { getDetails(INDEX_PATTERNS_DETAILS).should('have.text', indexPatterns.join('')); - getDetails(CUSTOM_QUERY_DETAILS).should('have.text', rule.customQuery); + getDetails(CUSTOM_QUERY_DETAILS).should('have.text', this.rule.customQuery); getDetails(RULE_TYPE_DETAILS).should('have.text', 'Event Correlation'); getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', 'None'); }); cy.get(SCHEDULE_DETAILS).within(() => { getDetails(RUNS_EVERY_DETAILS).should( 'have.text', - `${rule.runsEvery.interval}${rule.runsEvery.type}` + `${this.rule.runsEvery.interval}${this.rule.runsEvery.type}` ); getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should( 'have.text', - `${rule.lookBack.interval}${rule.lookBack.type}` + `${this.rule.lookBack.interval}${this.rule.lookBack.type}` ); }); @@ -165,27 +169,32 @@ describe.skip('Detection rules, EQL', () => { waitForAlertsToPopulate(); cy.get(NUMBER_OF_ALERTS).should('have.text', expectedNumberOfAlerts); - cy.get(ALERT_RULE_NAME).first().should('have.text', rule.name); + cy.get(ALERT_RULE_NAME).first().should('have.text', this.rule.name); cy.get(ALERT_RULE_VERSION).first().should('have.text', '1'); cy.get(ALERT_RULE_METHOD).first().should('have.text', 'eql'); - cy.get(ALERT_RULE_SEVERITY).first().should('have.text', rule.severity.toLowerCase()); - cy.get(ALERT_RULE_RISK_SCORE).first().should('have.text', rule.riskScore); + cy.get(ALERT_RULE_SEVERITY).first().should('have.text', this.rule.severity.toLowerCase()); + cy.get(ALERT_RULE_RISK_SCORE).first().should('have.text', this.rule.riskScore); }); }); -describe.skip('Detection rules, sequence EQL', () => { +describe('Detection rules, sequence EQL', () => { const expectedNumberOfRules = 1; const expectedNumberOfSequenceAlerts = 1; - const rule = { ...eqlSequenceRule }; beforeEach(() => { cleanKibana(); createTimeline(eqlSequenceRule.timeline).then((response) => { - rule.timeline.id = response.body.data.persistTimeline.timeline.savedObjectId; + cy.wrap({ + ...eqlSequenceRule, + timeline: { + ...eqlSequenceRule.timeline, + id: response.body.data.persistTimeline.timeline.savedObjectId, + }, + }).as('rule'); }); }); - it('Creates and activates a new EQL rule with a sequence', () => { + it('Creates and activates a new EQL rule with a sequence', function () { loginAndWaitForPageWithoutDateRange(DETECTIONS_URL); waitForAlertsPanelToBeLoaded(); waitForAlertsIndexToBeCreated(); @@ -193,9 +202,9 @@ describe.skip('Detection rules, sequence EQL', () => { waitForLoadElasticPrebuiltDetectionRulesTableToBeLoaded(); goToCreateNewRule(); selectEqlRuleType(); - fillDefineEqlRuleAndContinue(rule); - fillAboutRuleAndContinue(rule); - fillScheduleRuleAndContinue(rule); + fillDefineEqlRuleAndContinue(this.rule); + fillAboutRuleAndContinue(this.rule); + fillScheduleRuleAndContinue(this.rule); createAndActivateRule(); cy.get(CUSTOM_RULES_BTN).should('have.text', 'Custom rules (1)'); @@ -213,10 +222,10 @@ describe.skip('Detection rules, sequence EQL', () => { waitForAlertsToPopulate(); cy.get(NUMBER_OF_ALERTS).should('have.text', expectedNumberOfSequenceAlerts); - cy.get(ALERT_RULE_NAME).first().should('have.text', rule.name); + cy.get(ALERT_RULE_NAME).first().should('have.text', this.rule.name); cy.get(ALERT_RULE_VERSION).first().should('have.text', '1'); cy.get(ALERT_RULE_METHOD).first().should('have.text', 'eql'); - cy.get(ALERT_RULE_SEVERITY).first().should('have.text', rule.severity.toLowerCase()); - cy.get(ALERT_RULE_RISK_SCORE).first().should('have.text', rule.riskScore); + cy.get(ALERT_RULE_SEVERITY).first().should('have.text', this.rule.severity.toLowerCase()); + cy.get(ALERT_RULE_RISK_SCORE).first().should('have.text', this.rule.riskScore); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_export.spec.ts b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_export.spec.ts index 0f5ce9c47a439..f33ecd3f49a8c 100644 --- a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_export.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_export.spec.ts @@ -17,8 +17,7 @@ import { loginAndWaitForPageWithoutDateRange } from '../tasks/login'; import { DETECTIONS_URL } from '../urls/navigation'; -describe.skip('Export rules', () => { - let ruleResponse: Cypress.Response; +describe('Export rules', () => { beforeEach(() => { cleanKibana(); cy.intercept( @@ -28,16 +27,14 @@ describe.skip('Export rules', () => { loginAndWaitForPageWithoutDateRange(DETECTIONS_URL); waitForAlertsPanelToBeLoaded(); waitForAlertsIndexToBeCreated(); - createCustomRule(newRule).then((response) => { - ruleResponse = response; - }); + createCustomRule(newRule).as('ruleResponse'); }); - it('Exports a custom rule', () => { + it('Exports a custom rule', function () { goToManageAlertsDetectionRules(); exportFirstRule(); cy.wait('@export').then(({ response }) => { - cy.wrap(response!.body).should('eql', expectedExportedRule(ruleResponse)); + cy.wrap(response!.body).should('eql', expectedExportedRule(this.ruleResponse)); }); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_ml.spec.ts b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_ml.spec.ts index baefcba945447..0813b51cd84c3 100644 --- a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_ml.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_ml.spec.ts @@ -88,7 +88,7 @@ describe.skip('Detection rules, machine learning', () => { fillScheduleRuleAndContinue(machineLearningRule); createAndActivateRule(); - cy.get(CUSTOM_RULES_BTN).invoke('text').should('eql', 'Custom rules (1)'); + cy.get(CUSTOM_RULES_BTN).should('have.text', 'Custom rules (1)'); changeToThreeHundredRowsPerPage(); waitForRulesToBeLoaded(); diff --git a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_override.spec.ts b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_override.spec.ts index c641d572f515c..9c7074f48cf96 100644 --- a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_override.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_override.spec.ts @@ -5,7 +5,7 @@ */ import { formatMitreAttackDescription } from '../helpers/rules'; -import { indexPatterns, newOverrideRule, severitiesOverride } from '../objects/rule'; +import { indexPatterns, newOverrideRule, severitiesOverride, OverrideRule } from '../objects/rule'; import { NUMBER_OF_ALERTS, @@ -89,25 +89,29 @@ describe('Detection rules, override', () => { const expectedTags = newOverrideRule.tags.join(''); const expectedMitre = formatMitreAttackDescription(newOverrideRule.mitre); - const rule = { ...newOverrideRule }; - beforeEach(() => { cleanKibana(); createTimeline(newOverrideRule.timeline).then((response) => { - rule.timeline.id = response.body.data.persistTimeline.timeline.savedObjectId; + cy.wrap({ + ...newOverrideRule, + timeline: { + ...newOverrideRule.timeline, + id: response.body.data.persistTimeline.timeline.savedObjectId, + }, + }).as('rule'); }); }); - it('Creates and activates a new custom rule with override option', () => { + it('Creates and activates a new custom rule with override option', function () { loginAndWaitForPageWithoutDateRange(DETECTIONS_URL); waitForAlertsPanelToBeLoaded(); waitForAlertsIndexToBeCreated(); goToManageAlertsDetectionRules(); waitForLoadElasticPrebuiltDetectionRulesTableToBeLoaded(); goToCreateNewRule(); - fillDefineCustomRuleWithImportedQueryAndContinue(rule); - fillAboutRuleWithOverrideAndContinue(rule); - fillScheduleRuleAndContinue(rule); + fillDefineCustomRuleWithImportedQueryAndContinue(this.rule); + fillAboutRuleWithOverrideAndContinue(this.rule); + fillScheduleRuleAndContinue(this.rule); createAndActivateRule(); cy.get(CUSTOM_RULES_BTN).should('have.text', 'Custom rules (1)'); @@ -125,23 +129,23 @@ describe('Detection rules, override', () => { cy.get(RULES_TABLE).then(($table) => { cy.wrap($table.find(RULES_ROW).length).should('eql', 1); }); - cy.get(RULE_NAME).should('have.text', rule.name); - cy.get(RISK_SCORE).should('have.text', rule.riskScore); - cy.get(SEVERITY).should('have.text', rule.severity); + cy.get(RULE_NAME).should('have.text', this.rule.name); + cy.get(RISK_SCORE).should('have.text', this.rule.riskScore); + cy.get(SEVERITY).should('have.text', this.rule.severity); cy.get(RULE_SWITCH).should('have.attr', 'aria-checked', 'true'); goToRuleDetails(); - cy.get(RULE_NAME_HEADER).should('have.text', `${rule.name}`); - cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', rule.description); + cy.get(RULE_NAME_HEADER).should('have.text', `${this.rule.name}`); + cy.get(ABOUT_RULE_DESCRIPTION).should('have.text', this.rule.description); cy.get(ABOUT_DETAILS).within(() => { - getDetails(SEVERITY_DETAILS).should('have.text', rule.severity); - getDetails(RISK_SCORE_DETAILS).should('have.text', rule.riskScore); + getDetails(SEVERITY_DETAILS).should('have.text', this.rule.severity); + getDetails(RISK_SCORE_DETAILS).should('have.text', this.rule.riskScore); getDetails(RISK_SCORE_OVERRIDE_DETAILS).should( 'have.text', - `${rule.riskOverride}signal.rule.risk_score` + `${this.rule.riskOverride}signal.rule.risk_score` ); - getDetails(RULE_NAME_OVERRIDE_DETAILS).should('have.text', rule.nameOverride); + getDetails(RULE_NAME_OVERRIDE_DETAILS).should('have.text', this.rule.nameOverride); getDetails(REFERENCE_URLS_DETAILS).should((details) => { expect(removeExternalLinkText(details.text())).equal(expectedUrls); }); @@ -150,11 +154,11 @@ describe('Detection rules, override', () => { expect(removeExternalLinkText(mitre.text())).equal(expectedMitre); }); getDetails(TAGS_DETAILS).should('have.text', expectedTags); - getDetails(TIMESTAMP_OVERRIDE_DETAILS).should('have.text', rule.timestampOverride); + getDetails(TIMESTAMP_OVERRIDE_DETAILS).should('have.text', this.rule.timestampOverride); cy.contains(DETAILS_TITLE, 'Severity override') .invoke('index', DETAILS_TITLE) // get index relative to other titles, not all siblings .then((severityOverrideIndex) => { - rule.severityOverride.forEach((severity, i) => { + (this.rule as OverrideRule).severityOverride.forEach((severity, i) => { cy.get(DETAILS_DESCRIPTION) .eq(severityOverrideIndex + i) .should( @@ -168,25 +172,25 @@ describe('Detection rules, override', () => { cy.get(ABOUT_INVESTIGATION_NOTES).should('have.text', INVESTIGATION_NOTES_MARKDOWN); cy.get(DEFINITION_DETAILS).within(() => { getDetails(INDEX_PATTERNS_DETAILS).should('have.text', indexPatterns.join('')); - getDetails(CUSTOM_QUERY_DETAILS).should('have.text', rule.customQuery); + getDetails(CUSTOM_QUERY_DETAILS).should('have.text', this.rule.customQuery); getDetails(RULE_TYPE_DETAILS).should('have.text', 'Query'); getDetails(TIMELINE_TEMPLATE_DETAILS).should('have.text', 'None'); }); cy.get(SCHEDULE_DETAILS).within(() => { getDetails(RUNS_EVERY_DETAILS).should( 'have.text', - `${rule.runsEvery.interval}${rule.runsEvery.type}` + `${this.rule.runsEvery.interval}${this.rule.runsEvery.type}` ); getDetails(ADDITIONAL_LOOK_BACK_DETAILS).should( 'have.text', - `${rule.lookBack.interval}${rule.lookBack.type}` + `${this.rule.lookBack.interval}${this.rule.lookBack.type}` ); }); waitForTheRuleToBeExecuted(); waitForAlertsToPopulate(); - cy.get(NUMBER_OF_ALERTS).invoke('text').then(parseFloat).should('be.above', 0); + cy.get(NUMBER_OF_ALERTS).should(($count) => expect(+$count.text()).to.be.gte(1)); cy.get(ALERT_RULE_NAME).first().should('have.text', 'auditbeat'); cy.get(ALERT_RULE_VERSION).first().should('have.text', '1'); cy.get(ALERT_RULE_METHOD).first().should('have.text', 'query'); diff --git a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_threshold.spec.ts b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_threshold.spec.ts index 058bac6258ffc..96d7c3d5d5a84 100644 --- a/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_threshold.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/alerts_detection_rules_threshold.spec.ts @@ -169,7 +169,7 @@ describe.skip('Detection rules, threshold', () => { waitForTheRuleToBeExecuted(); waitForAlertsToPopulate(); - cy.get(NUMBER_OF_ALERTS).invoke('text').then(parseFloat).should('be.below', 100); + cy.get(NUMBER_OF_ALERTS).should(($count) => expect(+$count.text()).to.be.lt(100)); cy.get(ALERT_RULE_NAME).first().should('have.text', rule.name); cy.get(ALERT_RULE_VERSION).first().should('have.text', '1'); cy.get(ALERT_RULE_METHOD).first().should('have.text', 'threshold'); diff --git a/x-pack/plugins/security_solution/cypress/integration/cases.spec.ts b/x-pack/plugins/security_solution/cypress/integration/cases.spec.ts index 18325401d9abc..9fa9d83ec85ea 100644 --- a/x-pack/plugins/security_solution/cypress/integration/cases.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/cases.spec.ts @@ -26,7 +26,7 @@ import { import { CASE_DETAILS_DESCRIPTION, CASE_DETAILS_PAGE_TITLE, - CASE_DETAILS_PUSH_TO_EXTERNAL_SERVICE_BTN, + // CASE_DETAILS_PUSH_TO_EXTERNAL_SERVICE_BTN, CASE_DETAILS_STATUS, CASE_DETAILS_TAGS, CASE_DETAILS_USER_ACTION_DESCRIPTION_USERNAME, @@ -52,20 +52,26 @@ import { loginAndWaitForPageWithoutDateRange } from '../tasks/login'; import { CASES_URL } from '../urls/navigation'; describe('Cases', () => { - const mycase = { ...case1 }; - beforeEach(() => { cleanKibana(); - createTimeline(case1.timeline).then((response) => { - mycase.timeline.id = response.body.data.persistTimeline.timeline.savedObjectId; - }); + createTimeline(case1.timeline).then((response) => + cy + .wrap({ + ...case1, + timeline: { + ...case1.timeline, + id: response.body.data.persistTimeline.timeline.savedObjectId, + }, + }) + .as('mycase') + ); }); - it('Creates a new case with timeline and opens the timeline', () => { + it('Creates a new case with timeline and opens the timeline', function () { loginAndWaitForPageWithoutDateRange(CASES_URL); goToCreateNewCase(); - fillCasesMandatoryfields(mycase); - attachTimeline(mycase); + fillCasesMandatoryfields(this.mycase); + attachTimeline(this.mycase); createCase(); backToCases(); @@ -76,9 +82,9 @@ describe('Cases', () => { cy.get(ALL_CASES_OPEN_CASES_COUNT).should('have.text', 'Open (1)'); cy.get(ALL_CASES_REPORTERS_COUNT).should('have.text', 'Reporter1'); cy.get(ALL_CASES_TAGS_COUNT).should('have.text', 'Tags2'); - cy.get(ALL_CASES_NAME).should('have.text', mycase.name); - cy.get(ALL_CASES_REPORTER).should('have.text', mycase.reporter); - mycase.tags.forEach((tag, index) => { + cy.get(ALL_CASES_NAME).should('have.text', this.mycase.name); + cy.get(ALL_CASES_REPORTER).should('have.text', this.mycase.reporter); + (this.mycase as typeof case1).tags.forEach((tag, index) => { cy.get(ALL_CASES_TAGS(index)).should('have.text', tag); }); cy.get(ALL_CASES_COMMENTS_COUNT).should('have.text', '0'); @@ -89,24 +95,24 @@ describe('Cases', () => { goToCaseDetails(); - const expectedTags = mycase.tags.join(''); - cy.get(CASE_DETAILS_PAGE_TITLE).should('have.text', mycase.name); + const expectedTags = this.mycase.tags.join(''); + cy.get(CASE_DETAILS_PAGE_TITLE).should('have.text', this.mycase.name); cy.get(CASE_DETAILS_STATUS).should('have.text', 'Open'); - cy.get(CASE_DETAILS_USER_ACTION_DESCRIPTION_USERNAME).should('have.text', mycase.reporter); + cy.get(CASE_DETAILS_USER_ACTION_DESCRIPTION_USERNAME).should('have.text', this.mycase.reporter); cy.get(CASE_DETAILS_USER_ACTION_DESCRIPTION_EVENT).should('have.text', 'added description'); cy.get(CASE_DETAILS_DESCRIPTION).should( 'have.text', - `${mycase.description} ${mycase.timeline.title}` + `${this.mycase.description} ${this.mycase.timeline.title}` ); - cy.get(CASE_DETAILS_USERNAMES).eq(REPORTER).should('have.text', mycase.reporter); - cy.get(CASE_DETAILS_USERNAMES).eq(PARTICIPANTS).should('have.text', mycase.reporter); + cy.get(CASE_DETAILS_USERNAMES).eq(REPORTER).should('have.text', this.mycase.reporter); + cy.get(CASE_DETAILS_USERNAMES).eq(PARTICIPANTS).should('have.text', this.mycase.reporter); cy.get(CASE_DETAILS_TAGS).should('have.text', expectedTags); - cy.get(CASE_DETAILS_PUSH_TO_EXTERNAL_SERVICE_BTN).should('have.attr', 'disabled'); + // cy.get(CASE_DETAILS_PUSH_TO_EXTERNAL_SERVICE_BTN).should('have.attr', 'disabled'); openCaseTimeline(); - cy.get(TIMELINE_TITLE).contains(mycase.timeline.title); - cy.get(TIMELINE_DESCRIPTION).contains(mycase.timeline.description); - cy.get(TIMELINE_QUERY).invoke('text').should('eq', mycase.timeline.query); + cy.get(TIMELINE_TITLE).contains(this.mycase.timeline.title); + cy.get(TIMELINE_DESCRIPTION).contains(this.mycase.timeline.description); + cy.get(TIMELINE_QUERY).should('have.text', this.mycase.timeline.query); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/events_viewer.spec.ts b/x-pack/plugins/security_solution/cypress/integration/events_viewer.spec.ts index 4e34dcac1873d..721ce277338f6 100644 --- a/x-pack/plugins/security_solution/cypress/integration/events_viewer.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/events_viewer.spec.ts @@ -44,7 +44,7 @@ const defaultHeadersInDefaultEcsCategory = [ { id: 'destination.ip' }, ]; -describe.skip('Events Viewer', () => { +describe('Events Viewer', () => { context('Fields rendering', () => { before(() => { cleanKibana(); @@ -118,7 +118,7 @@ describe.skip('Events Viewer', () => { }); }); - context('Events behaviour', () => { + context('Events behavior', () => { before(() => { cleanKibana(); loginAndWaitForPage(HOSTS_URL); diff --git a/x-pack/plugins/security_solution/cypress/integration/ml_conditional_links.spec.ts b/x-pack/plugins/security_solution/cypress/integration/ml_conditional_links.spec.ts index 64e75c6b03387..8087e30bff609 100644 --- a/x-pack/plugins/security_solution/cypress/integration/ml_conditional_links.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/ml_conditional_links.spec.ts @@ -32,36 +32,34 @@ describe('ml conditional links', () => { it('sets the KQL from a single IP with a value for the query', () => { loginAndWaitForPageWithoutDateRange(mlNetworkSingleIpKqlQuery); - cy.get(KQL_INPUT) - .invoke('text') - .should('eq', '(process.name: "conhost.exe" or process.name: "sc.exe")'); + cy.get(KQL_INPUT).should( + 'have.text', + '(process.name: "conhost.exe" or process.name: "sc.exe")' + ); }); it('sets the KQL from a multiple IPs with a null for the query', () => { loginAndWaitForPageWithoutDateRange(mlNetworkMultipleIpNullKqlQuery); - cy.get(KQL_INPUT) - .invoke('text') - .should( - 'eq', - '((source.ip: "127.0.0.1" or destination.ip: "127.0.0.1") or (source.ip: "127.0.0.2" or destination.ip: "127.0.0.2"))' - ); + cy.get(KQL_INPUT).should( + 'have.text', + '((source.ip: "127.0.0.1" or destination.ip: "127.0.0.1") or (source.ip: "127.0.0.2" or destination.ip: "127.0.0.2"))' + ); }); it('sets the KQL from a multiple IPs with a value for the query', () => { loginAndWaitForPageWithoutDateRange(mlNetworkMultipleIpKqlQuery); - cy.get(KQL_INPUT) - .invoke('text') - .should( - 'eq', - '((source.ip: "127.0.0.1" or destination.ip: "127.0.0.1") or (source.ip: "127.0.0.2" or destination.ip: "127.0.0.2")) and ((process.name: "conhost.exe" or process.name: "sc.exe"))' - ); + cy.get(KQL_INPUT).should( + 'have.text', + '((source.ip: "127.0.0.1" or destination.ip: "127.0.0.1") or (source.ip: "127.0.0.2" or destination.ip: "127.0.0.2")) and ((process.name: "conhost.exe" or process.name: "sc.exe"))' + ); }); it('sets the KQL from a $ip$ with a value for the query', () => { loginAndWaitForPageWithoutDateRange(mlNetworkKqlQuery); - cy.get(KQL_INPUT) - .invoke('text') - .should('eq', '(process.name: "conhost.exe" or process.name: "sc.exe")'); + cy.get(KQL_INPUT).should( + 'have.text', + '(process.name: "conhost.exe" or process.name: "sc.exe")' + ); }); it('sets the KQL from a single host name with a value for query', () => { @@ -73,26 +71,26 @@ describe('ml conditional links', () => { it('sets the KQL from a multiple host names with null for query', () => { loginAndWaitForPageWithoutDateRange(mlHostMultiHostNullKqlQuery); - cy.get(KQL_INPUT) - .invoke('text') - .should('eq', '(host.name: "siem-windows" or host.name: "siem-suricata")'); + cy.get(KQL_INPUT).should( + 'have.text', + '(host.name: "siem-windows" or host.name: "siem-suricata")' + ); }); it('sets the KQL from a multiple host names with a value for query', () => { loginAndWaitForPageWithoutDateRange(mlHostMultiHostKqlQuery); - cy.get(KQL_INPUT) - .invoke('text') - .should( - 'eq', - '(host.name: "siem-windows" or host.name: "siem-suricata") and ((process.name: "conhost.exe" or process.name: "sc.exe"))' - ); + cy.get(KQL_INPUT).should( + 'have.text', + '(host.name: "siem-windows" or host.name: "siem-suricata") and ((process.name: "conhost.exe" or process.name: "sc.exe"))' + ); }); it('sets the KQL from a undefined/null host name but with a value for query', () => { loginAndWaitForPageWithoutDateRange(mlHostVariableHostKqlQuery); - cy.get(KQL_INPUT) - .invoke('text') - .should('eq', '(process.name: "conhost.exe" or process.name: "sc.exe")'); + cy.get(KQL_INPUT).should( + 'have.text', + '(process.name: "conhost.exe" or process.name: "sc.exe")' + ); }); it('redirects from a single IP with a null for the query', () => { diff --git a/x-pack/plugins/security_solution/cypress/integration/overview.spec.ts b/x-pack/plugins/security_solution/cypress/integration/overview.spec.ts index f72559b9f21e6..0b1ee9f84f910 100644 --- a/x-pack/plugins/security_solution/cypress/integration/overview.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/overview.spec.ts @@ -26,7 +26,7 @@ describe('Overview Page', () => { expandHostStats(); HOST_STATS.forEach((stat) => { - cy.get(stat.domId).invoke('text').should('eq', stat.value); + cy.get(stat.domId).should('have.text', stat.value); }); }); @@ -36,7 +36,7 @@ describe('Overview Page', () => { expandNetworkStats(); NETWORK_STATS.forEach((stat) => { - cy.get(stat.domId).invoke('text').should('eq', stat.value); + cy.get(stat.domId).should('have.text', stat.value); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/sourcerer.spec.ts b/x-pack/plugins/security_solution/cypress/integration/sourcerer.spec.ts index aa126e2f33c90..96007ca0326d1 100644 --- a/x-pack/plugins/security_solution/cypress/integration/sourcerer.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/sourcerer.spec.ts @@ -34,8 +34,10 @@ describe.skip('Sourcerer', () => { }); beforeEach(() => { + cy.clearLocalStorage(); loginAndWaitForPage(HOSTS_URL); }); + describe('Default scope', () => { it('has SIEM index patterns selected on initial load', () => { openSourcerer(); @@ -46,6 +48,7 @@ describe.skip('Sourcerer', () => { openSourcerer(); isSourcererOptions([`metrics-*`, `logs-*`]); }); + it('selected KIP gets added to sourcerer', () => { setSourcererOption(`metrics-*`); openSourcerer(); @@ -69,10 +72,12 @@ describe.skip('Sourcerer', () => { isNotSourcererSelection(`metrics-*`); }); }); + describe('Timeline scope', () => { const alertPatterns = ['.siem-signals-default']; const rawPatterns = ['auditbeat-*']; const allPatterns = [...alertPatterns, ...rawPatterns]; + it('Radio buttons select correct sourcerer patterns', () => { openTimelineUsingToggle(); openSourcerer('timeline'); @@ -84,6 +89,7 @@ describe.skip('Sourcerer', () => { alertPatterns.forEach((ss) => isSourcererSelection(ss, 'timeline')); rawPatterns.forEach((ss) => isNotSourcererSelection(ss, 'timeline')); }); + it('Adding an option results in the custom radio becoming active', () => { openTimelineUsingToggle(); openSourcerer('timeline'); @@ -94,17 +100,13 @@ describe.skip('Sourcerer', () => { openSourcerer('timeline'); isCustomRadio(); }); - it.skip('Selected index patterns are properly queried', () => { + + it('Selected index patterns are properly queried', () => { openTimelineUsingToggle(); populateTimeline(); openSourcerer('timeline'); deselectSourcererOptions(rawPatterns, 'timeline'); - cy.get(SERVER_SIDE_EVENT_COUNT) - .invoke('text') - .then((strCount) => { - const intCount = +strCount; - cy.wrap(intCount).should('eq', 0); - }); + cy.get(SERVER_SIDE_EVENT_COUNT).should(($count) => expect(+$count.text()).to.eql(0)); }); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/timeline_attach_to_case.spec.ts b/x-pack/plugins/security_solution/cypress/integration/timeline_attach_to_case.spec.ts index a0051eee0a22e..56b2ef00169dc 100644 --- a/x-pack/plugins/security_solution/cypress/integration/timeline_attach_to_case.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/timeline_attach_to_case.spec.ts @@ -20,66 +20,58 @@ import { createCase } from '../tasks/api_calls/cases'; // https://github.com/elastic/kibana/issues/86959 describe.skip('attach timeline to case', () => { - const myTimeline = { ...timeline }; - context('without cases created', () => { - before(() => { + beforeEach(() => { cleanKibana(); - createTimeline(timeline).then((response) => { - myTimeline.id = response.body.data.persistTimeline.timeline.savedObjectId; - }); + createTimeline(timeline).then((response) => + cy.wrap(response.body.data.persistTimeline.timeline).as('myTimeline') + ); }); - it('attach timeline to a new case', () => { - loginAndWaitForTimeline(myTimeline.id!); + it('attach timeline to a new case', function () { + loginAndWaitForTimeline(this.myTimeline.savedObjectId); attachTimelineToNewCase(); cy.location('origin').then((origin) => { cy.get(DESCRIPTION_INPUT).should( 'have.text', - `[${myTimeline.title}](${origin}/app/security/timelines?timeline=(id:%27${myTimeline.id}%27,isOpen:!t))` + `[${this.myTimeline.title}](${origin}/app/security/timelines?timeline=(id:%27${this.myTimeline.savedObjectId}%27,isOpen:!t))` ); }); }); - it('attach timeline to an existing case with no case', () => { - loginAndWaitForTimeline(myTimeline.id!); + it('attach timeline to an existing case with no case', function () { + loginAndWaitForTimeline(this.myTimeline.savedObjectId); attachTimelineToExistingCase(); addNewCase(); cy.location('origin').then((origin) => { cy.get(DESCRIPTION_INPUT).should( 'have.text', - `[${ - myTimeline.title - }](${origin}/app/security/timelines?timeline=(id:%27${myTimeline.id!}%27,isOpen:!t))` + `[${this.myTimeline.title}](${origin}/app/security/timelines?timeline=(id:%27${this.myTimeline.savedObjectId}%27,isOpen:!t))` ); }); }); }); context('with cases created', () => { - let timelineId: string; - let caseId: string; before(() => { cleanKibana(); - createTimeline(timeline).then((response) => { - timelineId = response.body.data.persistTimeline.timeline.savedObjectId; - }); - createCase(case1).then((response) => { - caseId = response.body.id; - }); + createTimeline(timeline).then((response) => + cy.wrap(response.body.data.persistTimeline.timeline.savedObjectId).as('timelineId') + ); + createCase(case1).then((response) => cy.wrap(response.body.id).as('caseId')); }); - it('attach timeline to an existing case', () => { - loginAndWaitForTimeline(timelineId); + it('attach timeline to an existing case', function () { + loginAndWaitForTimeline(this.timelineId); attachTimelineToExistingCase(); - selectCase(caseId); + selectCase(this.caseId); cy.location('origin').then((origin) => { cy.get(ADD_COMMENT_INPUT).should( 'have.text', - `[${timeline.title}](${origin}/app/security/timelines?timeline=(id:%27${timelineId}%27,isOpen:!t))` + `[${timeline.title}](${origin}/app/security/timelines?timeline=(id:%27${this.timelineId}%27,isOpen:!t))` ); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/timeline_creation.spec.ts b/x-pack/plugins/security_solution/cypress/integration/timeline_creation.spec.ts index a926a5ac4938a..cacf2802b6d71 100644 --- a/x-pack/plugins/security_solution/cypress/integration/timeline_creation.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/timeline_creation.spec.ts @@ -8,6 +8,7 @@ import { timeline } from '../objects/timeline'; import { FAVORITE_TIMELINE, LOCKED_ICON, + UNLOCKED_ICON, NOTES_TAB_BUTTON, NOTES_TEXT, // NOTES_COUNT, @@ -47,8 +48,6 @@ import { openTimeline } from '../tasks/timelines'; import { OVERVIEW_URL } from '../urls/navigation'; describe('Timelines', () => { - let timelineId: string; - beforeEach(() => { cleanKibana(); }); @@ -70,7 +69,7 @@ describe('Timelines', () => { addNameToTimeline(timeline.title); cy.wait('@timeline').then(({ response }) => { - timelineId = response!.body.data.persistTimeline.timeline.savedObjectId; + const timelineId = response!.body.data.persistTimeline.timeline.savedObjectId; addDescriptionToTimeline(timeline.description); addNotesToTimeline(timeline.notes); @@ -96,6 +95,7 @@ describe('Timelines', () => { cy.get(PIN_EVENT) .should('have.attr', 'aria-label') .and('match', /Unpin the event in row 2/); + cy.get(UNLOCKED_ICON).should('be.visible'); cy.get(NOTES_TAB_BUTTON).click(); cy.get(NOTES_TEXT_AREA).should('exist'); diff --git a/x-pack/plugins/security_solution/cypress/integration/timeline_local_storage.spec.ts b/x-pack/plugins/security_solution/cypress/integration/timeline_local_storage.spec.ts index 1d0256dbfbdc9..f5091dd893446 100644 --- a/x-pack/plugins/security_solution/cypress/integration/timeline_local_storage.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/timeline_local_storage.spec.ts @@ -20,24 +20,21 @@ describe.skip('persistent timeline', () => { loginAndWaitForPage(HOSTS_URL); openEvents(); waitsForEventsToBeLoaded(); + cy.get(DRAGGABLE_HEADER).then((header) => + cy.wrap(header.length - 1).as('expectedNumberOfTimelineColumns') + ); }); - it('persist the deletion of a column', () => { - cy.get(DRAGGABLE_HEADER).then((header) => { - const currentNumberOfTimelineColumns = header.length; - const expectedNumberOfTimelineColumns = currentNumberOfTimelineColumns - 1; + it('persist the deletion of a column', function () { + cy.get(DRAGGABLE_HEADER).eq(TABLE_COLUMN_EVENTS_MESSAGE).should('have.text', 'message'); + removeColumn(TABLE_COLUMN_EVENTS_MESSAGE); - cy.wrap(header).eq(TABLE_COLUMN_EVENTS_MESSAGE).invoke('text').should('equal', 'message'); - removeColumn(TABLE_COLUMN_EVENTS_MESSAGE); + cy.get(DRAGGABLE_HEADER).should('have.length', this.expectedNumberOfTimelineColumns); - cy.get(DRAGGABLE_HEADER).should('have.length', expectedNumberOfTimelineColumns); - - reload(waitsForEventsToBeLoaded); + reload(); + waitsForEventsToBeLoaded(); - cy.get(DRAGGABLE_HEADER).should('have.length', expectedNumberOfTimelineColumns); - cy.get(DRAGGABLE_HEADER).each(($el) => { - expect($el.text()).not.equal('message'); - }); - }); + cy.get(DRAGGABLE_HEADER).should('have.length', this.expectedNumberOfTimelineColumns); + cy.get(DRAGGABLE_HEADER).each(($el) => expect($el.text()).not.equal('message')); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/timeline_search_or_filter.spec.ts b/x-pack/plugins/security_solution/cypress/integration/timeline_search_or_filter.spec.ts index 52274329034b1..54a717e7a29e7 100644 --- a/x-pack/plugins/security_solution/cypress/integration/timeline_search_or_filter.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/timeline_search_or_filter.spec.ts @@ -13,7 +13,7 @@ import { executeTimelineKQL } from '../tasks/timeline'; import { HOSTS_URL } from '../urls/navigation'; -describe.skip('timeline search or filter KQL bar', () => { +describe('timeline search or filter KQL bar', () => { beforeEach(() => { cleanKibana(); loginAndWaitForPage(HOSTS_URL); @@ -24,11 +24,6 @@ describe.skip('timeline search or filter KQL bar', () => { openTimelineUsingToggle(); executeTimelineKQL(hostExistsQuery); - cy.get(SERVER_SIDE_EVENT_COUNT) - .invoke('text') - .then((strCount) => { - const intCount = +strCount; - cy.wrap(intCount).should('be.above', 0); - }); + cy.get(SERVER_SIDE_EVENT_COUNT).should(($count) => expect(+$count.text()).to.be.gt(0)); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/timeline_templates_export.spec.ts b/x-pack/plugins/security_solution/cypress/integration/timeline_templates_export.spec.ts index f2af37c939d02..cc526b53033a5 100644 --- a/x-pack/plugins/security_solution/cypress/integration/timeline_templates_export.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/timeline_templates_export.spec.ts @@ -16,24 +16,24 @@ import { createTimelineTemplate } from '../tasks/api_calls/timelines'; import { cleanKibana } from '../tasks/common'; describe('Export timelines', () => { - let templateResponse: Cypress.Response; - let templateId: string; - beforeEach(() => { cleanKibana(); cy.intercept('POST', 'api/timeline/_export?file_name=timelines_export.ndjson').as('export'); createTimelineTemplate(timelineTemplate).then((response) => { - templateResponse = response; - templateId = response.body.data.persistTimeline.timeline.savedObjectId; + cy.wrap(response).as('templateResponse'); + cy.wrap(response.body.data.persistTimeline.timeline.savedObjectId).as('templateId'); }); }); - it('Exports a custom timeline template', () => { + it('Exports a custom timeline template', function () { loginAndWaitForPageWithoutDateRange(TIMELINE_TEMPLATES_URL); - exportTimeline(templateId!); + exportTimeline(this.templateId); cy.wait('@export').then(({ response }) => { - cy.wrap(response!.body).should('eql', expectedExportedTimelineTemplate(templateResponse)); + cy.wrap(response!.body).should( + 'eql', + expectedExportedTimelineTemplate(this.templateResponse) + ); }); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/timelines_export.spec.ts b/x-pack/plugins/security_solution/cypress/integration/timelines_export.spec.ts index a75074baeef54..cba9cfb2579f1 100644 --- a/x-pack/plugins/security_solution/cypress/integration/timelines_export.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/timelines_export.spec.ts @@ -13,25 +13,23 @@ import { expectedExportedTimeline, timeline } from '../objects/timeline'; import { cleanKibana } from '../tasks/common'; describe('Export timelines', () => { - let timelineResponse: Cypress.Response; - let timelineId: string; beforeEach(() => { cleanKibana(); cy.intercept('POST', '/api/timeline/_export?file_name=timelines_export.ndjson').as('export'); createTimeline(timeline).then((response) => { - timelineResponse = response; - timelineId = response.body.data.persistTimeline.timeline.savedObjectId; + cy.wrap(response).as('timelineResponse'); + cy.wrap(response.body.data.persistTimeline.timeline.savedObjectId).as('timelineId'); }); }); - it('Exports a custom timeline', () => { + it('Exports a custom timeline', function () { loginAndWaitForPageWithoutDateRange(TIMELINES_URL); waitForTimelinesPanelToBeLoaded(); - exportTimeline(timelineId); + exportTimeline(this.timelineId); cy.wait('@export').then(({ response }) => { cy.wrap(response!.statusCode).should('eql', 200); - cy.wrap(response!.body).should('eql', expectedExportedTimeline(timelineResponse)); + cy.wrap(response!.body).should('eql', expectedExportedTimeline(this.timelineResponse)); }); }); }); diff --git a/x-pack/plugins/security_solution/cypress/integration/url_state.spec.ts b/x-pack/plugins/security_solution/cypress/integration/url_state.spec.ts index a13ae62eb7f84..18f14e8d8b12f 100644 --- a/x-pack/plugins/security_solution/cypress/integration/url_state.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/url_state.spec.ts @@ -49,9 +49,8 @@ const ABSOLUTE_DATE = { startTimeTimeline: '2019-08-02T20:03:29.186Z', }; -// FLAKY: https://github.com/elastic/kibana/issues/61612 -describe.skip('url state', () => { - before(() => { +describe('url state', () => { + beforeEach(() => { cleanKibana(); }); @@ -142,12 +141,12 @@ describe.skip('url state', () => { it('sets kql on network page', () => { loginAndWaitForPageWithoutDateRange(ABSOLUTE_DATE_RANGE.urlKqlNetworkNetwork); - cy.get(KQL_INPUT).invoke('text').should('eq', 'source.ip: "10.142.0.9"'); + cy.get(KQL_INPUT).should('have.text', 'source.ip: "10.142.0.9"'); }); it('sets kql on hosts page', () => { loginAndWaitForPageWithoutDateRange(ABSOLUTE_DATE_RANGE.urlKqlHostsHosts); - cy.get(KQL_INPUT).invoke('text').should('eq', 'source.ip: "10.142.0.9"'); + cy.get(KQL_INPUT).should('have.text', 'source.ip: "10.142.0.9"'); }); it('sets the url state when kql is set', () => { @@ -188,7 +187,7 @@ describe.skip('url state', () => { 'href', `/app/security/network?query=(language:kuery,query:'host.name:%20%22siem-kibana%22%20')&sourcerer=(default:!(\'auditbeat-*\'))&timerange=(global:(linkTo:!(timeline),timerange:(from:'2019-08-01T20:03:29.186Z',kind:absolute,to:'2020-01-01T21:33:29.186Z')),timeline:(linkTo:!(global),timerange:(from:'2019-08-01T20:03:29.186Z',kind:absolute,to:'2020-01-01T21:33:29.186Z')))` ); - cy.get(HOSTS_NAMES).first().invoke('text').should('eq', 'siem-kibana'); + cy.get(HOSTS_NAMES).first().should('have.text', 'siem-kibana'); openFirstHostDetails(); clearSearchBar(); @@ -218,7 +217,7 @@ describe.skip('url state', () => { it('Do not clears kql when navigating to a new page', () => { loginAndWaitForPageWithoutDateRange(ABSOLUTE_DATE_RANGE.urlKqlHostsHosts); navigateFromHeaderTo(NETWORK); - cy.get(KQL_INPUT).invoke('text').should('eq', 'source.ip: "10.142.0.9"'); + cy.get(KQL_INPUT).should('have.text', 'source.ip: "10.142.0.9"'); }); it('sets and reads the url state for timeline by id', () => { diff --git a/x-pack/plugins/security_solution/cypress/integration/value_lists.spec.ts b/x-pack/plugins/security_solution/cypress/integration/value_lists.spec.ts index ae0c4f35177a9..341ca31715356 100644 --- a/x-pack/plugins/security_solution/cypress/integration/value_lists.spec.ts +++ b/x-pack/plugins/security_solution/cypress/integration/value_lists.spec.ts @@ -26,14 +26,9 @@ import { exportValueList, } from '../tasks/lists'; import { VALUE_LISTS_TABLE, VALUE_LISTS_ROW, VALUE_LISTS_MODAL_ACTIVATOR } from '../screens/lists'; -import { cleanKibana } from '../tasks/common'; describe('value lists', () => { describe('management modal', () => { - before(() => { - cleanKibana(); - }); - beforeEach(() => { loginAndWaitForPageWithoutDateRange(DETECTIONS_URL); waitForAlertsPanelToBeLoaded(); diff --git a/x-pack/plugins/security_solution/cypress/screens/timeline.ts b/x-pack/plugins/security_solution/cypress/screens/timeline.ts index 627469e16218e..fef94da062e01 100644 --- a/x-pack/plugins/security_solution/cypress/screens/timeline.ts +++ b/x-pack/plugins/security_solution/cypress/screens/timeline.ts @@ -51,9 +51,12 @@ 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 UNLOCKED_ICON = '[data-test-subj="timeline-date-picker-unlock-button"]'; + export const NOTES = '[data-test-subj="note-card-body"]'; -export const NOTE_BY_NOTE_ID = (noteId: string) => `[data-test-subj="note-preview-${noteId}"]`; +export const NOTE_BY_NOTE_ID = (noteId: string) => + `[data-test-subj="note-preview-${noteId}"] .euiMarkdownFormat`; export const NOTE_CONTENT = (noteId: string) => `${NOTE_BY_NOTE_ID(noteId)} p`; diff --git a/x-pack/plugins/security_solution/cypress/tasks/alerts.ts b/x-pack/plugins/security_solution/cypress/tasks/alerts.ts index 39e57f39a145d..94b26fa2e56ea 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/alerts.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/alerts.ts @@ -110,13 +110,18 @@ export const waitForAlerts = () => { }; export const waitForAlertsIndexToBeCreated = () => { - cy.request({ url: '/api/detection_engine/index', retryOnStatusCodeFailure: true }).then( - (response) => { - if (response.status !== 200) { - cy.wait(7500); - } + cy.request({ + url: '/api/detection_engine/index', + failOnStatusCode: false, + }).then((response) => { + if (response.status !== 200) { + cy.request({ + method: 'POST', + url: `/api/detection_engine/index`, + headers: { 'kbn-xsrf': 'create-signals-index' }, + }); } - ); + }); }; export const waitForAlertsPanelToBeLoaded = () => { diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts b/x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts index 29cdf4ec2be5d..26cc7c87c3055 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/api_calls/rules.ts @@ -25,6 +25,7 @@ export const createCustomRule = (rule: CustomRule, ruleId = 'rule_testing') => enabled: false, }, headers: { 'kbn-xsrf': 'cypress-creds' }, + failOnStatusCode: false, }); export const createCustomRuleActivated = (rule: CustomRule, ruleId = 'rule_testing') => @@ -47,6 +48,7 @@ export const createCustomRuleActivated = (rule: CustomRule, ruleId = 'rule_testi tags: ['rule1'], }, headers: { 'kbn-xsrf': 'cypress-creds' }, + failOnStatusCode: false, }); export const deleteCustomRule = (ruleId = 'rule_testing') => { diff --git a/x-pack/plugins/security_solution/cypress/tasks/api_calls/timelines.ts b/x-pack/plugins/security_solution/cypress/tasks/api_calls/timelines.ts index 32c2af1a1866b..8cac4b90fef18 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/api_calls/timelines.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/api_calls/timelines.ts @@ -121,5 +121,5 @@ export const getTimelineById = (timelineId: string) => query: 'query GetOneTimeline($id: ID!, $timelineType: TimelineType) {\n getOneTimeline(id: $id, timelineType: $timelineType) {\n savedObjectId\n columns {\n aggregatable\n category\n columnHeaderType\n description\n example\n indexes\n id\n name\n searchable\n type\n __typename\n }\n dataProviders {\n id\n name\n enabled\n excluded\n kqlQuery\n type\n queryMatch {\n field\n displayField\n value\n displayValue\n operator\n __typename\n }\n and {\n id\n name\n enabled\n excluded\n kqlQuery\n type\n queryMatch {\n field\n displayField\n value\n displayValue\n operator\n __typename\n }\n __typename\n }\n __typename\n }\n dateRange {\n start\n end\n __typename\n }\n description\n eventType\n eventIdToNoteIds {\n eventId\n note\n timelineId\n noteId\n created\n createdBy\n timelineVersion\n updated\n updatedBy\n version\n __typename\n }\n excludedRowRendererIds\n favorite {\n fullName\n userName\n favoriteDate\n __typename\n }\n filters {\n meta {\n alias\n controlledBy\n disabled\n field\n formattedValue\n index\n key\n negate\n params\n type\n value\n __typename\n }\n query\n exists\n match_all\n missing\n range\n script\n __typename\n }\n kqlMode\n kqlQuery {\n filterQuery {\n kuery {\n kind\n expression\n __typename\n }\n serializedQuery\n __typename\n }\n __typename\n }\n indexNames\n notes {\n eventId\n note\n timelineId\n timelineVersion\n noteId\n created\n createdBy\n updated\n updatedBy\n version\n __typename\n }\n noteIds\n pinnedEventIds\n pinnedEventsSaveObject {\n pinnedEventId\n eventId\n timelineId\n created\n createdBy\n updated\n updatedBy\n version\n __typename\n }\n status\n title\n timelineType\n templateTimelineId\n templateTimelineVersion\n savedQueryId\n sort\n created\n createdBy\n updated\n updatedBy\n version\n __typename\n }\n}\n', }, - headers: { 'kbn-xsrf': '' }, + headers: { 'kbn-xsrf': 'timeline-by-id' }, }); diff --git a/x-pack/plugins/security_solution/cypress/tasks/common.ts b/x-pack/plugins/security_solution/cypress/tasks/common.ts index c14f50ca35c6b..cd8761ec3ddb2 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/common.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/common.ts @@ -4,8 +4,7 @@ * you may not use this file except in compliance with the Elastic License. */ -import { removeSignalsIndex } from './api_calls/rules'; -import { esArchiverLoadEmptyKibana } from './es_archiver'; +import { esArchiverResetKibana } from './es_archiver'; const primaryButton = 0; @@ -58,28 +57,76 @@ export const drop = (dropTarget: JQuery) => { .wait(300); }; -export const reload = (afterReload: () => void) => { +export const reload = () => { cy.reload(); cy.contains('a', 'Security'); - afterReload(); }; export const cleanKibana = () => { - const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana\*`; + const kibanaIndexUrl = `${Cypress.env('ELASTICSEARCH_URL')}/.kibana_\*`; + cy.request('POST', `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed`, { + query: { + bool: { + filter: [ + { + match: { + type: 'alert', + }, + }, + { + match: { + 'alert.alertTypeId': 'siem.signals', + }, + }, + { + match: { + 'alert.consumer': 'siem', + }, + }, + ], + }, + }, + }); - // Delete kibana indexes and wait until they are deleted - cy.request('DELETE', kibanaIndexUrl); - cy.waitUntil(() => { - cy.wait(500); - return cy.request(kibanaIndexUrl).then((response) => JSON.stringify(response.body) === '{}'); + cy.request('POST', `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed`, { + query: { + bool: { + filter: [ + { + match: { + type: 'cases', + }, + }, + ], + }, + }, }); - // Load kibana indexes and wait until they are created - esArchiverLoadEmptyKibana(); - cy.waitUntil(() => { - cy.wait(500); - return cy.request(kibanaIndexUrl).then((response) => JSON.stringify(response.body) !== '{}'); + cy.request('POST', `${kibanaIndexUrl}/_delete_by_query?conflicts=proceed`, { + query: { + bool: { + filter: [ + { + match: { + type: 'siem-ui-timeline', + }, + }, + ], + }, + }, }); - removeSignalsIndex(); + cy.request( + 'POST', + `${Cypress.env( + 'ELASTICSEARCH_URL' + )}/.lists-*,.items-*,.siem-signals-*/_delete_by_query?conflicts=proceed&scroll_size=10000`, + { + query: { + match_all: {}, + }, + } + ); + + esArchiverResetKibana(); }; diff --git a/x-pack/plugins/security_solution/cypress/tasks/date_picker.ts b/x-pack/plugins/security_solution/cypress/tasks/date_picker.ts index 2e1d3379dc202..0e75bc0df2c8c 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/date_picker.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/date_picker.ts @@ -62,15 +62,11 @@ export const setTimelineStartDate = (date: string) => { }; export const updateDates = () => { - cy.get(DATE_PICKER_APPLY_BUTTON) - .click({ force: true }) - .invoke('text') - .should('not.equal', 'Updating'); + cy.get(DATE_PICKER_APPLY_BUTTON).click({ force: true }).should('not.have.text', 'Updating'); }; export const updateTimelineDates = () => { cy.get(DATE_PICKER_APPLY_BUTTON_TIMELINE) .click({ force: true }) - .invoke('text') - .should('not.equal', 'Updating'); + .should('not.have.text', 'Updating'); }; diff --git a/x-pack/plugins/security_solution/cypress/tasks/es_archiver.ts b/x-pack/plugins/security_solution/cypress/tasks/es_archiver.ts index c0436603a256a..5ebaaf419ed34 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/es_archiver.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/es_archiver.ts @@ -4,14 +4,6 @@ * you may not use this file except in compliance with the Elastic License. */ -export const esArchiverLoadEmptyKibana = () => { - cy.exec( - `node ../../../scripts/es_archiver load empty_kibana --dir ../../test/security_solution_cypress/es_archives --config ../../../test/functional/config.js --es-url ${Cypress.env( - 'ELASTICSEARCH_URL' - )} --kibana-url ${Cypress.config().baseUrl}` - ); -}; - export const esArchiverLoad = (folder: string) => { cy.exec( `node ../../../scripts/es_archiver load ${folder} --dir ../../test/security_solution_cypress/es_archives --config ../../../test/functional/config.js --es-url ${Cypress.env( @@ -28,18 +20,11 @@ export const esArchiverUnload = (folder: string) => { ); }; -export const esArchiverUnloadEmptyKibana = () => { - cy.exec( - `node ../../../scripts/es_archiver unload empty_kibana --dir ../../test/security_solution_cypress/es_archives --config ../../../test/functional/config.js --es-url ${Cypress.env( - 'ELASTICSEARCH_URL' - )} --kibana-url ${Cypress.config().baseUrl}` - ); -}; - export const esArchiverResetKibana = () => { cy.exec( `node ../../../scripts/es_archiver empty-kibana-index --config ../../../test/functional/config.js --es-url ${Cypress.env( 'ELASTICSEARCH_URL' - )} --kibana-url ${Cypress.config().baseUrl}` + )} --kibana-url ${Cypress.config().baseUrl}`, + { failOnNonZeroExit: false } ); }; diff --git a/x-pack/plugins/security_solution/cypress/tasks/hosts/authentications.ts b/x-pack/plugins/security_solution/cypress/tasks/hosts/authentications.ts index cd64fe4ff1726..7db3f76bac1d1 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/hosts/authentications.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/hosts/authentications.ts @@ -9,5 +9,5 @@ import { REFRESH_BUTTON } from '../../screens/security_header'; export const waitForAuthenticationsToBeLoaded = () => { cy.get(AUTHENTICATIONS_TABLE).should('exist'); - cy.get(REFRESH_BUTTON).invoke('text').should('not.equal', 'Updating'); + cy.get(REFRESH_BUTTON).should('not.have.text', 'Updating'); }; diff --git a/x-pack/plugins/security_solution/cypress/tasks/hosts/uncommon_processes.ts b/x-pack/plugins/security_solution/cypress/tasks/hosts/uncommon_processes.ts index 598def9ed41d0..18f31119ec662 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/hosts/uncommon_processes.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/hosts/uncommon_processes.ts @@ -9,5 +9,5 @@ import { REFRESH_BUTTON } from '../../screens/security_header'; export const waitForUncommonProcessesToBeLoaded = () => { cy.get(UNCOMMON_PROCESSES_TABLE).should('exist'); - cy.get(REFRESH_BUTTON).invoke('text').should('not.equal', 'Updating'); + cy.get(REFRESH_BUTTON).should('not.have.text', 'Updating'); }; diff --git a/x-pack/plugins/security_solution/cypress/tasks/timeline.ts b/x-pack/plugins/security_solution/cypress/tasks/timeline.ts index 8eb9a989a9125..47c1fd237432c 100644 --- a/x-pack/plugins/security_solution/cypress/tasks/timeline.ts +++ b/x-pack/plugins/security_solution/cypress/tasks/timeline.ts @@ -18,7 +18,7 @@ import { CLOSE_TIMELINE_BTN, COMBO_BOX, CREATE_NEW_TIMELINE, - HEADER, + DRAGGABLE_HEADER, ID_FIELD, ID_HEADER_FIELD, ID_TOGGLE_FIELD, @@ -189,8 +189,11 @@ export const dragAndDropIdToggleFieldToTimeline = () => { }; export const removeColumn = (column: number) => { - cy.get(HEADER).eq(column).click(); - cy.get(REMOVE_COLUMN).eq(column).click({ force: true }); + cy.get(DRAGGABLE_HEADER) + .eq(column) + .within(() => { + cy.get(REMOVE_COLUMN).click({ force: true }); + }); }; export const resetFields = () => { diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx index d35a5f487ed8e..d6ea611660eda 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/index.tsx @@ -86,7 +86,7 @@ export const NotePreviews = React.memo( return { 'data-test-subj': `note-preview-${note.savedObjectId}`, username: defaultToEmptyTag(note.updatedBy), - event: 'added a comment', + event: i18n.ADDED_A_NOTE, timestamp: note.updated ? ( ) : ( @@ -95,7 +95,7 @@ export const NotePreviews = React.memo( children: (
-

{i18n.USER_ADDED_A_NOTE(note.updatedBy ?? i18n.AN_UNKNOWN_USER)}

+

{`${note.updatedBy ?? i18n.AN_UNKNOWN_USER} ${i18n.ADDED_A_NOTE}`}

{note.note ?? ''}
diff --git a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/translations.ts b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/translations.ts index d38dee8a41504..2525173970687 100644 --- a/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/translations.ts +++ b/x-pack/plugins/security_solution/public/timelines/components/open_timeline/note_previews/translations.ts @@ -13,14 +13,12 @@ export const TOGGLE_EXPAND_EVENT_DETAILS = i18n.translate( } ); -export const USER_ADDED_A_NOTE = (user: string) => - i18n.translate('xpack.securitySolution.timeline.userAddedANoteScreenReaderOnly', { - values: { user }, - defaultMessage: '{user} added a note', - }); +export const ADDED_A_NOTE = i18n.translate('xpack.securitySolution.timeline.addedANoteLabel', { + defaultMessage: 'added a note', +}); export const AN_UNKNOWN_USER = i18n.translate( - 'xpack.securitySolution.timeline.anUnknownUserScreenReaderOnly', + 'xpack.securitySolution.timeline.anUnknownUserLabel', { defaultMessage: 'an unknown user', } diff --git a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/get_index_version.ts b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/get_index_version.ts index 8553c427588d3..c2c676ef06006 100644 --- a/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/get_index_version.ts +++ b/x-pack/plugins/security_solution/server/lib/detection_engine/routes/index/get_index_version.ts @@ -26,7 +26,7 @@ export const getIndexVersion = async ( index, }); const writeIndex = Object.keys(indexAlias).find( - (key) => indexAlias[key].aliases[index].is_write_index + (key) => indexAlias[key].aliases[index]?.is_write_index ); if (writeIndex === undefined) { return 0; diff --git a/yarn.lock b/yarn.lock index 585d6a1c81ca9..81b57de1947da 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1369,10 +1369,10 @@ snap-shot-compare "2.8.3" snap-shot-store "1.2.3" -"@cypress/webpack-preprocessor@^5.4.11": - version "5.4.11" - resolved "https://registry.yarnpkg.com/@cypress/webpack-preprocessor/-/webpack-preprocessor-5.4.11.tgz#77f86e399f04969d5d8692ada96c794c52d38f87" - integrity sha512-6kj0HsaWf1s0UT4qkABuwl676sW8S8lSTai3NUcF3BWj9BqhN4JPd2DdGcHNkNmYRkjpklPeGUHqAOyqMDj5+A== +"@cypress/webpack-preprocessor@^5.5.0": + version "5.5.0" + resolved "https://registry.yarnpkg.com/@cypress/webpack-preprocessor/-/webpack-preprocessor-5.5.0.tgz#e7010b2ee7449691cc16a9d5d1956af17ea175fd" + integrity sha512-iqwPygSNZ1u6bM3r5QRVv6qYngkcgI2xCzi9Jmo4mrkcofwX08UaItJq7xlB2/dHbB2aryQYOsfe4xNKtQIm3A== dependencies: bluebird "^3.7.1" debug "^4.1.1" @@ -10908,10 +10908,10 @@ cypress-promise@^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@^6.1.0: - version "6.1.0" - resolved "https://registry.yarnpkg.com/cypress/-/cypress-6.1.0.tgz#af2596cb110aa98eaf75fef3d8ab379ca0ff2413" - integrity sha512-uQnSxRcZ6hkf9R5cr8KpRBTzN88QZwLIImbf5DWa5RIxH6o5Gpff58EcjiYhAR8/8p9SGv7O6SRygq4H+k0Qpw== +cypress@^6.2.1: + version "6.2.1" + resolved "https://registry.yarnpkg.com/cypress/-/cypress-6.2.1.tgz#27d5fbcf008c698c390fdb0c03441804176d06c4" + integrity sha512-OYkSgzA4J4Q7eMjZvNf5qWpBLR4RXrkqjL3UZ1UzGGLAskO0nFTi/RomNTG6TKvL3Zp4tw4zFY1gp5MtmkCZrA== dependencies: "@cypress/listr-verbose-renderer" "^0.4.1" "@cypress/request" "^2.88.5"