diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index 690ed1c84..5bc2c3d17 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -27,7 +27,7 @@ You should have a running instance of OpenSearch Dashboards to run these tests a ### Installation -To install the dependencies run +To install the dependencies run ``` npm install @@ -76,16 +76,16 @@ To run tests against a local cluster without security: ``` -$ yarn cypress run-without-security --spec "cypress/integration/core-opensearch-dashboards/vanilla-opensearch-dashboards/*.js" +$ yarn cypress:run-without-security --spec "cypress/integration/core-opensearch-dashboards/vanilla-opensearch-dashboards/*.js" ``` with security: ``` -$ yarn cypress run-with-security --spec "cypress/integration/core-opensearch-dashboards/opensearch-dashboards/*.js" +$ yarn cypress:run-with-security --spec "cypress/integration/core-opensearch-dashboards/opensearch-dashboards/*.js" ``` -These tests run in headless mode by default. +These tests run in headless mode by default. And you can override certain [cypress config or environment variable](cypress.json) by applying additional cli arguments, for example to override the baseUrl and openSearchUrl to test a remote OpenSearch endpoint: @@ -99,7 +99,6 @@ $ yarn cypress run --spec "cypress/integration/core-opensearch-dashboards/opense `MANAGED_SERVICE_ENDPOINT`: set to true if tests are running against managed service domains. - ## Writing tests The testing library uses [Cypress](https://www.cypress.io/) as its testing framework and follow its high level folder structure. All tests are written under the `./cypress/integration` folder. @@ -125,6 +124,7 @@ Tests for plugins that are not a part of the [OpenSearch Dashboards](https://git /plugins / ``` + ### Experimental Features When writing tests for experimental features, please follow these steps. @@ -146,6 +146,7 @@ Create a new workflow by referring to [this template](https://github.com/opensea To make the build repo enable your experimental feature when spinning up OSD service, make sure that you update [this file](https://github.com/opensearch-project/opensearch-build/blob/main/src/test_workflow/integ_test/service_opensearch_dashboards.py) You could either modify the start command or the yml file. To avoid a potentially long start command, it is preferred to modify the yml file to turn on the feature. ## General + ### Formatting `prettier` and `ESLint` is integrated and used to standardize formatting of files, where `prettier` takes care of the code formatting and `ESLint` takes care of the code style. You can check the formatting of all files (new and existing) by running @@ -153,9 +154,11 @@ To make the build repo enable your experimental feature when spinning up OSD ser ``` $ yarn lint ``` + and auto fix the formatting of all files (new and existing) by running + ``` $ yarn lint --fix ``` -`Husky` precommit hook is used to automatically run `yarn lint`, please fix the files according to lint result before commiting code changes (run `yarn lint --fix` for fixable errors, or manully fix code according to error messages). If you have any doubts on `ESLint` rules, feel free to [open an issue](issues). \ No newline at end of file +`Husky` precommit hook is used to automatically run `yarn lint`, please fix the files according to lint result before commiting code changes (run `yarn lint --fix` for fixable errors, or manully fix code according to error messages). If you have any doubts on `ESLint` rules, feel free to [open an issue](issues). diff --git a/cypress.json b/cypress.json index f048c8e2f..f79ebf340 100644 --- a/cypress.json +++ b/cypress.json @@ -19,6 +19,7 @@ "MANAGED_SERVICE_ENDPOINT": false, "VISBUILDER_ENABLED": true, "DATASOURCE_MANAGEMENT_ENABLED": false, - "ML_COMMONS_DASHBOARDS_ENABLED": true + "ML_COMMONS_DASHBOARDS_ENABLED": true, + "WAIT_FOR_LOADER_BUFFER_MS": 0 } } diff --git a/cypress/fixtures/plugins/alerting-dashboards-plugin/sample_cluster_metrics_health_monitor.json b/cypress/fixtures/plugins/alerting-dashboards-plugin/sample_cluster_metrics_health_monitor.json new file mode 100644 index 000000000..52ea935ed --- /dev/null +++ b/cypress/fixtures/plugins/alerting-dashboards-plugin/sample_cluster_metrics_health_monitor.json @@ -0,0 +1,58 @@ +{ + "name": "sample_cluster_metrics_health_monitor", + "type": "monitor", + "monitor_type": "cluster_metrics_monitor", + "enabled": true, + "schedule": { + "period": { + "unit": "MINUTES", + "interval": 1 + } + }, + "inputs": [ + { + "uri": { + "api_type": "CLUSTER_HEALTH", + "path": "_cluster/health/", + "path_params": "", + "url": "http://localhost:9200/_cluster/health/" + } + } + ], + "triggers": [], + "ui_metadata": { + "schedule": { + "timezone": null, + "frequency": "interval", + "period": { + "unit": "MINUTES", + "interval": 1 + }, + "daily": 0, + "weekly": { + "tue": false, + "wed": false, + "thur": false, + "sat": false, + "fri": false, + "mon": false, + "sun": false + }, + "monthly": { + "type": "day", + "day": 1 + }, + "cronExpression": "0 */1 * * *" + }, + "search": { + "searchType": "clusterMetrics", + "timeField": "", + "aggregations": [], + "groupBy": [], + "bucketValue": 1, + "bucketUnitOfTime": "h", + "filters": [] + }, + "monitor_type": "cluster_metrics_monitor" + } +} diff --git a/cypress/fixtures/plugins/alerting-dashboards-plugin/sample_cluster_metrics_stats_monitor.json b/cypress/fixtures/plugins/alerting-dashboards-plugin/sample_cluster_metrics_stats_monitor.json new file mode 100644 index 000000000..a258b0586 --- /dev/null +++ b/cypress/fixtures/plugins/alerting-dashboards-plugin/sample_cluster_metrics_stats_monitor.json @@ -0,0 +1,73 @@ +{ + "name": "sample_cluster_metrics_stats_monitor", + "type": "monitor", + "monitor_type": "cluster_metrics_monitor", + "enabled": true, + "schedule": { + "period": { + "unit": "MINUTES", + "interval": 1 + } + }, + "inputs": [ + { + "uri": { + "api_type": "CLUSTER_STATS", + "path": "_cluster/stats/", + "path_params": "", + "url": "http://localhost:9200/_cluster/stats/" + } + } + ], + "triggers": [ + { + "query_level_trigger": { + "id": "Y5mmA4kBIezNcMbMJnEy", + "name": "sample_cluster_metrics_stats_monitor-trigger1", + "severity": "1", + "condition": { + "script": { + "source": "ctx.results[0].indices.count >= 0", + "lang": "painless" + } + }, + "actions": [] + } + } + ], + "ui_metadata": { + "schedule": { + "timezone": null, + "frequency": "interval", + "period": { + "unit": "MINUTES", + "interval": 1 + }, + "daily": 0, + "weekly": { + "tue": false, + "wed": false, + "thur": false, + "sat": false, + "fri": false, + "mon": false, + "sun": false + }, + "monthly": { + "type": "day", + "day": 1 + }, + "cronExpression": "0 */1 * * *" + }, + "search": { + "searchType": "clusterMetrics", + "timeField": "", + "aggregations": [], + "groupBy": [], + "bucketValue": 1, + "bucketUnitOfTime": "h", + "filters": [] + }, + "monitor_type": "cluster_metrics_monitor" + } +} diff --git a/cypress/fixtures/plugins/alerting-dashboards-plugin/sample_composite_level_monitor.json b/cypress/fixtures/plugins/alerting-dashboards-plugin/sample_composite_level_monitor.json new file mode 100644 index 000000000..9b1f67bf4 --- /dev/null +++ b/cypress/fixtures/plugins/alerting-dashboards-plugin/sample_composite_level_monitor.json @@ -0,0 +1,274 @@ +{ + "sample_composite_monitor": { + "type": "workflow", + "schema_version": 0, + "name": "sampleComponentLevelMonitor", + "workflow_type": "composite", + "enabled": true, + "enabled_time": 1686908176848, + "schedule": { + "period": { + "interval": 1, + "unit": "MINUTES" + } + }, + "inputs": [ + { + "composite_input": { + "sequence": { + "delegates": [ + { + "order": 1, + "monitor_id": "qdYBw4gB2qeAWe54jQyZ" + }, + { + "order": 2, + "monitor_id": "rtYBw4gB2qeAWe54wAx5" + } + ] + } + } + } + ], + "triggers": [ + { + "chained_alert_trigger": { + "id": "pNaQw4gB2qeAWe54Fg2U", + "name": "sample_trigger", + "severity": "1", + "condition": { + "script": { + "source": "(monitor[id=qdYBw4gB2qeAWe54jQyZ]) && (monitor[id=rtYBw4gB2qeAWe54wAx5])", + "lang": "painless" + } + }, + "actions": [ + { + "id": "pdaQw4gB2qeAWe54Fg2U", + "name": "sample_channel", + "destination_id": "6dYFw4gB2qeAWe54NgyL", + "message_template": { + "source": "Monitor {{ctx.monitor.name}} just entered alert status. Please investigate the issue.\n - Trigger: {{ctx.trigger.name}}\n - Severity: {{ctx.trigger.severity}}\n - Period start: {{ctx.periodStart}}\n - Period end: {{ctx.periodEnd}}", + "lang": "mustache" + }, + "throttle_enabled": false, + "subject_template": { + "source": "Monitor {{ctx.monitor.name}} triggered an alert {{ctx.trigger.name}}", + "lang": "mustache" + } + } + ] + } + } + ], + "last_update_time": 1686908180116, + "owner": "alerting", + "monitor_type": "composite" + }, + "sample_composite_index": { + "mappings": { + "properties": { + "audit_category": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "audit_node_host_name": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + }, + "audit_node_id": { + "type": "text", + "fields": { + "keyword": { + "type": "keyword", + "ignore_above": 256 + } + } + } + } + } + }, + "sample_composite_associated_monitor_1": { + "name": "monitorOne", + "type": "monitor", + "monitor_type": "doc_level_monitor", + "enabled": false, + "schedule": { + "period": { + "unit": "MINUTES", + "interval": 1 + } + }, + "inputs": [ + { + "doc_level_input": { + "description": "", + "indices": ["sample_index_1"], + "queries": [ + { + "id": "monitor_1_query_1", + "name": "monitor_1_query_1", + "query": "NOT (audit_category:\"sample_text\")", + "tags": [] + }, + { + "id": "monitor_1_query_2", + "name": "monitor_1_query_2", + "query": "NOT (audit_node_host_name:\"sample_text\")", + "tags": [] + }, + { + "id": "monitor_1_query_3", + "name": "monitor_1_query_3", + "query": "NOT (audit_node_id:\"sample_text\")", + "tags": [] + } + ] + } + } + ], + "triggers": [ + { + "document_level_trigger": { + "id": "sample_trigger_id_1", + "name": "monitor_1_query_2", + "severity": "1", + "condition": { + "script": { + "source": "query[name=monitor_1_query_1] || query[name=monitor_1_query_2] && query[name=monitor_1_query_3]", + "lang": "painless" + } + }, + "actions": [] + } + } + ] + }, + "sample_composite_associated_monitor_2": { + "name": "monitorTwo", + "type": "monitor", + "monitor_type": "doc_level_monitor", + "enabled": false, + "schedule": { + "period": { + "unit": "MINUTES", + "interval": 1 + } + }, + "inputs": [ + { + "doc_level_input": { + "description": "", + "indices": ["sample_index_2"], + "queries": [ + { + "id": "monitor_2_query_1", + "name": "monitor_2_query_1", + "query": "NOT (audit_category:\"sample_text\")", + "tags": [] + }, + { + "id": "monitor_2_query_2", + "name": "monitor_2_query_2", + "query": "NOT (audit_node_host_name:\"sample_text\")", + "tags": [] + }, + { + "id": "monitor_2_query_3", + "name": "monitor_2_query_3", + "query": "NOT (audit_node_id:\"sample_text\")", + "tags": [] + } + ] + } + } + ], + "triggers": [ + { + "document_level_trigger": { + "id": "sample_trigger_2", + "name": "monitor_2_query_2", + "severity": "1", + "condition": { + "script": { + "source": "query[name=monitor_2_query_1] || query[name=monitor_2_query_2] && query[name=monitor_2_query_3]", + "lang": "painless" + } + }, + "actions": [] + } + } + ] + }, + "sample_composite_associated_monitor_3": { + "name": "monitorThree", + "type": "monitor", + "monitor_type": "doc_level_monitor", + "enabled": false, + "schedule": { + "period": { + "unit": "MINUTES", + "interval": 1 + } + }, + "inputs": [ + { + "doc_level_input": { + "description": "", + "indices": ["sample_index_2"], + "queries": [ + { + "id": "monitor_2_query_1", + "name": "monitor_2_query_1", + "query": "NOT (audit_category:\"sample_text\")", + "tags": [] + }, + { + "id": "monitor_2_query_2", + "name": "monitor_2_query_2", + "query": "NOT (audit_node_host_name:\"sample_text\")", + "tags": [] + }, + { + "id": "monitor_2_query_3", + "name": "monitor_2_query_3", + "query": "NOT (audit_node_id:\"sample_text\")", + "tags": [] + } + ] + } + } + ], + "triggers": [ + { + "document_level_trigger": { + "id": "sample_trigger_2", + "name": "monitor_2_query_2", + "severity": "1", + "condition": { + "script": { + "source": "query[name=monitor_2_query_1] || query[name=monitor_2_query_2] && query[name=monitor_2_query_3]", + "lang": "painless" + } + }, + "actions": [] + } + } + ] + }, + "sample_composite_associated_index_document": { + "audit_category": "FAILED_LOGIN", + "audit_node_host_name": "127.0.0.1", + "audit_node_id": "sample_node_id" + } +} diff --git a/cypress/integration/common/dashboard_sample_data_spec.js b/cypress/integration/common/dashboard_sample_data_spec.js index d6ee6f0c7..7d7afa310 100644 --- a/cypress/integration/common/dashboard_sample_data_spec.js +++ b/cypress/integration/common/dashboard_sample_data_spec.js @@ -247,9 +247,8 @@ export function dashboardSanityTests() { describe('checking discover', () => { before(() => { - cy.setAdvancedSetting({ 'discover:v2': false }); // Go to the Discover page - miscUtils.visitPage('app/discover#/'); + miscUtils.visitPage('app/data-explorer/discover#/'); }); after(() => {}); @@ -280,10 +279,7 @@ export function dashboardSanityTests() { }); it('checking index pattern switch button display', () => { - commonUI.checkElementExists( - 'button[data-test-subj="indexPattern-switch-link"]', - 1 - ); + cy.getElementByTestId('dataExplorerDSSelect').should('be.visible'); }); it('checking field filter display', () => { diff --git a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/vis_builder/dashboard.spec.js b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/vis_builder/dashboard.spec.js index 72bd3a35a..234d4138a 100644 --- a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/vis_builder/dashboard.spec.js +++ b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/vis_builder/dashboard.spec.js @@ -108,38 +108,42 @@ if (Cypress.env('VISBUILDER_ENABLED')) { cy.deleteSavedObjectByType(VB_SO_TYPE, `vb${cleanupKey}`); }); - it('Should be able to edit a visualization', () => { - // Navigate to vis builder - cy.getElementByTestId('dashboardEditMode').click(); - cy.getElementByTestId( - `embeddablePanelHeading-${toTestId(VB_METRIC_VIS_TITLE, '')}` - ) - .find('[data-test-subj="embeddablePanelToggleMenuIcon"]') - .click(); - cy.getElementByTestId('embeddablePanelAction-editPanel').click(); - cy.getElementByTestId('visualizationLoader') - .find('.mtrVis__value') - .should('contain.text', VB_INDEX_DOC_COUNT); - - // Edit visualization - const newLabel = 'Editied Label'; - cy.getElementByTestId('dropBoxField-metric-0').click(); - cy.vbEditAgg([ - { - testSubj: 'visEditorStringInput1customLabel', - type: 'input', - value: newLabel, - }, - ]); - - // Save and return - cy.getElementByTestId('visBuilderSaveAndReturnButton').click(); - - cy.getElementByTestId('visualizationLoader').should( - 'contain.text', - newLabel - ); - }); + it( + 'Should be able to edit a visualization', + { retries: { runMode: 2 } }, + () => { + // Navigate to vis builder + cy.getElementByTestId('dashboardEditMode').click(); + cy.getElementByTestId( + `embeddablePanelHeading-${toTestId(VB_METRIC_VIS_TITLE, '')}` + ) + .find('[data-test-subj="embeddablePanelToggleMenuIcon"]') + .click(); + cy.getElementByTestId('embeddablePanelAction-editPanel').click(); + cy.getElementByTestId('visualizationLoader') + .find('.mtrVis__value') + .should('contain.text', VB_INDEX_DOC_COUNT); + + // Edit visualization + const newLabel = 'Editied Label'; + cy.getElementByTestId('dropBoxField-metric-0').click(); + cy.vbEditAgg([ + { + testSubj: 'visEditorStringInput1customLabel', + type: 'input', + value: newLabel, + }, + ]); + + // Save and return + cy.getElementByTestId('visBuilderSaveAndReturnButton').click(); + + cy.getElementByTestId('visBuilderLoader').should( + 'contain.text', + newLabel + ); + } + ); after(() => { cy.deleteIndex(VB_INDEX_ID); diff --git a/cypress/integration/plugins/alerting-dashboards-plugin/cluster_metrics_monitor_spec.js b/cypress/integration/plugins/alerting-dashboards-plugin/cluster_metrics_monitor_spec.js index be3075ff4..9d6c165ec 100644 --- a/cypress/integration/plugins/alerting-dashboards-plugin/cluster_metrics_monitor_spec.js +++ b/cypress/integration/plugins/alerting-dashboards-plugin/cluster_metrics_monitor_spec.js @@ -105,10 +105,12 @@ describe('ClusterMetricsMonitor', () => { cy.contains('There are no existing monitors'); // Go to create monitor page - cy.contains('Create monitor').click(); + cy.contains('Create monitor', { timeout: 20000 }).click({ force: true }); // Select ClusterMetrics radio card - cy.get('[data-test-subj="clusterMetricsMonitorRadioCard"]').click(); + cy.get('[data-test-subj="clusterMetricsMonitorRadioCard"]').click({ + force: true, + }); // Wait for input to load and then type in the monitor name cy.get('input[name="name"]').type(SAMPLE_CLUSTER_METRICS_HEALTH_MONITOR); @@ -119,7 +121,7 @@ describe('ClusterMetricsMonitor', () => { ); // Confirm the Query parameters field is present and described as "optional" - cy.contains('Query parameters - optional'); + cy.contains('Path parameters - optional'); cy.get('[data-test-subj="clusterMetricsParamsFieldText"]'); // Press the 'Run for response' button @@ -144,7 +146,7 @@ describe('ClusterMetricsMonitor', () => { // .type('{downarrow}{enter}'); // Click the create button - cy.get('button').contains('Create').click(); + cy.get('button').contains('Create').click({ force: true }); // Confirm we can see only one row in the trigger list by checking element cy.contains('This table contains 1 row'); @@ -153,7 +155,7 @@ describe('ClusterMetricsMonitor', () => { cy.contains(SAMPLE_TRIGGER); // Go back to the Monitors list - cy.get('a').contains('Monitors').click(); + cy.get('a').contains('Monitors').click({ force: true }); // Confirm we can see the created monitor in the list cy.contains(SAMPLE_CLUSTER_METRICS_HEALTH_MONITOR); @@ -223,7 +225,7 @@ describe('ClusterMetricsMonitor', () => { }); }); - describe('displays Query parameters field appropriately', () => { + describe('displays Path parameters field appropriately', () => { beforeEach(() => { cy.deleteAllMonitors(); cy.reload(); @@ -234,10 +236,12 @@ describe('ClusterMetricsMonitor', () => { cy.contains('There are no existing monitors'); // Go to create monitor page - cy.contains('Create monitor').click(); + cy.contains('Create monitor', { timeout: 20000 }).click({ force: true }); // Select ClusterMetrics radio card - cy.get('[data-test-subj="clusterMetricsMonitorRadioCard"]').click(); + cy.get('[data-test-subj="clusterMetricsMonitorRadioCard"]').click({ + force: true, + }); // Wait for input to load and then type in the monitor name cy.get('input[name="name"]').type( @@ -249,9 +253,9 @@ describe('ClusterMetricsMonitor', () => { 'list snapshots{enter}' ); - // Confirm the Query parameters field is present and is not described as "optional" - cy.contains('Query parameters - optional').should('not.exist'); - cy.contains('Query parameters'); + // Confirm the Path parameters field is present and is not described as "optional" + cy.contains('Path parameters - optional').should('not.exist'); + cy.contains('Path parameters'); cy.get('[data-test-subj="clusterMetricsParamsFieldText"]'); }); }); diff --git a/cypress/integration/plugins/alerting-dashboards-plugin/composite_level_monitor_spec.js b/cypress/integration/plugins/alerting-dashboards-plugin/composite_level_monitor_spec.js new file mode 100644 index 000000000..f4f911758 --- /dev/null +++ b/cypress/integration/plugins/alerting-dashboards-plugin/composite_level_monitor_spec.js @@ -0,0 +1,195 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + ALERTING_API, + ALERTING_PLUGIN_NAME, +} from '../../../utils/plugins/alerting-dashboards-plugin/constants'; +import sampleCompositeJson from '../../../fixtures/plugins/alerting-dashboards-plugin/sample_composite_level_monitor.json'; +import * as _ from 'lodash'; +import { BASE_PATH } from '../../../utils/base_constants'; + +const sample_index_1 = 'sample_index_1'; +const sample_index_2 = 'sample_index_2'; +const SAMPLE_VISUAL_EDITOR_MONITOR = + 'sample_visual_editor_composite_level_monitor'; + +const clearAll = () => { + cy.deleteIndexByName(sample_index_1); + cy.deleteIndexByName(sample_index_2); + + cy.deleteAllAlerts(); + cy.deleteAllMonitors(); +}; + +describe('CompositeLevelMonitor', () => { + before(() => { + clearAll(); + + // Create indices + cy.createIndexByName( + sample_index_1, + sampleCompositeJson.sample_composite_index + ); + cy.createIndexByName( + sample_index_2, + sampleCompositeJson.sample_composite_index + ); + + // Create associated monitors + cy.createMonitor(sampleCompositeJson.sample_composite_associated_monitor_1); + cy.createMonitor(sampleCompositeJson.sample_composite_associated_monitor_2); + cy.createMonitor(sampleCompositeJson.sample_composite_associated_monitor_3); + }); + + beforeEach(() => { + // Set welcome screen tracking to false + localStorage.setItem('home:welcome:show', 'false'); + }); + + describe('can be created', () => { + beforeEach(() => { + // Visit Alerting OpenSearch Dashboards + cy.visit(`${BASE_PATH}/app/${ALERTING_PLUGIN_NAME}#/monitors`); + + // Common text to wait for to confirm page loaded, give up to 20 seconds for initial load + cy.contains('Create monitor', { timeout: 20000 }); + + // Go to create monitor page + cy.contains('Create monitor').click({ force: true }); + + // Select the Composite-Level Monitor type + cy.get('[data-test-subj="compositeLevelMonitorRadioCard"]').click({ + force: true, + }); + }); + + it('by visual editor', () => { + // Select visual editor for method of definition + cy.get('[data-test-subj="visualEditorRadioCard"]').click({ force: true }); + + // Wait for input to load and then type in the monitor name + cy.get('input[name="name"]').type(SAMPLE_VISUAL_EDITOR_MONITOR, { + force: true, + }); + + // Select associated monitors + cy.get('[id="associatedMonitorsList_0"]').type('monitorOne', { + delay: 50, + force: true, + }); + cy.get('[title="monitorOne"]').click({ force: true }); + + cy.get('[id="associatedMonitorsList_1"]').type('monitorTwo', { + delay: 50, + force: true, + }); + cy.get('[title="monitorTwo"]').click({ force: true }); + + cy.get('button').contains('Add trigger').click({ force: true }); + + // Type trigger name + cy.get('[data-test-subj="composite-trigger-name"]') + .type('{selectall}', { force: true }) + .type('{backspace}', { force: true }) + .type('Composite trigger', { force: true }); + + cy.intercept('api/alerting/workflows').as('createMonitorRequest'); + cy.intercept(`api/alerting/monitors?*`).as('getMonitorsRequest'); + cy.get('button').contains('Create').click({ force: true }); + + // Wait for monitor to be created + cy.wait('@createMonitorRequest').then(() => { + // Verify the monitor name on details page + cy.contains(SAMPLE_VISUAL_EDITOR_MONITOR); + + // Go back to the Monitors list + cy.get('a').contains('Monitors').click({ force: true }); + + cy.contains(SAMPLE_VISUAL_EDITOR_MONITOR); + }); + }); + }); + + describe('can be edited', () => { + beforeEach(() => { + const body = { + size: 200, + query: { + match_all: {}, + }, + }; + cy.request({ + method: 'GET', + url: `${Cypress.env('openSearchUrl')}${ + ALERTING_API.MONITOR_BASE + }/_search`, + failOnStatusCode: false, // In case there is no alerting config index in cluster, where the status code is 404 + body, + }).then((response) => { + if (response.status === 200) { + const monitors = response.body.hits.hits; + const createdMonitor = _.find( + monitors, + (monitor) => monitor._source.name === SAMPLE_VISUAL_EDITOR_MONITOR + ); + if (createdMonitor) { + cy.visit( + `${BASE_PATH}/app/${ALERTING_PLUGIN_NAME}#/monitors/${createdMonitor._id}?action=update-monitor&type=workflow` + ); + } else { + cy.log( + 'Failed to get created monitor ', + SAMPLE_VISUAL_EDITOR_MONITOR + ); + throw new Error( + `Failed to get created monitor ${SAMPLE_VISUAL_EDITOR_MONITOR}` + ); + } + } else { + cy.log('Failed to get all monitors.', response); + } + }); + }); + + it('by visual editor', () => { + // Verify edit page + cy.contains('Edit monitor', { timeout: 20000 }); + cy.get('input[name="name"]').type('_edited'); + + cy.get('label').contains('Visual editor').click({ force: true }); + + cy.get('button').contains('Add another monitor').click({ force: true }); + + cy.get('[id="associatedMonitorsList_2"]').type('monitorThree', { + delay: 50, + force: true, + }); + cy.get('[title="monitorThree"]').click({ force: true }); + + cy.get('button').contains('Composite trigger').click({ force: true }); + + cy.get('[data-test-subj="condition-add-options-btn_0"]').click({ + force: true, + }); + cy.get('[data-test-subj="select-expression_0_2"]').click({ force: true }); + cy.wait(1000); + cy.get('[data-test-subj="monitors-combobox-0-2"]') + .type('monitorThree', { delay: 50 }) + .type('{enter}'); + + cy.intercept('api/alerting/workflows/*').as('updateMonitorRequest'); + cy.get('button').contains('Update').click({ force: true }); + + // Wait for monitor to be created + cy.wait('@updateMonitorRequest').then(() => { + cy.wait(5000); + cy.contains(`${SAMPLE_VISUAL_EDITOR_MONITOR}_edited`); + }); + }); + }); + + after(() => clearAll()); +}); diff --git a/cypress/integration/plugins/alerting-dashboards-plugin/monitors_dashboard_spec.js b/cypress/integration/plugins/alerting-dashboards-plugin/monitors_dashboard_spec.js new file mode 100644 index 000000000..ba8898ee6 --- /dev/null +++ b/cypress/integration/plugins/alerting-dashboards-plugin/monitors_dashboard_spec.js @@ -0,0 +1,152 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + ALERTING_INDEX, + ALERTING_PLUGIN_NAME, +} from '../../../utils/plugins/alerting-dashboards-plugin/constants'; +import sampleAlertsFlyoutBucketMonitor from '../../../fixtures/plugins/alerting-dashboards-plugin/sample_alerts_flyout_bucket_level_monitor.json'; +import sampleAlertsFlyoutQueryMonitor from '../../../fixtures/plugins/alerting-dashboards-plugin/sample_alerts_flyout_query_level_monitor.json'; +import sampleClusterMetricsHealthMonitor from '../../../fixtures/plugins/alerting-dashboards-plugin/sample_cluster_metrics_health_monitor.json'; +import sampleClusterMetricsStatsMonitor from '../../../fixtures/plugins/alerting-dashboards-plugin/sample_cluster_metrics_stats_monitor.json'; +import { BASE_PATH } from '../../../utils/base_constants'; + +const queryMonitor = { + ...sampleAlertsFlyoutQueryMonitor, + id: 'monitors_dashboard_cypress_query_level', + name: 'monitors_dashboard_cypress_query_level', + enabled: false, +}; +const bucketMonitor = { + ...sampleAlertsFlyoutBucketMonitor, + id: 'monitors_dashboard_cypress_bucket_level', + name: 'monitors_dashboard_cypress_bucket_level', + enabled: false, +}; +const clusterHealthMonitor = { + ...sampleClusterMetricsHealthMonitor, + id: 'monitors_dashboard_cypress_cluster_health', + name: 'monitors_dashboard_cypress_cluster_health', + enabled: false, + triggers: [ + { + query_level_trigger: { + id: 'WJmlA4kBIezNcMbMwnFg', + name: 'sample_cluster_metrics_health_monitor-trigger1', + severity: '1', + condition: { + script: { + source: 'ctx.results[0].status != "green"', + lang: 'painless', + }, + }, + actions: [], + }, + }, + ], +}; +const clusterStatsMonitor = { + ...sampleClusterMetricsStatsMonitor, + enabled: false, + id: 'monitors_dashboard_cypress_cluster_stats', + name: 'monitors_dashboard_cypress_cluster_stats', +}; +const testMonitors = [ + { + monitor: queryMonitor, + expectedAlertsCount: 1, + triggerName: queryMonitor.triggers[0].query_level_trigger.name, + }, + { + monitor: bucketMonitor, + expectedAlertsCount: 46, + triggerName: bucketMonitor.triggers[0].bucket_level_trigger.name, + }, + { + monitor: clusterHealthMonitor, + expectedAlertsCount: 1, + triggerName: clusterHealthMonitor.triggers[0].query_level_trigger.name, + }, + { + monitor: clusterStatsMonitor, + expectedAlertsCount: 1, + triggerName: clusterStatsMonitor.triggers[0].query_level_trigger.name, + }, +]; + +describe('Monitors dashboard page', () => { + before(() => { + // Delete any existing monitors + cy.deleteAllMonitors() + .then(() => { + // Load sample data + cy.loadSampleEcommerceData(); + }) + .then(() => { + // Short wait to reduce flakiness while ecommerce data is loaded + cy.wait(5000); + + // Create the test monitors + testMonitors.forEach((entry) => + cy.createAndExecuteMonitor(entry.monitor) + ); + }); + + // Visit Alerting OpenSearch Dashboards + cy.visit(`${BASE_PATH}/app/${ALERTING_PLUGIN_NAME}#/monitors`); + }); + + beforeEach(() => { + // Refresh Alerting OpenSearch Dashboards + cy.visit(`${BASE_PATH}/app/${ALERTING_PLUGIN_NAME}#/monitors`); + + // Common text to wait for to confirm page loaded, give up to 20 seconds for initial load + cy.contains('Create monitor', { timeout: 20000 }); + }); + + it('Displays expected number of alerts', () => { + // Ensure the 'Monitor name' column is sorted in ascending order by sorting another column first + cy.contains('Last updated by').click({ force: true }); + cy.contains('Monitor name').click({ force: true }); + + testMonitors.forEach((entry) => { + cy.get('tbody > tr') + .filter(`:contains(${entry.monitor.name})`, { timeout: 20000 }) + .within(() => { + cy.get('[class="euiTableRowCell"]') + .filter(':contains(Latest alert)', { timeout: 20000 }) + .should('contain', entry.triggerName); + + cy.get('[class="euiTableRowCell"]') + .filter(':contains(State)', { timeout: 20000 }) + .should('contain', 'Disabled'); + + cy.get('[class="euiTableRowCell"]') + .filter(':contains(Active)', { timeout: 20000 }) + .should('contain', entry.expectedAlertsCount); + + cy.get('[class="euiTableRowCell"]') + .filter(':contains(Acknowledged)', { timeout: 20000 }) + .should('contain', 0); + + cy.get('[class="euiTableRowCell"]') + .filter(':contains(Errors)', { timeout: 20000 }) + .should('contain', 0); + + cy.get('[class="euiTableRowCell"]') + .filter(':contains(Ignored)', { timeout: 20000 }) + .should('contain', 0); + }); + }); + }); + + after(() => { + // Delete all monitors + cy.deleteAllMonitors(); + + // Delete sample data + cy.deleteIndexByName(ALERTING_INDEX.SAMPLE_DATA_ECOMMERCE); + }); +}); diff --git a/cypress/integration/plugins/alerting-dashboards-plugin/query_level_monitor_spec.js b/cypress/integration/plugins/alerting-dashboards-plugin/query_level_monitor_spec.js index 9ff1aac74..5a7a9d858 100644 --- a/cypress/integration/plugins/alerting-dashboards-plugin/query_level_monitor_spec.js +++ b/cypress/integration/plugins/alerting-dashboards-plugin/query_level_monitor_spec.js @@ -34,7 +34,12 @@ const addVisualQueryLevelTrigger = ( thresholdValue ) => { // Click 'Add trigger' button - cy.contains('Add trigger', { timeout: 20000 }).click({ force: true }); + if (triggerIndex === 0) + cy.contains('Add trigger', { timeout: 20000 }).click({ force: true }); + else + cy.contains('Add another trigger', { timeout: 20000 }).click({ + force: true, + }); if (isEdit) { // TODO: Passing button props in EUI accordion was added in newer versions (31.7.0+). @@ -244,6 +249,10 @@ describe('Query-Level Monitors', () => { // Click the Delete button cy.contains('Delete').click({ force: true }); + cy.wait(1000); + cy.get('[data-test-subj="confirmModalConfirmButton"]').click({ + force: true, + }); // Confirm we can see an empty monitor list cy.contains('There are no existing monitors'); diff --git a/cypress/integration/plugins/custom-import-map-dashboards/import_vector_map_tab.spec.js b/cypress/integration/plugins/custom-import-map-dashboards/import_vector_map_tab.spec.js index 415c8b970..9fb5bb5be 100644 --- a/cypress/integration/plugins/custom-import-map-dashboards/import_vector_map_tab.spec.js +++ b/cypress/integration/plugins/custom-import-map-dashboards/import_vector_map_tab.spec.js @@ -14,16 +14,14 @@ describe('Verify the presence of import custom map tab in region map plugin', () cy.deleteAllIndices(); miscUtils.addSampleData(); - cy.visit(`${BASE_PATH}/app/visualize#/`); - - // Click on "Create Visualization" tab - cy.contains('Create visualization').click({ force: true }); - - // Click on "Region Map" icon - cy.contains('Region Map').click({ force: true }); - - // Select index source - [Flights] Flight Log - cy.contains('[Flights] Flight Log').click({ force: true }); + // Load region map visualization with sample data opensearch_dashboards_sample_data_flights + cy.visit( + `${BASE_PATH}/app/visualize#/create?type=region_map&indexPattern=d3d7af60-4c81-11e8-b3d7-01146121b73d`, + { + retryOnStatusCodeFailure: true, + timeout: 60000, + } + ); }); it('checks import custom map tab is present', () => { diff --git a/cypress/integration/plugins/observability-dashboards/1_trace_analytics_dashboard.spec.js b/cypress/integration/plugins/observability-dashboards/1_trace_analytics_dashboard.spec.js index c67828db9..f3032d034 100644 --- a/cypress/integration/plugins/observability-dashboards/1_trace_analytics_dashboard.spec.js +++ b/cypress/integration/plugins/observability-dashboards/1_trace_analytics_dashboard.spec.js @@ -79,7 +79,9 @@ describe('Testing dashboard table', () => { }); it('Redirects to traces table with filter', () => { - cy.get('.euiLink').contains('13').click(); + cy.get('[data-test-subj="dashboard-table-traces-button"]') + .contains('13') + .click(); cy.wait(delayTime); cy.contains(' (13)').should('exist'); @@ -107,7 +109,9 @@ describe('Testing plots', () => { it('Renders service map', () => { // plotly scale texts are in attribute "data-unformatted" - cy.get('text.ytitle[data-unformatted="Latency (ms)"]').should('exist'); + cy.get('text.ytitle[data-unformatted="Average duration (ms)"]').should( + 'exist' + ); cy.get('text[data-unformatted="200"]').should('exist'); cy.get('.vis-network').should('exist'); diff --git a/cypress/integration/plugins/observability-dashboards/4_panels.spec.js b/cypress/integration/plugins/observability-dashboards/4_panels.spec.js index 6715e3b6a..3a256341e 100644 --- a/cypress/integration/plugins/observability-dashboards/4_panels.spec.js +++ b/cypress/integration/plugins/observability-dashboards/4_panels.spec.js @@ -8,17 +8,9 @@ import { PANEL_DELAY as delay, TEST_PANEL, - PPL_VISUALIZATIONS, - PPL_VISUALIZATIONS_NAMES, - supressResizeObserverIssue, BASE_PATH, } from '../../../utils/constants'; -const moveToEventsHome = () => { - cy.visit(`${BASE_PATH}/app/observability-logs#`); - cy.wait(delay * 3); -}; - const moveToPanelHome = () => { cy.visit(`${BASE_PATH}/app/observability-dashboards#`); cy.wait(delay * 3); @@ -35,40 +27,6 @@ const moveToTestPanel = () => { cy.wait(delay); }; -describe('Creating visualizations', () => { - beforeEach(() => { - moveToEventsHome(); - }); - - it('Create first visualization in event analytics', () => { - cy.get('[id^=autocomplete-textarea]').focus().type(PPL_VISUALIZATIONS[0], { - delay: 50, - }); - cy.get('.euiButton__text').contains('Refresh').trigger('mouseover').click(); - cy.wait(delay); - supressResizeObserverIssue(); - cy.get('button[id="main-content-vis"]') - .contains('Visualizations') - .trigger('mouseover') - .click(); - cy.wait(delay * 2); - cy.get('[data-test-subj="eventExplorer__saveManagementPopover"]') - .trigger('mouseover') - .click(); - cy.wait(1000); - cy.get('[data-test-subj="eventExplorer__querySaveName"]') - .focus() - .type(PPL_VISUALIZATIONS_NAMES[0], { - delay: 50, - }); - cy.get('[data-test-subj="eventExplorer__querySaveConfirm"]') - .trigger('mouseover') - .click(); - cy.wait(delay); - cy.get('.euiToastHeader__title').contains('successfully').should('exist'); - }); -}); - describe('Testing panels table', () => { beforeEach(() => { moveToPanelHome(); @@ -112,6 +70,7 @@ describe('Testing panels table', () => { }); it('Deletes panels', () => { + cy.get('.panel-header-count').contains('(2)'); cy.get('.euiCheckbox__input[data-test-subj="checkboxSelectAll"]') .trigger('mouseover') .click(); @@ -166,6 +125,7 @@ describe('Testing a panel', () => { }); cy.get('.euiLink').contains('This year').trigger('mouseover').click(); cy.wait(delay * 2); + moveToTestPanel(); cy.get( '.euiSuperDatePicker__prettyFormat[data-test-subj="superDatePickerShowDatesButton"]' ) diff --git a/cypress/integration/plugins/query-workbench-dashboards/ui.spec.js b/cypress/integration/plugins/query-workbench-dashboards/ui.spec.js index 0187b6d52..cb3be70b4 100644 --- a/cypress/integration/plugins/query-workbench-dashboards/ui.spec.js +++ b/cypress/integration/plugins/query-workbench-dashboards/ui.spec.js @@ -91,7 +91,6 @@ describe('Test PPL UI', () => { it('Test full screen view', () => { cy.get('.euiButton__text').contains('Full screen view').should('not.exist'); - cy.get('.euiTitle').contains('Query Workbench').should('exist'); cy.get('textarea.ace_text-input') .eq(0) @@ -104,12 +103,9 @@ describe('Test PPL UI', () => { .contains('Full screen view') .click({ force: true }); - cy.get('.euiTitle').should('not.exist'); - cy.get('button#exit-fullscreen-button').click({ force: true }); cy.wait(QUERY_WORKBENCH_DELAY); cy.get('.euiButton__text').contains('Full screen view').should('exist'); - cy.get('.euiTitle').contains('Query Workbench').should('exist'); }); }); @@ -179,15 +175,12 @@ describe('Test SQL UI', () => { it('Test full screen view', () => { cy.get('.euiButton__text').contains('Full screen view').should('not.exist'); - cy.get('.euiTitle').contains('Query Workbench').should('exist'); cy.get('.euiButton__text').contains('Run').click({ force: true }); cy.wait(QUERY_WORKBENCH_DELAY * 5); cy.get('.euiButton__text') .contains('Full screen view') .click({ force: true }); - - cy.get('.euiTitle').should('not.exist'); }); }); diff --git a/cypress/integration/plugins/reports-dashboards/04-download.spec.js b/cypress/integration/plugins/reports-dashboards/04-download.spec.js index ff2d0c60b..e94e7be66 100644 --- a/cypress/integration/plugins/reports-dashboards/04-download.spec.js +++ b/cypress/integration/plugins/reports-dashboards/04-download.spec.js @@ -38,10 +38,10 @@ describe('Cypress', () => { cy.wait(12500); cy.get('[id="landingPageOnDemandDownload"]') - .contains('PDF') + .contains('CSV') .click({ force: true }); cy.get('.euiToastHeader__title') - .contains('Successfully generated report') + .contains('Successfully downloaded report') .should('exist'); }); diff --git a/cypress/utils/dashboards/commands.js b/cypress/utils/dashboards/commands.js index 1d2188c4f..dd1f5d024 100644 --- a/cypress/utils/dashboards/commands.js +++ b/cypress/utils/dashboards/commands.js @@ -15,7 +15,7 @@ Cypress.Commands.add('waitForLoader', () => { displayName: 'wait', message: 'page load', }); - + cy.wait(Cypress.env('WAIT_FOR_LOADER_BUFFER_MS')); cy.getElementByTestId('homeIcon', opts); // Update to `homeLoader` once useExpandedHeader is enabled }); diff --git a/cypress/utils/plugins/alerting-dashboards-plugin/commands.js b/cypress/utils/plugins/alerting-dashboards-plugin/commands.js index 962566271..c0a49307a 100644 --- a/cypress/utils/plugins/alerting-dashboards-plugin/commands.js +++ b/cypress/utils/plugins/alerting-dashboards-plugin/commands.js @@ -36,7 +36,7 @@ Cypress.Commands.add('createMonitor', (monitorJSON) => { 'POST', `${Cypress.env('openSearchUrl')}${ALERTING_API.MONITOR_BASE}`, monitorJSON - ); + ).then(({ body }) => body); }); Cypress.Commands.add('createAndExecuteMonitor', (monitorJSON) => { @@ -50,10 +50,43 @@ Cypress.Commands.add('createAndExecuteMonitor', (monitorJSON) => { `${Cypress.env('openSearchUrl')}${ALERTING_API.MONITOR_BASE}/${ response.body._id }/_execute` - ); + ).then(({ body }) => body); }); }); +Cypress.Commands.add('executeMonitor', (monitorID) => { + cy.request( + 'POST', + `${Cypress.env('openSearchUrl')}${ + ALERTING_API.MONITOR_BASE + }/${monitorID}/_execute` + ).then(({ body }) => body); +}); + +Cypress.Commands.add('executeCompositeMonitor', (monitorID) => { + cy.request( + 'POST', + `${Cypress.env('openSearchUrl')}${ + ALERTING_API.WORKFLOW_BASE + }/${monitorID}/_execute` + ).then(({ body }) => body); +}); + +Cypress.Commands.add('deleteAllAlerts', () => { + cy.request({ + method: 'POST', + url: `${Cypress.env( + 'openSearchUrl' + )}/.opendistro-alerting-alert*/_delete_by_query`, + body: { + query: { + match_all: {}, + }, + }, + failOnStatusCode: false, + }).then(({ body }) => body); +}); + Cypress.Commands.add('deleteMonitorByName', (monitorName) => { const body = { query: { @@ -75,7 +108,7 @@ Cypress.Commands.add('deleteMonitorByName', (monitorName) => { `${Cypress.env('openSearchUrl')}${ALERTING_API.MONITOR_BASE}/${ response.body.hits.hits[0]._id }` - ); + ).then(({ body }) => body); }); }); @@ -83,9 +116,7 @@ Cypress.Commands.add('deleteAllMonitors', () => { const body = { size: 200, query: { - exists: { - field: 'monitor', - }, + match_all: {}, }, }; cy.request({ @@ -95,13 +126,21 @@ Cypress.Commands.add('deleteAllMonitors', () => { body, }).then((response) => { if (response.status === 200) { - for (let i = 0; i < response.body.hits.total.value; i++) { - cy.request( - 'DELETE', - `${Cypress.env('openSearchUrl')}${ALERTING_API.MONITOR_BASE}/${ - response.body.hits.hits[i]._id - }` - ); + const monitors = response.body.hits.hits.sort((monitor) => + monitor._source.type === 'workflow' ? -1 : 1 + ); + for (let i = 0; i < monitors.length; i++) { + if (monitors[i]._id) { + cy.request({ + method: 'DELETE', + url: `${Cypress.env('openSearchUrl')}${ + monitors[i]._source.type === 'workflow' + ? ALERTING_API.WORKFLOW_BASE + : ALERTING_API.MONITOR_BASE + }/${monitors[i]._id}`, + failOnStatusCode: false, + }).then(({ body }) => body); + } } } else { cy.log('Failed to get all monitors.', response); @@ -110,11 +149,17 @@ Cypress.Commands.add('deleteAllMonitors', () => { }); Cypress.Commands.add('createIndexByName', (indexName) => { - cy.request('PUT', `${Cypress.env('openSearchUrl')}/${indexName}`); + cy.request('PUT', `${Cypress.env('openSearchUrl')}/${indexName}`).then( + ({ body }) => body + ); }); Cypress.Commands.add('deleteIndexByName', (indexName) => { - cy.request('DELETE', `${Cypress.env('openSearchUrl')}/${indexName}`); + cy.request({ + method: 'DELETE', + url: `${Cypress.env('openSearchUrl')}/${indexName}`, + failOnStatusCode: false, + }).then(({ body }) => body); }); Cypress.Commands.add( @@ -124,7 +169,7 @@ Cypress.Commands.add( 'POST', `${Cypress.env('openSearchUrl')}/${indexName}/_doc/${documentId}`, documentBody - ); + ).then(({ body }) => body); } ); @@ -133,5 +178,5 @@ Cypress.Commands.add('loadSampleEcommerceData', () => { method: 'POST', headers: { 'osd-xsrf': 'opensearch-dashboards' }, url: `${BASE_PATH}/api/sample_data/ecommerce`, - }); + }).then(({ body }) => body); }); diff --git a/cypress/utils/plugins/alerting-dashboards-plugin/constants.js b/cypress/utils/plugins/alerting-dashboards-plugin/constants.js index f4a1aad82..f2df921ac 100644 --- a/cypress/utils/plugins/alerting-dashboards-plugin/constants.js +++ b/cypress/utils/plugins/alerting-dashboards-plugin/constants.js @@ -12,6 +12,7 @@ export const ALERTING_INDEX = { export const ALERTING_API = { MONITOR_BASE: `${API_ROUTE_PREFIX}/monitors`, + WORKFLOW_BASE: `${API_ROUTE_PREFIX}/workflows`, DESTINATION_BASE: `${API_ROUTE_PREFIX}/destinations`, }; diff --git a/cypress/utils/plugins/observability-dashboards/constants.js b/cypress/utils/plugins/observability-dashboards/constants.js index e11b1e43b..d73a64f21 100644 --- a/cypress/utils/plugins/observability-dashboards/constants.js +++ b/cypress/utils/plugins/observability-dashboards/constants.js @@ -50,10 +50,7 @@ export const setTimeFilter = (setEndTime = false, refresh = true) => { timeout: TIMEOUT_DELAY, }).click(); cy.get('.euiQuickSelect__applyButton').click(); - cy.get('.euiSuperDatePicker__prettyFormatLink').click(); - cy.get( - 'button.euiDatePopoverButton--start[data-test-subj="superDatePickerstartDatePopoverButton"]' - ).click(); + cy.get('[data-test-subj="superDatePickerShowDatesButton"]').click(); cy.get('.euiTab__content').contains('Absolute').click(); cy.get('input[data-test-subj="superDatePickerAbsoluteDateInput"]', { timeout: TIMEOUT_DELAY, diff --git a/package.json b/package.json index 4dae0d436..14d84624b 100644 --- a/package.json +++ b/package.json @@ -7,8 +7,8 @@ "test": "echo \"Error: no test specified\" && exit 1", "cypress:open": "cypress open", "cypress:run-without-security": "env TZ=America/Los_Angeles NO_COLOR=1 cypress run --headless --env SECURITY_ENABLED=false", - "cypress:run-with-security": "env TZ=America/Los_Angeles NO_COLOR=1 cypress run --headless --env SECURITY_ENABLED=true,openSearchUrl=https://localhost:9200", - "cypress:run-with-security-and-aggregation-view": "env TZ=America/Los_Angeles NO_COLOR=1 cypress run --headless --env SECURITY_ENABLED=true,openSearchUrl=https://localhost:9200,AGGREGATION_VIEW=true", + "cypress:run-with-security": "env TZ=America/Los_Angeles NO_COLOR=1 cypress run --headless --env SECURITY_ENABLED=true,openSearchUrl=https://localhost:9200,WAIT_FOR_LOADER_BUFFER_MS=500", + "cypress:run-with-security-and-aggregation-view": "env TZ=America/Los_Angeles NO_COLOR=1 cypress run --headless --env SECURITY_ENABLED=true,openSearchUrl=https://localhost:9200,AGGREGATION_VIEW=true,WAIT_FOR_LOADER_BUFFER_MS=500", "cypress:run-plugin-tests-without-security": "yarn cypress:run-without-security --spec 'cypress/integration/plugins/*/*.js'", "cypress:run-plugin-tests-with-security": "yarn cypress:run-with-security --spec 'cypress/integration/plugins/*/*.js'", "cypress:release-chrome": "yarn cypress:run-with-security --browser chrome --spec 'cypress/integration/core-opensearch-dashboards/opensearch-dashboards/*.js,cypress/integration/plugins/*/*'",