From 06bcf20b9522a43c058778aa71b93d447b711ee4 Mon Sep 17 00:00:00 2001 From: Justin Kim Date: Thu, 19 Dec 2024 12:13:18 -0800 Subject: [PATCH] refactor some query-enhancement utility functions, add some missing typings (#9074) * refactor some query-enhancement utility functions, add some missing typings Signed-off-by: Justin Kim * Changeset file for PR #9074 created/updated --------- Signed-off-by: Justin Kim Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- changelogs/fragments/9074.yml | 2 + .../apps/query_enhancements/a_check.spec.js | 2 +- .../dataset_selector.spec.js | 18 ++-- .../apps/query_enhancements/queries.spec.js | 10 +- cypress/utils/apps/commands.js | 19 +--- cypress/utils/apps/index.d.ts | 9 +- .../utils/apps/query_enhancements/commands.js | 4 +- .../utils/apps/query_enhancements/index.d.ts | 18 ++++ cypress/utils/dashboards/commands.js | 95 +++++++++++++++---- cypress/utils/dashboards/index.d.ts | 31 ++++++ 10 files changed, 151 insertions(+), 57 deletions(-) create mode 100644 changelogs/fragments/9074.yml create mode 100644 cypress/utils/apps/query_enhancements/index.d.ts create mode 100644 cypress/utils/dashboards/index.d.ts diff --git a/changelogs/fragments/9074.yml b/changelogs/fragments/9074.yml new file mode 100644 index 000000000000..bbec367b6af8 --- /dev/null +++ b/changelogs/fragments/9074.yml @@ -0,0 +1,2 @@ +test: +- Query-enhancements testing utility updates and additions ([#9074](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/9074)) \ No newline at end of file diff --git a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/a_check.spec.js b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/a_check.spec.js index bbc86cfd1f25..c2eca9265aa9 100644 --- a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/a_check.spec.js +++ b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/a_check.spec.js @@ -47,7 +47,7 @@ describe('No Index Pattern Check Test', () => { describe('empty state', () => { it('no index pattern', function () { // Go to the Discover page - cy.waitForLoaderNewHeader(); + cy.waitForLoader(true); cy.getElementByTestId('discoverNoIndexPatterns'); }); }); diff --git a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/dataset_selector.spec.js b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/dataset_selector.spec.js index b985bd0ecae3..38ff03888a2d 100644 --- a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/dataset_selector.spec.js +++ b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/dataset_selector.spec.js @@ -19,7 +19,7 @@ describe.skip('dataset selector', { scrollBehavior: false }, () => { `app/data-explorer/discover#/?_g=(filters:!(),time:(from:'2015-09-19T13:31:44.000Z',to:'2015-09-24T01:31:44.000Z'))` ); - cy.waitForLoaderNewHeader(); + cy.waitForLoader(true); cy.getElementByTestId('discoverNoIndexPatterns'); }); }); @@ -52,7 +52,7 @@ describe.skip('dataset selector', { scrollBehavior: false }, () => { // Go to the Discover page miscUtils.visitPage(`app/data-explorer/discover#/`); - cy.waitForLoaderNewHeader(); + cy.waitForLoader(true); }); it('with SQL as default language', function () { @@ -70,11 +70,11 @@ describe.skip('dataset selector', { scrollBehavior: false }, () => { cy.getElementByTestId(`advancedSelectorTimeFieldSelect`).select('timestamp'); cy.getElementByTestId('advancedSelectorConfirmButton').click(); - cy.waitForLoaderNewHeader(); + cy.waitForLoader(true); // SQL should already be selected cy.getElementByTestId('queryEditorLanguageSelector').should('contain', 'OpenSearch SQL'); - cy.waitForLoaderNewHeader(); + cy.waitForLoader(true); // SQL query should be executed and sending back result cy.get(`[data-test-subj="queryResultCompleteMsg"]`).should('be.visible'); @@ -85,7 +85,7 @@ describe.skip('dataset selector', { scrollBehavior: false }, () => { const toTime = 'Sep 21, 2019 @ 00:00:00.000'; cy.setTopNavDate(fromTime, toTime); - cy.waitForLoaderNewHeader(); + cy.waitForLoader(true); cy.get(`[data-test-subj="queryResultCompleteMsg"]`).should('be.visible'); }); @@ -105,7 +105,7 @@ describe.skip('dataset selector', { scrollBehavior: false }, () => { cy.getElementByTestId(`advancedSelectorTimeFieldSelect`).select('timestamp'); cy.getElementByTestId('advancedSelectorConfirmButton').click(); - cy.waitForLoaderNewHeader(); + cy.waitForLoader(true); // PPL should already be selected cy.getElementByTestId('queryEditorLanguageSelector').should('contain', 'PPL'); @@ -114,7 +114,7 @@ describe.skip('dataset selector', { scrollBehavior: false }, () => { const toTime = 'Sep 21, 2019 @ 00:00:00.000'; cy.setTopNavDate(fromTime, toTime); - cy.waitForLoaderNewHeader(); + cy.waitForLoader(true); // Query should finish running with timestamp and finish time in the footer cy.getElementByTestId('queryResultCompleteMsg').should('be.visible'); @@ -123,7 +123,7 @@ describe.skip('dataset selector', { scrollBehavior: false }, () => { // Switch language to SQL cy.setQueryLanguage('OpenSearch SQL'); - cy.waitForLoaderNewHeader(); + cy.waitForLoader(true); cy.getElementByTestId('queryResultCompleteMsg').should('be.visible'); cy.getElementByTestId('queryEditorFooterTimestamp').should('contain', 'timestamp'); }); @@ -148,7 +148,7 @@ describe.skip('dataset selector', { scrollBehavior: false }, () => { cy.get(`[title="logstash-*"]`).click(); cy.getElementByTestId('datasetSelectorNext').click(); - cy.waitForLoaderNewHeader(); + cy.waitForLoader(true); cy.waitForSearch(); cy.getElementByTestId(`queryResultCompleteMsg`).should('be.visible'); }); diff --git a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/queries.spec.js b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/queries.spec.js index 7ae18bb3bc7e..d08aa98cb364 100644 --- a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/queries.spec.js +++ b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/queries.spec.js @@ -32,7 +32,7 @@ describe.skip('query enhancement queries', { scrollBehavior: false }, () => { cy.get(`[class~="datasetSelector__button"]`).click(); cy.get(`[data-test-subj="datasetOption-timestamp-*"]`).click(); - cy.waitForLoaderNewHeader(); + cy.waitForLoader(true); cy.waitForSearch(); }); @@ -40,7 +40,7 @@ describe.skip('query enhancement queries', { scrollBehavior: false }, () => { it('with DQL', function () { const query = `_id:1`; cy.setSingleLineQueryEditor(query); - cy.waitForLoaderNewHeader(); + cy.waitForLoader(true); cy.waitForSearch(); cy.verifyHitCount(1); @@ -54,7 +54,7 @@ describe.skip('query enhancement queries', { scrollBehavior: false }, () => { const query = `_id:1`; cy.setSingleLineQueryEditor(query); - cy.waitForLoaderNewHeader(); + cy.waitForLoader(true); cy.waitForSearch(); cy.verifyHitCount(1); @@ -67,7 +67,7 @@ describe.skip('query enhancement queries', { scrollBehavior: false }, () => { cy.setQueryLanguage('OpenSearch SQL'); // default SQL query should be set - cy.waitForLoaderNewHeader(); + cy.waitForLoader(true); cy.getElementByTestId(`osdQueryEditor__multiLine`).contains( `SELECT * FROM timestamp-* LIMIT 10` ); @@ -87,7 +87,7 @@ describe.skip('query enhancement queries', { scrollBehavior: false }, () => { cy.setQueryLanguage('PPL'); // default PPL query should be set - cy.waitForLoaderNewHeader(); + cy.waitForLoader(true); cy.getElementByTestId(`osdQueryEditor__multiLine`).contains(`source = timestamp-*`); cy.waitForSearch(); cy.getElementByTestId(`queryResultCompleteMsg`).should('be.visible'); diff --git a/cypress/utils/apps/commands.js b/cypress/utils/apps/commands.js index ef97337437be..732913779d6f 100644 --- a/cypress/utils/apps/commands.js +++ b/cypress/utils/apps/commands.js @@ -6,7 +6,7 @@ import './data_explorer/commands'; import './query_enhancements/commands'; -Cypress.Commands.add('waitForLoader', () => { +Cypress.Commands.add('waitForLoader', (isEnhancement = false) => { const opts = { log: false }; Cypress.log({ @@ -14,20 +14,11 @@ 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 -}); - -Cypress.Commands.add('waitForLoaderNewHeader', () => { - const opts = { log: false }; - Cypress.log({ - name: 'waitForPageLoad', - displayName: 'wait', - message: 'page load', - }); - cy.wait(Cypress.env('WAIT_FOR_LOADER_BUFFER_MS')); - cy.getElementByTestId('recentItemsSectionButton', opts); + // Use recentItemsSectionButton for query enhancement, otherwise use homeIcon + cy.getElementByTestId(isEnhancement ? 'recentItemsSectionButton' : 'homeIcon', opts).should( + 'be.visible' + ); }); Cypress.Commands.add('setTopNavQuery', (value, submit = true) => { diff --git a/cypress/utils/apps/index.d.ts b/cypress/utils/apps/index.d.ts index 34195a6145d8..56ec83e71f08 100644 --- a/cypress/utils/apps/index.d.ts +++ b/cypress/utils/apps/index.d.ts @@ -10,14 +10,7 @@ declare namespace Cypress { * @example * cy.waitForLoader() */ - waitForLoader(): Chainable; - - /** - * Wait for Dashboards page to load with new header - * @example - * cy.waitForLoaderNewHeader() - */ - waitForLoaderNewHeader(): Chainable; + waitForLoader(isEnhancement?: boolean): Chainable; /** * Set the top nav query value diff --git a/cypress/utils/apps/query_enhancements/commands.js b/cypress/utils/apps/query_enhancements/commands.js index c1cedadd5b42..654f3f8fc5e5 100644 --- a/cypress/utils/apps/query_enhancements/commands.js +++ b/cypress/utils/apps/query_enhancements/commands.js @@ -68,8 +68,8 @@ Cypress.Commands.add('addDataSource', (options) => { cy.get('[name="password"]').type(credentials.password); } - // Submit form - cy.getElementByTestId('createDataSourceButton').click(); + // Submit form. Adding 'force' as sometimes a popover hides the button + cy.getElementByTestId('createDataSourceButton').click({ force: true }); // Wait for successful creation cy.wait('@createDataSourceRequest').then((interception) => { diff --git a/cypress/utils/apps/query_enhancements/index.d.ts b/cypress/utils/apps/query_enhancements/index.d.ts new file mode 100644 index 000000000000..05caf8d7b2a1 --- /dev/null +++ b/cypress/utils/apps/query_enhancements/index.d.ts @@ -0,0 +1,18 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +declare namespace Cypress { + interface Chainable { + setSingleLineQueryEditor(value: string, submit?: boolean): Chainable; + setQueryLanguage(value: 'DQL' | 'Lucene' | 'OpenSearch SQL' | 'PPL'): Chainable; + addDataSource(opts: { + name: string; + url: string; + auth_type?: string; + credentials?: { username: string; password: string }; + }): Chainable; + deleteDataSourceByName(dataSourceName: string): Chainable; + } +} diff --git a/cypress/utils/dashboards/commands.js b/cypress/utils/dashboards/commands.js index 879385c32670..72b2fbf3b01b 100644 --- a/cypress/utils/dashboards/commands.js +++ b/cypress/utils/dashboards/commands.js @@ -59,20 +59,30 @@ Cypress.Commands.add( Cypress.Commands.add( //navigate to workspace specific pages 'navigateToWorkSpaceSpecificPage', - (url, workspaceName, page) => { + (opts) => { + const { url, workspaceName, page, isEnhancement = false } = opts; + // Navigating to the WorkSpace Home Page cy.navigateToWorkSpaceHomePage(url, workspaceName); // Opening the side panel - cy.getElementByTestId('toggleNavButton').then((ele) => { - if (ele.length > 0) { - ele.first().click(); - } - }); + cy.getElementByTestId('toggleNavButton') + .should('be.visible') + .then((ele) => { + if (ele.length > 0) { + ele.first().click(); + } + }); - cy.getElementByTestId(`collapsibleNavAppLink-${page}`).click(); + cy.getElementByTestId(`collapsibleNavAppLink-${page}`).should('be.visible').click(); - cy.waitForLoader(); + // wait until page loads and close side panel + cy.waitForLoader(isEnhancement); + + // close the nav menu + if (isEnhancement) { + cy.getElementByTestId('collapsibleNavShrinkButton').should('be.visible').click(); + } } ); @@ -80,27 +90,76 @@ Cypress.Commands.add( // creates an index pattern within the workspace // Don't use * in the indexPattern it adds it by default at the end of name 'createWorkspaceIndexPatterns', - (url, workspaceName, indexPattern, dataSource, timefieldName = '') => { + (opts) => { + const { + url, + workspaceName, + indexPattern, + timefieldName, + indexPatternHasTimefield = true, + dataSource, + isEnhancement = false, + } = opts; + // Navigate to Workspace Specific IndexPattern Page - cy.navigateToWorkSpaceSpecificPage(url, workspaceName, 'indexPatterns'); + cy.navigateToWorkSpaceSpecificPage({ + url, + workspaceName, + page: 'indexPatterns', + isEnhancement, + }); + cy.getElementByTestId('createIndexPatternButton').click(); - cy.getElementByTestId('createIndexPatternButton').click({ force: true }); + if (dataSource) { + cy.get('[type="data-source"]').contains(dataSource).click(); + } - cy.get('[type="data-source"]').contains(dataSource).click(); cy.getElementByTestId('createIndexPatternStepDataSourceNextStepButton').click(); - cy.wait(1000); // Intentional Wait - - cy.getElementByTestId('createIndexPatternNameInput').clear().type(indexPattern); + cy.getElementByTestId('createIndexPatternNameInput') + .should('be.visible') + .clear() + .type(indexPattern); cy.getElementByTestId('createIndexPatternGoToStep2Button').click(); - if (timefieldName !== '') { + // wait for the select input if it exists + if (indexPatternHasTimefield || timefieldName) { + cy.getElementByTestId('createIndexPatternTimeFieldSelect').should('be.visible'); + } + + if (indexPatternHasTimefield && !!timefieldName) { cy.getElementByTestId('createIndexPatternTimeFieldSelect').select(timefieldName); - } else { + } else if (indexPatternHasTimefield && !timefieldName) { cy.getElementByTestId('createIndexPatternTimeFieldSelect').select( "I don't want to use the time filter" ); } - cy.getElementByTestId('createIndexPatternButton').click(); + + cy.getElementByTestId('createIndexPatternButton').should('be.visible').click(); + cy.getElementByTestId('headerApplicationTitle').contains(indexPattern); + } +); + +Cypress.Commands.add( + // deletes an index pattern within the workspace + // Don't use * in the indexPattern it adds it by default at the end of name + 'deleteWorkspaceIndexPatterns', + (opts) => { + const { url, workspaceName, indexPattern, isEnhancement = false } = opts; + + // Navigate to Workspace Specific IndexPattern Page + cy.navigateToWorkSpaceSpecificPage({ + url, + workspaceName, + page: 'indexPatterns', + isEnhancement, + }); + + cy.contains('a', indexPattern).click(); + cy.getElementByTestId('deleteIndexPatternButton').should('be.visible').click(); + cy.getElementByTestId('confirmModalConfirmButton').should('be.visible').click(); + + // wait until delete is done + cy.getElementByTestId('headerApplicationTitle').should('be.visible'); } ); diff --git a/cypress/utils/dashboards/index.d.ts b/cypress/utils/dashboards/index.d.ts new file mode 100644 index 000000000000..78a534c3bc99 --- /dev/null +++ b/cypress/utils/dashboards/index.d.ts @@ -0,0 +1,31 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +declare namespace Cypress { + interface Chainable { + navigateToWorkSpaceHomePage(url: string, workspaceName: string): Chainable; + navigateToWorkSpaceSpecificPage(opts: { + url: string; + workspaceName: string; + page: string; + isEnhancement?: boolean; + }): Chainable; + createWorkspaceIndexPatterns(opts: { + url: string; + workspaceName: string; + indexPattern: string; + timefieldName?: string; + indexPatternHasTimefield?: boolean; + dataSource?: string; + isEnhancement?: boolean; + }): Chainable; + deleteWorkspaceIndexPatterns(opts: { + url: string; + workspaceName: string; + indexPattern: string; + isEnhancement?: boolean; + }): Chainable; + } +}