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 95c573fb34a6..7e55b45f724b 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 @@ -3,11 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { WORKSPACE_NAME, DATASOURCE_NAME } from '../../../../../utils/apps/constants'; +import { DATASOURCE_NAME } from '../../../../../utils/apps/constants'; import { SECONDARY_ENGINE } from '../../../../../utils/constants'; +import { getRandomizedWorkspaceName } from '../../../../../utils/apps/query_enhancements/shared'; -const randomString = Math.random().toString(36).substring(7); -const workspace = `${WORKSPACE_NAME}-${randomString}`; +const workspace = getRandomizedWorkspaceName(); describe('No Index Pattern Check Test', () => { before(() => { 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 252a5dca71f6..0309d193914f 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 @@ -3,16 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { - WORKSPACE_NAME, - DATASOURCE_NAME, - START_TIME, - END_TIME, -} from '../../../../../utils/apps/constants'; +import { DATASOURCE_NAME, START_TIME, END_TIME } from '../../../../../utils/apps/constants'; import { SECONDARY_ENGINE } from '../../../../../utils/constants'; +import { getRandomizedWorkspaceName } from '../../../../../utils/apps/query_enhancements/shared'; -const randomString = Math.random().toString(36).substring(7); -const workspace = `${WORKSPACE_NAME}-${randomString}`; +const workspace = getRandomizedWorkspaceName(); describe('dataset selector', { scrollBehavior: false }, () => { before(() => { diff --git a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/field_display_filtering.spec.js b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/field_display_filtering.spec.js index 37e31917664a..67c1b2ee1480 100644 --- a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/field_display_filtering.spec.js +++ b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/field_display_filtering.spec.js @@ -4,185 +4,24 @@ */ import { - WORKSPACE_NAME, DATASOURCE_NAME, - INDEX_NAME, - INDEX_PATTERN_NAME, - START_TIME, - END_TIME, - DATASET_CONFIGS, + INDEX_PATTERN_WITH_TIME, + INDEX_WITH_TIME_1, } from '../../../../../utils/apps/constants'; import * as dataExplorer from '../../../../../utils/apps/query_enhancements/field_display_filtering.js'; import { SECONDARY_ENGINE, BASE_PATH } from '../../../../../utils/constants'; import { NEW_SEARCH_BUTTON } from '../../../../../utils/dashboards/data_explorer/elements.js'; +import { + generateAllTestConfigurations, + getRandomizedWorkspaceName, + setDatePickerDatesAndSearchIfRelevant, +} from '../../../../../utils/apps/query_enhancements/shared'; +import { generateFieldDisplayFilteringTestConfiguration } from '../../../../../utils/apps/query_enhancements/field_display_filtering'; -const randomString = Math.random().toString(36).substring(7); -const workspace = `${WORKSPACE_NAME}-${randomString}`; - -const selectDataset = (datasetType, language) => { - switch (datasetType) { - case 'index': - dataExplorer.selectIndexDataset(DATASOURCE_NAME, INDEX_NAME, language); - break; - case 'index_pattern': - dataExplorer.selectIndexPatternDataset(INDEX_PATTERN_NAME, language); - break; - } -}; -const setDateRange = (datasetType, language) => { - if (language === 'OpenSearch SQL') { - return; - } else { - cy.setTopNavDate(START_TIME, END_TIME); - } -}; -const verifyTableFieldFilterActions = (datasetType, language, shouldExist) => { - selectDataset(datasetType, language); - setDateRange(datasetType, language); - - cy.getElementByTestId('docTable').get('tbody tr').should('have.length.above', 3); // To ensure it waits until a full table is loaded into the DOM, instead of a bug where table only has 1 hit. - - const shouldText = shouldExist ? 'exist' : 'not.exist'; - dataExplorer.getDocTableField(0, 0).within(() => { - cy.getElementByTestId('filterForValue').should(shouldText); - cy.getElementByTestId('filterOutValue').should(shouldText); - }); - - if (shouldExist) { - dataExplorer.verifyDocTableFilterAction(0, 'filterForValue', '10,000', '1', true); - dataExplorer.verifyDocTableFilterAction(0, 'filterOutValue', '10,000', '9,999', false); - } -}; -const verifyExpandedTableFilterActions = (datasetType, language, isFilterButtonsEnabled) => { - // Check if the first expanded Doc Table Field's first row's Filter For, Filter Out and Exists Filter buttons are disabled. - const verifyFirstExpandedFieldFilterForFilterOutFilterExistsButtons = () => { - const shouldText = isFilterButtonsEnabled ? 'be.enabled' : 'be.disabled'; - dataExplorer.getExpandedDocTableRow(0, 0).within(() => { - cy.getElementByTestId('addInclusiveFilterButton').should(shouldText); - cy.getElementByTestId('removeInclusiveFilterButton').should(shouldText); - cy.getElementByTestId('addExistsFilterButton').should(shouldText); - }); - }; - - /** - * Check the Filter For or Out buttons in the expandedDocumentRowNumberth field in the expanded Document filters the correct value. - * @param {string} filterButton For or Out - * @param {number} docTableRowNumber Integer starts from 0 for the first row - * @param {number} expandedDocumentRowNumber Integer starts from 0 for the first row - * @param {string} expectedQueryHitsWithoutFilter expected number of hits in string after the filter is removed Note you should add commas when necessary e.g. 9,999 - * @param {string} expectedQueryHitsAfterFilterApplied expected number of hits in string after the filter is applied. Note you should add commas when necessary e.g. 9,999 - * @example verifyDocTableFirstExpandedFieldFirstRowFilterForButtonFiltersCorrectField('for', 0, 0, '10,000', '1'); - */ - const verifyDocTableFirstExpandedFieldFirstRowFilterForOutButtonFiltersCorrectField = ( - filterButton, - docTableRowNumber, - expandedDocumentRowNumber, - expectedQueryHitsWithoutFilter, - expectedQueryHitsAfterFilterApplied - ) => { - if (filterButton !== 'for' || filterButton !== 'out') { - cy.log('Filter button must be for or or.'); - return; - } +const workspace = getRandomizedWorkspaceName(); - const filterButtonElement = - filterButton === 'for' ? 'addInclusiveFilterButton' : 'removeInclusiveFilterButton'; - const shouldText = filterButton === 'for' ? 'have.text' : 'not.have.text'; - - dataExplorer - .getExpandedDocTableRowValue(docTableRowNumber, expandedDocumentRowNumber) - .then(($expandedDocumentRowValue) => { - const filterFieldText = $expandedDocumentRowValue.text(); - dataExplorer - .getExpandedDocTableRow(docTableRowNumber, expandedDocumentRowNumber) - .within(() => { - cy.getElementByTestId(filterButtonElement).click(); - }); - // Verify pill text - cy.getElementByTestId('globalFilterLabelValue').should('have.text', filterFieldText); - cy.getElementByTestId('discoverQueryHits').should( - 'have.text', - expectedQueryHitsAfterFilterApplied - ); // checkQueryHitText must be in front of checking first line text to give time for DocTable to update. - dataExplorer - .getExpandedDocTableRowValue(docTableRowNumber, expandedDocumentRowNumber) - .should(shouldText, filterFieldText); - }); - cy.getElementByTestId('globalFilterBar').find('[aria-label="Delete"]').click(); - cy.getElementByTestId('discoverQueryHits').should('have.text', expectedQueryHitsWithoutFilter); - }; - - /** - * Check the first expanded Doc Table Field's first row's Exists Filter button filters the correct Field. - * @param {number} docTableRowNumber Integer starts from 0 for the first row - * @param {number} expandedDocumentRowNumber Integer starts from 0 for the first row - * @param {string} expectedQueryHitsWithoutFilter expected number of hits in string after the filter is removed Note you should add commas when necessary e.g. 9,999 - * @param {string} expectedQueryHitsAfterFilterApplied expected number of hits in string after the filter is applied. Note you should add commas when necessary e.g. 9,999 - */ - const verifyDocTableFirstExpandedFieldFirstRowExistsFilterButtonFiltersCorrectField = ( - docTableRowNumber, - expandedDocumentRowNumber, - expectedQueryHitsWithoutFilter, - expectedQueryHitsAfterFilterApplied - ) => { - dataExplorer - .getExpandedDocTableRowFieldName(docTableRowNumber, expandedDocumentRowNumber) - .then(($expandedDocumentRowField) => { - const filterFieldText = $expandedDocumentRowField.text(); - dataExplorer - .getExpandedDocTableRow(docTableRowNumber, expandedDocumentRowNumber) - .within(() => { - cy.getElementByTestId('addExistsFilterButton').click(); - }); - // Verify full pill text - // globalFilterLabelValue gives the inner element, but we may want all the text in the filter pill - cy.getElementByTestId('globalFilterLabelValue', { - timeout: 10000, - }) - .parent() - .should('have.text', filterFieldText + ': ' + 'exists'); - cy.getElementByTestId('discoverQueryHits').should( - 'have.text', - expectedQueryHitsAfterFilterApplied - ); - }); - cy.getElementByTestId('globalFilterBar').find('[aria-label="Delete"]').click(); - cy.getElementByTestId('discoverQueryHits').should('have.text', expectedQueryHitsWithoutFilter); - }; - - selectDataset(datasetType, language); - setDateRange(datasetType, language); - - cy.getElementByTestId('docTable').get('tbody tr').should('have.length.above', 3); // To ensure it waits until a full table is loaded into the DOM, instead of a bug where table only has 1 hit. - dataExplorer.toggleDocTableRow(0); - verifyFirstExpandedFieldFilterForFilterOutFilterExistsButtons(); - dataExplorer.verifyDocTableFirstExpandedFieldFirstRowToggleColumnButtonHasIntendedBehavior(); - - if (isFilterButtonsEnabled) { - verifyDocTableFirstExpandedFieldFirstRowFilterForOutButtonFiltersCorrectField( - 'for', - 0, - 0, - '10,000', - '1' - ); - verifyDocTableFirstExpandedFieldFirstRowFilterForOutButtonFiltersCorrectField( - 'out', - 0, - 0, - '10,000', - '9,999' - ); - verifyDocTableFirstExpandedFieldFirstRowExistsFilterButtonFiltersCorrectField( - 0, - 0, - '10,000', - '10,000' - ); - } -}; describe('filter for value spec', () => { - before(() => { + beforeEach(() => { // Load test data cy.setupTestData( SECONDARY_ENGINE.url, @@ -192,59 +31,196 @@ describe('filter for value spec', () => { // Add data source cy.addDataSource({ - name: `${DATASOURCE_NAME}`, + name: DATASOURCE_NAME, url: `${SECONDARY_ENGINE.url}`, authType: 'no_auth', }); // Create workspace - cy.deleteWorkspaceByName(`${workspace}`); + cy.deleteWorkspaceByName(workspace); cy.visit('/app/home'); - cy.createInitialWorkspaceWithDataSource(`${DATASOURCE_NAME}`, `${workspace}`); + cy.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspace); cy.wait(2000); cy.createWorkspaceIndexPatterns({ - url: `${BASE_PATH}`, - workspaceName: `${workspace}`, - indexPattern: INDEX_NAME, + workspaceName: workspace, + indexPattern: INDEX_PATTERN_WITH_TIME.replace('*', ''), timefieldName: 'timestamp', indexPatternHasTimefield: true, dataSource: DATASOURCE_NAME, isEnhancement: true, }); - }); - beforeEach(() => { cy.navigateToWorkSpaceSpecificPage({ url: BASE_PATH, - workspaceName: `${workspace}`, + workspaceName: workspace, page: 'discover', isEnhancement: true, }); cy.getElementByTestId(NEW_SEARCH_BUTTON).click(); }); - after(() => { - cy.deleteWorkspaceByName(`${workspace}`); - cy.deleteDataSourceByName(`${DATASOURCE_NAME}`); + afterEach(() => { + cy.deleteWorkspaceByName(workspace); + cy.deleteDataSourceByName(DATASOURCE_NAME); // TODO: Modify deleteIndex to handle an array of index and remove hard code - cy.deleteIndex(INDEX_PATTERN_NAME); + cy.deleteIndex(INDEX_WITH_TIME_1); }); - const testCases = [ - { name: 'table field', verifyFn: verifyTableFieldFilterActions }, - { name: 'expanded table', verifyFn: verifyExpandedTableFilterActions }, - ]; - - testCases.forEach(({ name, verifyFn }) => { - describe(`filter actions in ${name}`, () => { - Object.entries(DATASET_CONFIGS).forEach(([type, config]) => { - describe(`${type} dataset`, () => { - config.languages.forEach(({ name: language, isFilterButtonsEnabled }) => { - it(`${language}`, () => { - verifyFn(type, language, isFilterButtonsEnabled); - }); - }); + generateAllTestConfigurations(generateFieldDisplayFilteringTestConfiguration).forEach( + (config) => { + it(`filter actions in table field for ${config.testName}`, () => { + cy.setDataset(config.dataset, DATASOURCE_NAME, config.datasetType); + cy.setQueryLanguage(config.language); + setDatePickerDatesAndSearchIfRelevant(config.language); + + cy.getElementByTestId('docTable').get('tbody tr').should('have.length.above', 3); // To ensure it waits until a full table is loaded into the DOM, instead of a bug where table only has 1 hit. + + const shouldText = config.isFilterButtonsEnabled ? 'exist' : 'not.exist'; + dataExplorer.getDocTableField(0, 0).within(() => { + cy.getElementByTestId('filterForValue').should(shouldText); + cy.getElementByTestId('filterOutValue').should(shouldText); }); + + if (config.isFilterButtonsEnabled) { + dataExplorer.verifyDocTableFilterAction(0, 'filterForValue', '10,000', '1', true); + dataExplorer.verifyDocTableFilterAction(0, 'filterOutValue', '10,000', '9,999', false); + } }); - }); - }); + + it(`filter actions in expanded table for ${config.testName}`, () => { + // Check if the first expanded Doc Table Field's first row's Filter For, Filter Out and Exists Filter buttons are disabled. + const verifyFirstExpandedFieldFilterForFilterOutFilterExistsButtons = () => { + const shouldText = config.isFilterButtonsEnabled ? 'be.enabled' : 'be.disabled'; + dataExplorer.getExpandedDocTableRow(0, 0).within(() => { + cy.getElementByTestId('addInclusiveFilterButton').should(shouldText); + cy.getElementByTestId('removeInclusiveFilterButton').should(shouldText); + cy.getElementByTestId('addExistsFilterButton').should(shouldText); + }); + }; + + /** + * Check the Filter For or Out buttons in the expandedDocumentRowNumberth field in the expanded Document filters the correct value. + * @param {string} filterButton For or Out + * @param {number} docTableRowNumber Integer starts from 0 for the first row + * @param {number} expandedDocumentRowNumber Integer starts from 0 for the first row + * @param {string} expectedQueryHitsWithoutFilter expected number of hits in string after the filter is removed Note you should add commas when necessary e.g. 9,999 + * @param {string} expectedQueryHitsAfterFilterApplied expected number of hits in string after the filter is applied. Note you should add commas when necessary e.g. 9,999 + * @example verifyDocTableFirstExpandedFieldFirstRowFilterForButtonFiltersCorrectField('for', 0, 0, '10,000', '1'); + */ + const verifyDocTableFirstExpandedFieldFirstRowFilterForOutButtonFiltersCorrectField = ( + filterButton, + docTableRowNumber, + expandedDocumentRowNumber, + expectedQueryHitsWithoutFilter, + expectedQueryHitsAfterFilterApplied + ) => { + if (filterButton !== 'for' || filterButton !== 'out') { + cy.log('Filter button must be for or or.'); + return; + } + + const filterButtonElement = + filterButton === 'for' ? 'addInclusiveFilterButton' : 'removeInclusiveFilterButton'; + const shouldText = filterButton === 'for' ? 'have.text' : 'not.have.text'; + + dataExplorer + .getExpandedDocTableRowValue(docTableRowNumber, expandedDocumentRowNumber) + .then(($expandedDocumentRowValue) => { + const filterFieldText = $expandedDocumentRowValue.text(); + dataExplorer + .getExpandedDocTableRow(docTableRowNumber, expandedDocumentRowNumber) + .within(() => { + cy.getElementByTestId(filterButtonElement).click(); + }); + // Verify pill text + cy.getElementByTestId('globalFilterLabelValue').should('have.text', filterFieldText); + cy.getElementByTestId('discoverQueryHits').should( + 'have.text', + expectedQueryHitsAfterFilterApplied + ); // checkQueryHitText must be in front of checking first line text to give time for DocTable to update. + dataExplorer + .getExpandedDocTableRowValue(docTableRowNumber, expandedDocumentRowNumber) + .should(shouldText, filterFieldText); + }); + cy.getElementByTestId('globalFilterBar').find('[aria-label="Delete"]').click(); + cy.getElementByTestId('discoverQueryHits').should( + 'have.text', + expectedQueryHitsWithoutFilter + ); + }; + + /** + * Check the first expanded Doc Table Field's first row's Exists Filter button filters the correct Field. + * @param {number} docTableRowNumber Integer starts from 0 for the first row + * @param {number} expandedDocumentRowNumber Integer starts from 0 for the first row + * @param {string} expectedQueryHitsWithoutFilter expected number of hits in string after the filter is removed Note you should add commas when necessary e.g. 9,999 + * @param {string} expectedQueryHitsAfterFilterApplied expected number of hits in string after the filter is applied. Note you should add commas when necessary e.g. 9,999 + */ + const verifyDocTableFirstExpandedFieldFirstRowExistsFilterButtonFiltersCorrectField = ( + docTableRowNumber, + expandedDocumentRowNumber, + expectedQueryHitsWithoutFilter, + expectedQueryHitsAfterFilterApplied + ) => { + dataExplorer + .getExpandedDocTableRowFieldName(docTableRowNumber, expandedDocumentRowNumber) + .then(($expandedDocumentRowField) => { + const filterFieldText = $expandedDocumentRowField.text(); + dataExplorer + .getExpandedDocTableRow(docTableRowNumber, expandedDocumentRowNumber) + .within(() => { + cy.getElementByTestId('addExistsFilterButton').click(); + }); + // Verify full pill text + // globalFilterLabelValue gives the inner element, but we may want all the text in the filter pill + cy.getElementByTestId('globalFilterLabelValue', { + timeout: 10000, + }) + .parent() + .should('have.text', filterFieldText + ': ' + 'exists'); + cy.getElementByTestId('discoverQueryHits').should( + 'have.text', + expectedQueryHitsAfterFilterApplied + ); + }); + cy.getElementByTestId('globalFilterBar').find('[aria-label="Delete"]').click(); + cy.getElementByTestId('discoverQueryHits').should( + 'have.text', + expectedQueryHitsWithoutFilter + ); + }; + + cy.setDataset(config.dataset, DATASOURCE_NAME, config.datasetType); + cy.setQueryLanguage(config.language); + setDatePickerDatesAndSearchIfRelevant(config.language); + + cy.getElementByTestId('docTable').get('tbody tr').should('have.length.above', 3); // To ensure it waits until a full table is loaded into the DOM, instead of a bug where table only has 1 hit. + dataExplorer.toggleDocTableRow(0); + verifyFirstExpandedFieldFilterForFilterOutFilterExistsButtons(); + dataExplorer.verifyDocTableFirstExpandedFieldFirstRowToggleColumnButtonHasIntendedBehavior(); + + if (config.isFilterButtonsEnabled) { + verifyDocTableFirstExpandedFieldFirstRowFilterForOutButtonFiltersCorrectField( + 'for', + 0, + 0, + '10,000', + '1' + ); + verifyDocTableFirstExpandedFieldFirstRowFilterForOutButtonFiltersCorrectField( + 'out', + 0, + 0, + '10,000', + '9,999' + ); + verifyDocTableFirstExpandedFieldFirstRowExistsFilterButtonFiltersCorrectField( + 0, + 0, + '10,000', + '10,000' + ); + } + }); + } + ); }); 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 500490acdd08..06bb726e360d 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 @@ -3,16 +3,11 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { - WORKSPACE_NAME, - DATASOURCE_NAME, - START_TIME, - END_TIME, -} from '../../../../../utils/apps/constants'; +import { DATASOURCE_NAME, START_TIME, END_TIME } from '../../../../../utils/apps/constants'; import { SECONDARY_ENGINE } from '../../../../../utils/constants'; +import { getRandomizedWorkspaceName } from '../../../../../utils/apps/query_enhancements/shared'; -const randomString = Math.random().toString(36).substring(7); -const workspace = `${WORKSPACE_NAME}-${randomString}`; +const workspace = getRandomizedWorkspaceName(); describe('query enhancement queries', { scrollBehavior: false }, () => { before(() => { diff --git a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/s3_dataset.spec.js b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/s3_dataset.spec.js index 25d4bd3b1ecd..1b5f5b9677e3 100644 --- a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/s3_dataset.spec.js +++ b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/s3_dataset.spec.js @@ -8,7 +8,9 @@ import { DSM_API, S3_CLUSTER, } from '../../../../../utils/apps/query_enhancements/constants'; -import { WORKSPACE_NAME } from '../../../../../utils/apps/constants'; +import { getRandomizedWorkspaceName } from '../../../../../utils/apps/query_enhancements/shared'; + +const workspace = getRandomizedWorkspaceName(); let dataSourceId = ''; const definedS3Variables = !S3_CLUSTER.url; @@ -83,12 +85,12 @@ const definedS3Variables = !S3_CLUSTER.url; describe('Run S3 Query', () => { beforeEach(() => { // Create workspace - cy.deleteWorkspaceByName(WORKSPACE_NAME); + cy.deleteWorkspaceByName(workspace); cy.visit('/app/home'); - cy.createInitialWorkspaceWithDataSource(S3_CLUSTER.name, WORKSPACE_NAME); + cy.createInitialWorkspaceWithDataSource(S3_CLUSTER.name, workspace); }); afterEach(() => { - cy.deleteWorkspaceByName(WORKSPACE_NAME); + cy.deleteWorkspaceByName(workspace); }); it('with SQL', function () { diff --git a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_queries_flyout.spec.js b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_queries_flyout.spec.js index f9357ba4f9fe..9da0b68b5590 100644 --- a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_queries_flyout.spec.js +++ b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_queries_flyout.spec.js @@ -9,22 +9,25 @@ import { INDEX_WITH_TIME_2, SECONDARY_ENGINE, } from '../../../../../utils/constants'; - import { - workspaceName, - datasourceName, - setSearchConfigurations, + getRandomizedWorkspaceName, + getRandomizedDatasourceName, setDatePickerDatesAndSearchIfRelevant, + generateAllTestConfigurations, +} from '../../../../../utils/apps/query_enhancements/shared'; +import { + generateSavedTestConfiguration, + setSearchConfigurations, verifyDiscoverPageState, -} from '../../../../../utils/apps/query_enhancements/saved_search'; +} from '../../../../../utils/apps/query_enhancements/saved'; -import { generateAllTestConfigurations } from '../../../../../utils/apps/query_enhancements/saved_queries'; +const workspaceName = getRandomizedWorkspaceName(); +const datasourceName = getRandomizedDatasourceName(); // This spec assumes data.savedQueriesNewUI.enabled is true. - export const runSavedQueriesFlyoutUITests = () => { describe('saved queries flyout UI', () => { - before(() => { + beforeEach(() => { // Load test data cy.setupTestData( SECONDARY_ENGINE.url, @@ -57,7 +60,7 @@ export const runSavedQueriesFlyoutUITests = () => { }); }); - after(() => { + afterEach(() => { // No need to explicitly delete all saved queries as deleting the workspace will delete associated saved queries cy.deleteWorkspaceByName(workspaceName); // // TODO: Modify deleteIndex to handle an array of index and remove hard code @@ -66,8 +69,7 @@ export const runSavedQueriesFlyoutUITests = () => { cy.deleteIndex(INDEX_WITH_TIME_2); }); - const testConfigurations = generateAllTestConfigurations(); - testConfigurations.forEach((config) => { + generateAllTestConfigurations(generateSavedTestConfiguration).forEach((config) => { it(`should successfully create a saved query for ${config.testName}`, () => { cy.navigateToWorkSpaceSpecificPage({ workspaceName, @@ -83,15 +85,10 @@ export const runSavedQueriesFlyoutUITests = () => { setSearchConfigurations(config); verifyDiscoverPageState(config); cy.saveQuery(config.saveName); - }); - }); - - it('should see all saved queries', () => { - cy.getElementByTestId('saved-query-management-popover-button').click(); - - cy.getElementByTestId('saved-query-management-open-button').click(); - testConfigurations.forEach((config) => { + // verify that it has been saved + cy.getElementByTestId('saved-query-management-popover-button').click(); + cy.getElementByTestId('saved-query-management-open-button').click(); cy.getElementByTestId('euiFlyoutCloseButton') .parent() .contains(config.saveName) diff --git a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_queries_popover.spec.js b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_queries_popover.spec.js index 9e717edc0b29..6d6b5b942230 100644 --- a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_queries_popover.spec.js +++ b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_queries_popover.spec.js @@ -9,23 +9,26 @@ import { INDEX_WITH_TIME_2, SECONDARY_ENGINE, } from '../../../../../utils/constants'; - import { - workspaceName, - datasourceName, - setSearchConfigurations, + getRandomizedWorkspaceName, + getRandomizedDatasourceName, setDatePickerDatesAndSearchIfRelevant, + generateAllTestConfigurations, +} from '../../../../../utils/apps/query_enhancements/shared'; +import { + generateSavedTestConfiguration, + setSearchConfigurations, verifyDiscoverPageState, -} from '../../../../../utils/apps/query_enhancements/saved_search'; +} from '../../../../../utils/apps/query_enhancements/saved'; -import { generateAllTestConfigurations } from '../../../../../utils/apps/query_enhancements/saved_queries'; +const workspaceName = getRandomizedWorkspaceName(); +const datasourceName = getRandomizedDatasourceName(); // This spec assumes data.savedQueriesNewUI.enabled is false. // These tests will not be run until the older legacy tests are migrated https://github.com/opensearch-project/OpenSearch-Dashboards/pull/9166#discussion_r1913687440 - export const runSavedQueriesPopoverUITests = () => { describe.skip('saved queries popover UI', () => { - before(() => { + beforeEach(() => { // Load test data cy.setupTestData( SECONDARY_ENGINE.url, @@ -58,7 +61,7 @@ export const runSavedQueriesPopoverUITests = () => { }); }); - after(() => { + afterEach(() => { // No need to explicitly delete all saved queries as deleting the workspace will delete associated saved queries cy.deleteWorkspaceByName(workspaceName); // // TODO: Modify deleteIndex to handle an array of index and remove hard code @@ -67,8 +70,7 @@ export const runSavedQueriesPopoverUITests = () => { cy.deleteIndex(INDEX_WITH_TIME_2); }); - const testConfigurations = generateAllTestConfigurations(); - testConfigurations.forEach((config) => { + generateAllTestConfigurations(generateSavedTestConfiguration).forEach((config) => { it(`should successfully create a saved query for ${config.testName}`, () => { cy.navigateToWorkSpaceSpecificPage({ workspaceName, @@ -83,14 +85,10 @@ export const runSavedQueriesPopoverUITests = () => { setSearchConfigurations(config); verifyDiscoverPageState(config); - cy.saveQuery(config.saveName, ' ', false); - }); - }); - - it('should see all saved queries', () => { - cy.getElementByTestId('saved-query-management-popover-button').click(); + cy.saveQuery(config.saveName); - testConfigurations.forEach((config) => { + // verify that it has been saved + cy.getElementByTestId('saved-query-management-popover-button').click(); cy.getElementByTestId('saved-query-management-popover') .contains(config.saveName) .should('exist'); diff --git a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_search.spec.js b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_search.spec.js index 12f839bb05c6..ca0d2bd6dda6 100644 --- a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_search.spec.js +++ b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_search.spec.js @@ -11,16 +11,22 @@ import { SECONDARY_ENGINE, } from '../../../../../utils/constants'; import { - workspaceName, - datasourceName, generateAllTestConfigurations, + getRandomizedWorkspaceName, + getRandomizedDatasourceName, setDatePickerDatesAndSearchIfRelevant, +} from '../../../../../utils/apps/query_enhancements/shared'; +import { setSearchConfigurations, verifyDiscoverPageState, verifySavedSearchInAssetsPage, postRequestSaveSearch, updateSavedSearchAndSaveAndVerify, -} from '../../../../../utils/apps/query_enhancements/saved_search'; + generateSavedTestConfiguration, +} from '../../../../../utils/apps/query_enhancements/saved'; + +const workspaceName = getRandomizedWorkspaceName(); +const datasourceName = getRandomizedDatasourceName(); export const runSavedSearchTests = () => { describe('saved search', () => { @@ -65,7 +71,7 @@ export const runSavedSearchTests = () => { cy.deleteIndex(INDEX_WITH_TIME_2); }); - generateAllTestConfigurations().forEach((config) => { + generateAllTestConfigurations(generateSavedTestConfiguration).forEach((config) => { it(`should successfully create a saved search for ${config.testName}`, () => { cy.navigateToWorkSpaceSpecificPage({ workspaceName, @@ -86,7 +92,7 @@ export const runSavedSearchTests = () => { // the saved search does not appear. So adding this wait cy.wait(2000); - verifySavedSearchInAssetsPage(config); + verifySavedSearchInAssetsPage(config, workspaceName); }); // We are starting from various languages @@ -126,13 +132,13 @@ export const runSavedSearchTests = () => { it(`should successfully update a saved search for ${config.testName}`, () => { // using a POST request to create a saved search to load postRequestSaveSearch(config); - updateSavedSearchAndSaveAndVerify(config, false); + updateSavedSearchAndSaveAndVerify(config, workspaceName, datasourceName, false); }); it(`should successfully save a saved search as a new saved search for ${config.testName}`, () => { // using a POST request to create a saved search to load postRequestSaveSearch(config); - updateSavedSearchAndSaveAndVerify(config, true); + updateSavedSearchAndSaveAndVerify(config, workspaceName, datasourceName, true); }); }); }); diff --git a/cypress/utils/apps/data_explorer/commands.js b/cypress/utils/apps/data_explorer/commands.js index 56bd45f9f8f8..d8c1383d3d16 100644 --- a/cypress/utils/apps/data_explorer/commands.js +++ b/cypress/utils/apps/data_explorer/commands.js @@ -113,8 +113,7 @@ Cypress.Commands.add( } ); -// eslint-disable-next-line no-unused-vars -Cypress.Commands.add('saveQuery', (name, description = ' ', savedQueriesNewUIEnabled = true) => { +Cypress.Commands.add('saveQuery', (name, description = ' ') => { cy.whenTestIdNotFound('saved-query-management-popover', () => { cy.getElementByTestId('saved-query-management-popover-button').click(); }); @@ -123,7 +122,8 @@ Cypress.Commands.add('saveQuery', (name, description = ' ', savedQueriesNewUIEna cy.getElementByTestId('saveQueryFormTitle').type(name); cy.getElementByTestId('saveQueryFormDescription').type(description); - cy.getElementByTestId('savedQueryFormSaveButton').click(); + // putting force: true as this button is sometimes masked by a popup element + cy.getElementByTestId('savedQueryFormSaveButton').click({ force: true }); cy.getElementByTestId('euiToastHeader').contains('was saved').should('be.visible'); }); diff --git a/cypress/utils/apps/data_explorer/index.d.ts b/cypress/utils/apps/data_explorer/index.d.ts index 0386b535c3a9..12912ecbffb2 100644 --- a/cypress/utils/apps/data_explorer/index.d.ts +++ b/cypress/utils/apps/data_explorer/index.d.ts @@ -19,7 +19,7 @@ declare namespace Cypress { value: string, isEnhancement?: boolean ): Chainable; - saveQuery(name: string, description: string): Chainable; + saveQuery(name: string, description?: string): Chainable; loadSaveQuery(name: string): Chainable; clearSaveQuery(): Chainable; deleteSaveQuery(name: string): Chainable; diff --git a/cypress/utils/apps/query_enhancements/constants.js b/cypress/utils/apps/query_enhancements/constants.js index 304fb902e2cb..3d49f188ab48 100644 --- a/cypress/utils/apps/query_enhancements/constants.js +++ b/cypress/utils/apps/query_enhancements/constants.js @@ -7,32 +7,6 @@ export const DATASOURCE_NAME = 'data-logs-1'; export const WORKSPACE_NAME = 'query-ws'; export const START_TIME = 'Jan 1, 2020 @ 00:00:00.000'; export const END_TIME = 'Jan 1, 2024 @ 00:00:00.000'; -export const INDEX_NAME = 'data_logs_small_time_1'; -export const DEFAULT_TIME_INDEX_PATTERN_NAME = 'data_logs_small_time_1*'; -export const DEFAULT_NO_TIME_INDEX_PATTERN_NAME = 'data_logs_small_no_time_1*'; -export const INDEX_PATTERN_NAME = `${DATASOURCE_NAME}::${DEFAULT_TIME_INDEX_PATTERN_NAME}`; - -export const DATASET_CONFIGS = { - index_pattern: { - type: 'index_pattern', - name: INDEX_PATTERN_NAME, - languages: [ - // isFilterButtonsEnabled signifies if the filter buttons are supposed to be enabled. - { name: 'DQL', isFilterButtonsEnabled: true }, - { name: 'Lucene', isFilterButtonsEnabled: true }, - { name: 'OpenSearch SQL', isFilterButtonsEnabled: false }, - { name: 'PPL', isFilterButtonsEnabled: false }, - ], - }, - index: { - type: 'index', - name: INDEX_NAME, - languages: [ - { name: 'OpenSearch SQL', isFilterButtonsEnabled: false }, - { name: 'PPL', isFilterButtonsEnabled: false }, - ], - }, -}; export const clusterName = 'test_cluster'; export const clusterConnection = 'http://localhost:9200'; diff --git a/cypress/utils/apps/query_enhancements/field_display_filtering.js b/cypress/utils/apps/query_enhancements/field_display_filtering.js index 910250f6338f..d679f0301e6f 100644 --- a/cypress/utils/apps/query_enhancements/field_display_filtering.js +++ b/cypress/utils/apps/query_enhancements/field_display_filtering.js @@ -7,26 +7,26 @@ * Get specific row of DocTable. * @param {number} rowNumber Integer starts from 0 for the first row */ -export function getDocTableRow(rowNumber) { +export const getDocTableRow = (rowNumber) => { return cy.getElementByTestId('docTable').get('tbody tr').eq(rowNumber); -} +}; /** * Get specific field of DocTable. * @param {number} columnNumber Integer starts from 0 for the first column * @param {number} rowNumber Integer starts from 0 for the first row */ -export function getDocTableField(columnNumber, rowNumber) { +export const getDocTableField = (columnNumber, rowNumber) => { return getDocTableRow(rowNumber).findElementByTestId('docTableField').eq(columnNumber); -} +}; /** * find all Rows in Doc Table Field Expanded Document. * @param expandedDocument cypress representation of the Doc Table Field Expanded Document */ -export function findExpandedDocTableRows(expandedDocument) { +export const findExpandedDocTableRows = (expandedDocument) => { return expandedDocument.findElementByTestIdLike('tableDocViewRow-'); -} +}; /** * Get the "expandedDocumentRowNumber"th row from the expanded document from the "docTableRowNumber"th row of the DocTable. @@ -36,11 +36,11 @@ export function findExpandedDocTableRows(expandedDocument) { * // returns the first row from the expanded document from the second row of the DocTable. * getExpandedDocTableRow(1, 0); */ -export function getExpandedDocTableRow(docTableRowNumber, expandedDocumentRowNumber) { +export const getExpandedDocTableRow = (docTableRowNumber, expandedDocumentRowNumber) => { return findExpandedDocTableRows(getDocTableRow(docTableRowNumber + 1)).eq( expandedDocumentRowNumber ); -} +}; /** * Get the value for the "expandedDocumentRowNumber"th row from the expanded document from the "docTableRowNumber"th row of the DocTable. @@ -50,11 +50,11 @@ export function getExpandedDocTableRow(docTableRowNumber, expandedDocumentRowNum * // returns the value of the field from the first row from the expanded document from the second row of the DocTable. * getExpandedDocTableRowValue(1, 0); */ -export function getExpandedDocTableRowValue(docTableRowNumber, expandedDocumentRowNumber) { +export const getExpandedDocTableRowValue = (docTableRowNumber, expandedDocumentRowNumber) => { return getExpandedDocTableRow(docTableRowNumber, expandedDocumentRowNumber) .find(`[data-test-subj*="tableDocViewRow-"]`) .find('span'); -} +}; /** * Get the field name for the "expandedDocumentRowNumber"th row from the expanded document from the "docTableRowNumber"th row of the DocTable. @@ -64,22 +64,22 @@ export function getExpandedDocTableRowValue(docTableRowNumber, expandedDocumentR * // returns the name of the field from the first row from the expanded document from the second row of the DocTable. * getExpandedDocTableRowFieldName(1, 0); */ -export function getExpandedDocTableRowFieldName(docTableRowNumber, expandedDocumentRowNumber) { +export const getExpandedDocTableRowFieldName = (docTableRowNumber, expandedDocumentRowNumber) => { return getExpandedDocTableRow(docTableRowNumber, expandedDocumentRowNumber) .find('td') .eq(1) // Field name is in the second column. .find('span[class*="textTruncate"]'); -} +}; /** * Select a language in the Dataset Selector for Index * @param {string} datasetLanguage Index supports "OpenSearch SQL" and "PPL" */ -export function selectIndexDatasetLanguage(datasetLanguage) { +export const selectIndexDatasetLanguage = (datasetLanguage) => { cy.getElementByTestId('advancedSelectorLanguageSelect').select(datasetLanguage); cy.getElementByTestId('advancedSelectorTimeFieldSelect').select('timestamp'); cy.getElementByTestId('advancedSelectorConfirmButton').click(); -} +}; /** * Select an index dataset. @@ -87,7 +87,7 @@ export function selectIndexDatasetLanguage(datasetLanguage) { * @param {string} indexName Name of the index dataset to be used. * @param {string} datasetLanguage Index supports "OpenSearch SQL" and "PPL". */ -export function selectIndexDataset(indexClusterName, indexName, datasetLanguage) { +export const selectIndexDataset = (indexClusterName, indexName, datasetLanguage) => { cy.getElementByTestId('datasetSelectorButton').click(); cy.getElementByTestId('datasetSelectorAdvancedButton').click(); cy.getElementByTestId('datasetExplorerWindow').contains('Indexes').click(); @@ -95,40 +95,40 @@ export function selectIndexDataset(indexClusterName, indexName, datasetLanguage) cy.getElementByTestId('datasetExplorerWindow').contains(indexName).click(); cy.getElementByTestId('datasetSelectorNext').click(); selectIndexDatasetLanguage(datasetLanguage); -} +}; /** * Select a language in the Dataset Selector for Index Pattern * @param {string} datasetLanguage Index Pattern supports "DQL", "Lucene", "OpenSearch SQL" and "PPL" */ -export function selectIndexPatternDatasetLanguage(datasetLanguage) { +export const selectIndexPatternDatasetLanguage = (datasetLanguage) => { cy.getElementByTestId('advancedSelectorLanguageSelect').select(datasetLanguage); cy.getElementByTestId('advancedSelectorConfirmButton').click(); -} +}; /** * Select an index pattern dataset. * @param {string} indexPatternName Name of the index pattern to be used. * @param {string} datasetLanguage Index Pattern supports "DQL", "Lucene", "OpenSearch SQL" and "PPL" */ -export function selectIndexPatternDataset(indexPatternName, datasetLanguage) { +export const selectIndexPatternDataset = (indexPatternName, datasetLanguage) => { cy.getElementByTestId('datasetSelectorButton').click(); cy.getElementByTestId('datasetSelectorAdvancedButton').click(); cy.getElementByTestId('datasetExplorerWindow').contains('Index Patterns').click(); cy.getElementByTestId('datasetExplorerWindow').contains(indexPatternName).click(); cy.getElementByTestId('datasetSelectorNext').click(); selectIndexPatternDatasetLanguage(datasetLanguage); -} +}; /** * Toggle expansion of row rowNumber of Doc Table. * @param {number} rowNumber rowNumber of Doc Table starts at 0 for row 1. */ -export function toggleDocTableRow(rowNumber) { +export const toggleDocTableRow = (rowNumber) => { getDocTableRow(rowNumber).within(() => { cy.getElementByTestId('docTableExpandToggleColumn').find('button').click(); }); -} +}; /** * Check the Doc Table rowNumberth row's Filter buttons filters the correct value. @@ -139,13 +139,13 @@ export function toggleDocTableRow(rowNumber) { * @param {boolean} shouldMatch boolean to determine if same rowNumber text should match after filter is applied * @example verifyDocTableFilterAction(0, 'filterForValue', '10,000', '1', true) */ -export function verifyDocTableFilterAction( +export const verifyDocTableFilterAction = ( rowNumber, filterElement, expectedQueryHitsWithoutFilter, expectedQueryHitsAfterFilterApplied, shouldMatch -) { +) => { getDocTableField(0, rowNumber).then(($field) => { const shouldText = shouldMatch ? 'have.text' : 'not.have.text'; @@ -163,12 +163,12 @@ export function verifyDocTableFilterAction( }); cy.getElementByTestId('globalFilterBar').find('[aria-label="Delete"]').click(); cy.getElementByTestId('discoverQueryHits').should('have.text', expectedQueryHitsWithoutFilter); -} +}; /** * Check the first expanded Doc Table Field's first row's Toggle Column button has intended behavior. */ -export function verifyDocTableFirstExpandedFieldFirstRowToggleColumnButtonHasIntendedBehavior() { +export const verifyDocTableFirstExpandedFieldFirstRowToggleColumnButtonHasIntendedBehavior = () => { getExpandedDocTableRowFieldName(0, 0).then(($expandedDocumentRowFieldText) => { const fieldText = $expandedDocumentRowFieldText.text(); getExpandedDocTableRow(0, 0).within(() => { @@ -185,4 +185,31 @@ export function verifyDocTableFirstExpandedFieldFirstRowToggleColumnButtonHasInt }); cy.getElementByTestId('docTableHeader-' + fieldText).should('not.exist'); }); -} +}; + +/** + * The configurations needed for field display filtering tests + * @typedef {Object} FieldDisplayFilteringTestConfig + * @property {string} dataset - the dataset name to use + * @property {QueryEnhancementDataset} datasetType - the type of dataset + * @property {QueryEnhancementLanguage} language - the name of query language as it appears in the dashboard app + * @property {boolean} isFilterButtonsEnabled - whether filter button is enabled for this permutation + * @property {string} testName - the phrase to add to the test case's title + */ + +/** + * Returns the SavedSearchTestConfig for the provided dataset, datasetType, and language + * @param {string} dataset - the dataset name + * @param {QueryEnhancementDataset} datasetType - the type of the dataset + * @param {QueryEnhancementLanguageData} language - the relevant data for the query language to use + * @returns {FieldDisplayFilteringTestConfig} + */ +export const generateFieldDisplayFilteringTestConfiguration = (dataset, datasetType, language) => { + return { + dataset, + datasetType, + language: language.name, + isFilterButtonsEnabled: language.supports.filters, + testName: `dataset: ${datasetType} and language: ${language.name}`, + }; +}; diff --git a/cypress/utils/apps/query_enhancements/saved_search.js b/cypress/utils/apps/query_enhancements/saved.js similarity index 85% rename from cypress/utils/apps/query_enhancements/saved_search.js rename to cypress/utils/apps/query_enhancements/saved.js index 9e39786431a5..d6bce6482240 100644 --- a/cypress/utils/apps/query_enhancements/saved_search.js +++ b/cypress/utils/apps/query_enhancements/saved.js @@ -3,34 +3,15 @@ * SPDX-License-Identifier: Apache-2.0 */ +// This file is used for both saved_search and saved_queries spec + import { DatasetTypes, - DATASOURCE_NAME, - END_TIME, INDEX_PATTERN_WITH_TIME, INDEX_WITH_TIME_1, QueryLanguages, - START_TIME, - WORKSPACE_NAME, } from './constants'; - -const randomString = Math.random().toString(36); - -/** - * randomized workspace name - * @constant - * @type {string} - * @default - */ -export const workspaceName = `${WORKSPACE_NAME}-${randomString.substring(7)}`; - -/** - * randomized datasource name - * @constant - * @type {string} - * @default - */ -export const datasourceName = `${DATASOURCE_NAME}-${randomString.substring(0, 18)}`; +import { setDatePickerDatesAndSearchIfRelevant } from './shared'; /** * The fields to select for saved search. Also takes shape of the API for saved search @@ -176,8 +157,8 @@ const getSampleTableData = (datasetType, language) => { }; /** - * The configurations needed for saved search tests - * @typedef {Object} SavedSearchTestConfig + * The configurations needed for saved search/queries tests + * @typedef {Object} SavedTestConfig * @property {string} dataset - the dataset name to use * @property {QueryEnhancementDataset} datasetType - the type of dataset * @property {QueryEnhancementLanguage} language - the name of query language as it appears in the dashboard app @@ -194,13 +175,13 @@ const getSampleTableData = (datasetType, language) => { */ /** - * Returns the SavedSearchTestConfig for the provided dataset, datasetType, and language + * Returns the SavedTestConfig for the provided dataset, datasetType, and language * @param {string} dataset - the dataset name * @param {QueryEnhancementDataset} datasetType - the type of the dataset * @param {QueryEnhancementLanguageData} language - the relevant data for the query language to use - * @returns {SavedSearchTestConfig} + * @returns {SavedTestConfig} */ -const generateTestConfiguration = (dataset, datasetType, language) => { +export const generateSavedTestConfiguration = (dataset, datasetType, language) => { const baseConfig = { dataset, datasetType, @@ -219,44 +200,9 @@ const generateTestConfiguration = (dataset, datasetType, language) => { }; }; -/** - * Returns an array of test configurations for every query language + dataset permutation - * @returns {SavedSearchTestConfig[]} - */ -export const generateAllTestConfigurations = () => { - return Object.values(DatasetTypes).flatMap((dataset) => - dataset.supportedLanguages.map((language) => { - let datasetToUse; - switch (dataset.name) { - case DatasetTypes.INDEX_PATTERN.name: - datasetToUse = INDEX_PATTERN_WITH_TIME; - break; - case DatasetTypes.INDEXES.name: - datasetToUse = INDEX_WITH_TIME_1; - break; - default: - throw new Error( - `generateAllTestConfigurations encountered unsupported dataset: ${dataset.name}` - ); - } - return generateTestConfiguration(datasetToUse, dataset.name, language); - }) - ); -}; - -/** - * Sets the top nav date if it is relevant for the passed language - * @param {QueryEnhancementLanguage} language - query language - */ -export const setDatePickerDatesAndSearchIfRelevant = (language) => { - if (language !== QueryLanguages.SQL.name) { - cy.setTopNavDate(START_TIME, END_TIME); - } -}; - /** * Set the search configurations for the saved search - * @param {SavedSearchTestConfig} testConfig - the relevant config for the test case + * @param {SavedTestConfig} testConfig - the relevant config for the test case */ export const setSearchConfigurations = ({ filters, @@ -307,7 +253,7 @@ export const setSearchConfigurations = ({ /** * Verify that the discover page is in the correct state after setSearchConfigurations have been run - * @param {SavedSearchTestConfig} testConfig - the relevant config for the test case + * @param {SavedTestConfig} testConfig - the relevant config for the test case */ export const verifyDiscoverPageState = ({ dataset, @@ -358,19 +304,23 @@ export const verifyDiscoverPageState = ({ /** * After a saved search have been saved, verify the data in the assets page - * @param {SavedSearchTestConfig} testConfig - the relevant config for the test case + * @param {SavedTestConfig} testConfig - the relevant config for the test case + * @param {string} workspaceName - name of workspace */ -export const verifySavedSearchInAssetsPage = ({ - apiLanguage, - dataset, - saveName, - queryString, - datasetType, - histogram, - selectFields, - sort, - filters, -}) => { +export const verifySavedSearchInAssetsPage = ( + { + apiLanguage, + dataset, + saveName, + queryString, + datasetType, + histogram, + selectFields, + sort, + filters, + }, + workspaceName +) => { cy.navigateToWorkSpaceSpecificPage({ workspaceName: workspaceName, page: 'objects', @@ -416,7 +366,7 @@ export const verifySavedSearchInAssetsPage = ({ /** * Returns the API body that is needed when creating a saved search directly through an API call - * @param {SavedSearchTestConfig} config - language + dataset permutation configuration + * @param {SavedTestConfig} config - language + dataset permutation configuration * @param {string} workspaceId - workspace ID * @param {string} datasourceId - datasource ID * @param {string} indexPatternId - index pattern ID @@ -469,7 +419,7 @@ const getSavedObjectPostBody = (config, workspaceId, datasourceId, indexPatternI /** * send a POST request to API to create a saved search object - * @param {SavedSearchTestConfig} config - the relevant config for the test case + * @param {SavedTestConfig} config - the relevant config for the test case */ export const postRequestSaveSearch = (config) => { cy.get('@WORKSPACE_ID').then((workspaceId) => { @@ -493,10 +443,17 @@ export const postRequestSaveSearch = (config) => { /** * Loads a saved search and updates it and verify that it is correct - * @param {SavedSearchTestConfig} config - the relevant config for the test case + * @param {SavedTestConfig} config - the relevant config for the test case + * @param {string} workspaceName - the name of the workspace + * @param {string} datasourceName - the name of the datasource * @param {boolean} saveAsNew - flag to determine whether to overwrite the saved search (false) or save as a new saved search (true) */ -export const updateSavedSearchAndSaveAndVerify = (config, saveAsNew) => { +export const updateSavedSearchAndSaveAndVerify = ( + config, + workspaceName, + datasourceName, + saveAsNew +) => { cy.navigateToWorkSpaceSpecificPage({ workspaceName: workspaceName, page: 'discover', @@ -512,7 +469,7 @@ export const updateSavedSearchAndSaveAndVerify = (config, saveAsNew) => { // If current language is PPL, update to OpenSearch SQL, else update to PPL const newLanguage = config.language === QueryLanguages.PPL.name ? QueryLanguages.SQL : QueryLanguages.PPL; - const newConfig = generateTestConfiguration(newDataset, newDatasetType, newLanguage); + const newConfig = generateSavedTestConfiguration(newDataset, newDatasetType, newLanguage); cy.setDataset(newConfig.dataset, datasourceName, newConfig.datasetType); cy.setQueryLanguage(newConfig.language); diff --git a/cypress/utils/apps/query_enhancements/saved_queries.js b/cypress/utils/apps/query_enhancements/saved_queries.js deleted file mode 100644 index 38e95211474f..000000000000 --- a/cypress/utils/apps/query_enhancements/saved_queries.js +++ /dev/null @@ -1,207 +0,0 @@ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { - DatasetTypes, - DATASOURCE_NAME, - INDEX_PATTERN_WITH_TIME, - INDEX_WITH_TIME_1, - QueryLanguages, - WORKSPACE_NAME, -} from './constants'; - -const randomString = Math.random().toString(36); - -/** - * randomized workspace name - * @constant - * @type {string} - * @default - */ -export const workspaceName = `${WORKSPACE_NAME}-${randomString.substring(7)}`; - -/** - * randomized datasource name - * @constant - * @type {string} - * @default - */ -export const datasourceName = `${DATASOURCE_NAME}-${randomString.substring(0, 18)}`; - -/** - * Returns the query string to use for a given dataset+language - * @param {string} dataset - the dataset name to use - * @param {QueryEnhancementLanguage} language - the name of query language - * @returns {string} - */ -const getQueryString = (dataset, language) => { - switch (language) { - case QueryLanguages.DQL.name: - return 'bytes_transferred > 9950'; - case QueryLanguages.Lucene.name: - return 'bytes_transferred: {9950 TO *}'; - case QueryLanguages.SQL.name: - return `SELECT * FROM ${dataset} WHERE bytes_transferred > 9950`; - case QueryLanguages.PPL.name: - return `source = ${dataset} | where bytes_transferred > 9950`; - default: - throw new Error(`getQueryString encountered unsupported language: ${language}`); - } -}; - -/** - * Returns the expected hit count, if relevant, for the provided datasetType + language - * @param {QueryEnhancementDataset} datasetType - the type of the dataset - * @param {QueryEnhancementLanguage} language - the query language name - * @returns {number|undefined} - */ -const getExpectedHitCount = (datasetType, language) => { - switch (datasetType) { - case DatasetTypes.INDEX_PATTERN.name: - switch (language) { - case QueryLanguages.DQL.name: - return 28; - case QueryLanguages.Lucene.name: - return 28; - case QueryLanguages.SQL.name: - return undefined; - case QueryLanguages.PPL.name: - // TODO: Update this to 101 once Histogram is supported on 2.17 - return undefined; - default: - throw new Error( - `getExpectedHitCount encountered unsupported language for ${datasetType}: ${language}` - ); - } - case DatasetTypes.INDEXES.name: - switch (language) { - case QueryLanguages.SQL.name: - return undefined; - case QueryLanguages.PPL.name: - // TODO: Update this to 50 once Histogram is supported on 2.17 - return undefined; - default: - throw new Error( - `getExpectedHitCount encountered unsupported language for ${datasetType}: ${language}` - ); - } - default: - throw new Error(`getExpectedHitCount encountered unsupported datasetType: ${datasetType}`); - } -}; - -/** - * returns an array of data present in the results table to check against. This is used to ensure that sorting is working as expected - * @param {QueryEnhancementDataset} datasetType - the type of the dataset - * @param {QueryEnhancementLanguage} language - the query language name - * @returns {[[number,string]]|*[]} An array of table data. For each element, 0th index is the index of the table cell, and 1st index is the value in that table cell - */ -const getSampleTableData = (datasetType, language) => { - switch (datasetType) { - case DatasetTypes.INDEX_PATTERN.name: - switch (language) { - case QueryLanguages.DQL.name: - return [ - [1, '9,998'], - [2, 'Phyllis Dach'], - ]; - case QueryLanguages.Lucene.name: - return [ - [1, '9,998'], - [2, 'Phyllis Dach'], - ]; - case QueryLanguages.SQL.name: - return []; - case QueryLanguages.PPL.name: - return []; - default: - throw new Error( - `getSampleTableData encountered unsupported language for ${datasetType}: ${language}` - ); - } - case DatasetTypes.INDEXES.name: - switch (language) { - case QueryLanguages.SQL.name: - return []; - case QueryLanguages.PPL.name: - return []; - default: - throw new Error( - `getSampleTableData encountered unsupported language for ${datasetType}: ${language}` - ); - } - default: - throw new Error(`getSampleTableData encountered unsupported datasetType: ${datasetType}`); - } -}; - -/** - * The configurations needed for saved queries tests - * @typedef {Object} SavedSearchTestConfig - * @property {string} dataset - the dataset name to use - * @property {QueryEnhancementDataset} datasetType - the type of dataset - * @property {QueryEnhancementLanguage} language - the name of query language as it appears in the dashboard app - * @property {string} apiLanguage - the name of query language as recognized by OpenSearch API - * @property {string} saveName - the name to use when saving the saved query - * @property {string} testName - the phrase to add to the test case's title - * @property {boolean} filters - whether the language supports filtering - * @property {boolean} histogram - whether the language supports histogram - * @property {boolean} selectFields - whether the language supports selecting fields to view data - * @property {boolean} sort - whether the language supports sorting by fields - * @property {string} queryString - the query to use for saved query associated with the language - * @property {number|undefined} hitCount - the hitCount of the applied query config, if relevant - * @property {[[number,string]]|*[]} sampleTableData - an array of some table data to test against to ensure that sorting is working as expected - */ - -/** - * Returns the SavedSearchTestConfig for the provided dataset, datasetType, and language - * @param {string} dataset - the dataset name - * @param {QueryEnhancementDataset} datasetType - the type of the dataset - * @param {QueryEnhancementLanguageData} language - the relevant data for the query language to use - * @returns {SavedSearchTestConfig} - */ -const generateTestConfiguration = (dataset, datasetType, language) => { - const baseConfig = { - dataset, - datasetType, - language: language.name, - apiLanguage: language.apiName, - saveName: `${language.name}-${datasetType}`, - testName: `${language.name}-${datasetType}`, - ...language.supports, - }; - - return { - ...baseConfig, - queryString: getQueryString(dataset, language.name), - hitCount: getExpectedHitCount(datasetType, language.name), - sampleTableData: getSampleTableData(datasetType, language.name), - }; -}; - -/** - * Returns an array of test configurations for every query language + dataset permutation - * @returns {SavedSearchTestConfig[]} - */ -export const generateAllTestConfigurations = () => { - return Object.values(DatasetTypes).flatMap((dataset) => - dataset.supportedLanguages.map((language) => { - let datasetToUse; - switch (dataset.name) { - case DatasetTypes.INDEX_PATTERN.name: - datasetToUse = INDEX_PATTERN_WITH_TIME; - break; - case DatasetTypes.INDEXES.name: - datasetToUse = INDEX_WITH_TIME_1; - break; - default: - throw new Error( - `generateAllTestConfigurations encountered unsupported dataset: ${dataset.name}` - ); - } - return generateTestConfiguration(datasetToUse, dataset.name, language); - }) - ); -}; diff --git a/cypress/utils/apps/query_enhancements/shared.js b/cypress/utils/apps/query_enhancements/shared.js new file mode 100644 index 000000000000..9fe5a24512f4 --- /dev/null +++ b/cypress/utils/apps/query_enhancements/shared.js @@ -0,0 +1,80 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + DatasetTypes, + DATASOURCE_NAME, + END_TIME, + INDEX_PATTERN_WITH_TIME, + INDEX_WITH_TIME_1, + QueryLanguages, + START_TIME, + WORKSPACE_NAME, +} from './constants'; + +/** + * Returns a randomized string + * @returns {string} + */ +const getRandomString = () => Math.random().toString(36); + +/** + * Returns a randomized workspace name + * @returns {string} + */ +export const getRandomizedWorkspaceName = () => + `${WORKSPACE_NAME}-${getRandomString().substring(7)}`; + +/** + * Returns a randomized datasource name + * @returns {string} + */ +export const getRandomizedDatasourceName = () => + `${DATASOURCE_NAME}-${getRandomString().substring(0, 18)}`; + +/** + * Callback for generateAllTestConfigurations + * @callback GenerateTestConfigurationCallback + * @param {string} dataset - the dataset name + * @param {QueryEnhancementDataset} datasetType - the type of the dataset + * @param {QueryEnhancementLanguageData} language - the relevant data for the query language to use + * @returns {object} + */ + +/** + * Returns an array of test configurations for every query language + dataset permutation + * @param {GenerateTestConfigurationCallback} generateTestConfigurationCallback - cb function that generates a test case for the particular permutation + * @returns {object[]} + */ +export const generateAllTestConfigurations = (generateTestConfigurationCallback) => { + return Object.values(DatasetTypes).flatMap((dataset) => + dataset.supportedLanguages.map((language) => { + let datasetToUse; + switch (dataset.name) { + case DatasetTypes.INDEX_PATTERN.name: + datasetToUse = INDEX_PATTERN_WITH_TIME; + break; + case DatasetTypes.INDEXES.name: + datasetToUse = INDEX_WITH_TIME_1; + break; + default: + throw new Error( + `generateAllTestConfigurations encountered unsupported dataset: ${dataset.name}` + ); + } + return generateTestConfigurationCallback(datasetToUse, dataset.name, language); + }) + ); +}; + +/** + * Sets the top nav date if it is relevant for the passed language + * @param {QueryEnhancementLanguage} language - query language + */ +export const setDatePickerDatesAndSearchIfRelevant = (language) => { + if (language !== QueryLanguages.SQL.name) { + cy.setTopNavDate(START_TIME, END_TIME); + } +};