diff --git a/cypress.config.ts b/cypress.config.ts index 0e08a3bc06da..cc4b3fbfb602 100644 --- a/cypress.config.ts +++ b/cypress.config.ts @@ -39,6 +39,7 @@ module.exports = defineConfig({ ML_COMMONS_DASHBOARDS_ENABLED: true, WAIT_FOR_LOADER_BUFFER_MS: 0, DISABLE_LOCAL_CLUSTER: false, + CYPRESS_RUNTIME_ENV: 'osd', }, e2e: { baseUrl: 'http://localhost:5601', 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 13539137ef2f..1ebedef10312 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,49 +3,54 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { SECONDARY_ENGINE, INDEX_WITH_TIME_1 } from '../../../../../utils/constants'; -import { - getRandomizedWorkspaceName, - getRandomizedDatasourceName, -} from '../../../../../utils/apps/query_enhancements/shared'; +import { DATASOURCE_NAME, PATHS, INDEX_WITH_TIME_1 } from '../../../../../utils/constants'; +import { getRandomizedWorkspaceName } from '../../../../../utils/apps/query_enhancements/shared'; +import { prepareTestSuite } from '../../../../../utils/helpers'; const workspaceName = getRandomizedWorkspaceName(); -const dataSourceName = getRandomizedDatasourceName(); -describe('No Index Pattern Check Test', () => { - before(() => { - // Load test data - cy.setupTestData( - SECONDARY_ENGINE.url, - ['cypress/fixtures/query_enhancements/data_logs_1/data_logs_small_time_1.mapping.json'], - ['cypress/fixtures/query_enhancements/data_logs_1/data_logs_small_time_1.data.ndjson'] - ); +const noIndexPatternTestSuite = () => { + describe('No Index Pattern Check Test', () => { + beforeEach(() => { + // Load test data + cy.osd.setupTestData( + PATHS.SECONDARY_ENGINE, + [`cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.mapping.json`], + [`cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.data.ndjson`] + ); - // Add data source - cy.addDataSource({ - name: dataSourceName, - url: SECONDARY_ENGINE.url, - authType: 'no_auth', + // Add data source + cy.osd.addDataSource({ + name: DATASOURCE_NAME, + url: PATHS.SECONDARY_ENGINE, + authType: 'no_auth', + }); + // Create workspace + cy.deleteAllWorkspaces(); + cy.visit('/app/home'); + cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspaceName); + cy.wait(2000); }); - // Create workspace - cy.deleteWorkspaceByName(workspaceName); - cy.visit('/app/home'); - cy.osd.createInitialWorkspaceWithDataSource(dataSourceName, workspaceName); - cy.wait(2000); - }); - after(() => { - cy.deleteWorkspaceByName(workspaceName); - // TODO: Modify deleteIndex to handle an array of index and remove hard code - cy.deleteDataSourceByName(dataSourceName); - cy.deleteIndex(INDEX_WITH_TIME_1); - }); + afterEach(() => { + cy.deleteWorkspaceByName(workspaceName); + cy.osd.deleteDataSourceByName(DATASOURCE_NAME); + cy.osd.deleteIndex(INDEX_WITH_TIME_1); + }); - describe('empty state', () => { - it('no index pattern', function () { - // Go to the Discover page - cy.waitForLoader(true); - cy.getElementByTestId('discoverNoIndexPatterns'); + describe('empty state', () => { + it('no index pattern', function () { + // Go to the Discover page + cy.navigateToWorkSpaceSpecificPage({ + workspaceName: workspaceName, + page: 'discover', + isEnhancement: true, + }); + cy.waitForLoader(true); + cy.getElementByTestId('discoverNoIndexPatterns').should('be.visible'); + }); }); }); -}); +}; + +prepareTestSuite('a_check', noIndexPatternTestSuite); 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 5bacbdb9ab1b..4f2a608d662c 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 @@ -4,16 +4,16 @@ */ import { + DATASOURCE_NAME, INDEX_PATTERN_WITH_TIME, INDEX_WITH_TIME_1, INDEX_WITH_TIME_2, - SECONDARY_ENGINE, + PATHS, } from '../../../../../utils/constants'; import { generateAllTestConfigurations, getRandomizedWorkspaceName, - getRandomizedDatasourceName, setDatePickerDatesAndSearchIfRelevant, getDefaultQuery, } from '../../../../../utils/apps/query_enhancements/shared'; @@ -25,16 +25,16 @@ import { verifyBaseState, setUpBaseState, } from '../../../../../utils/apps/query_enhancements/dataset_selector'; +import { prepareTestSuite } from '../../../../../utils/helpers'; const workspaceName = getRandomizedWorkspaceName(); -const dataSourceName = getRandomizedDatasourceName(); export const runDatasetSelectorTests = () => { describe('dataset selector', { scrollBehavior: false }, () => { beforeEach(() => { // Load test data - cy.setupTestData( - SECONDARY_ENGINE.url, + cy.osd.setupTestData( + PATHS.SECONDARY_ENGINE, [ `cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.mapping.json`, `cypress/fixtures/query_enhancements/data_logs_2/${INDEX_WITH_TIME_2}.mapping.json`, @@ -45,31 +45,30 @@ export const runDatasetSelectorTests = () => { ] ); // Add data source - cy.addDataSource({ - name: dataSourceName, - url: SECONDARY_ENGINE.url, + cy.osd.addDataSource({ + name: DATASOURCE_NAME, + url: PATHS.SECONDARY_ENGINE, authType: 'no_auth', }); // Create workspace - cy.deleteWorkspaceByName(workspaceName); + cy.deleteAllWorkspaces(); cy.visit('/app/home'); - cy.osd.createInitialWorkspaceWithDataSource(dataSourceName, workspaceName); + cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspaceName); cy.createWorkspaceIndexPatterns({ workspaceName: workspaceName, indexPattern: INDEX_PATTERN_WITH_TIME.replace('*', ''), timefieldName: 'timestamp', - dataSource: dataSourceName, + dataSource: DATASOURCE_NAME, isEnhancement: true, }); }); afterEach(() => { cy.deleteWorkspaceByName(workspaceName); - // TODO: Modify deleteIndex to handle an array of index and remove hard code - cy.deleteDataSourceByName(dataSourceName); - cy.deleteIndex(INDEX_WITH_TIME_1); - cy.deleteIndex(INDEX_WITH_TIME_2); + cy.osd.deleteDataSourceByName(DATASOURCE_NAME); + cy.osd.deleteIndex(INDEX_WITH_TIME_1); + cy.osd.deleteIndex(INDEX_WITH_TIME_2); }); generateAllTestConfigurations(generateDatasetSelectorTestConfiguration).forEach((config) => { @@ -81,9 +80,9 @@ export const runDatasetSelectorTests = () => { }); if (config.datasetType === 'INDEX_PATTERN') { - cy.setIndexPatternFromAdvancedSelector(config.dataset, dataSourceName, config.language); + cy.setIndexPatternFromAdvancedSelector(config.dataset, DATASOURCE_NAME, config.language); } else { - cy.setIndexAsDataset(config.dataset, dataSourceName, config.language); + cy.setIndexAsDataset(config.dataset, DATASOURCE_NAME, config.language); } setDatePickerDatesAndSearchIfRelevant(config.language); @@ -106,7 +105,7 @@ export const runDatasetSelectorTests = () => { }); // Setup the base state - setUpBaseState(INDEX_PATTERN_WITH_TIME, dataSourceName); + setUpBaseState(INDEX_PATTERN_WITH_TIME, DATASOURCE_NAME); // Verify if the base state is setup properly verifyBaseState(INDEX_PATTERN_WITH_TIME); @@ -115,14 +114,14 @@ export const runDatasetSelectorTests = () => { if (config.datasetType === 'INDEX_PATTERN') { cy.setIndexPatternFromAdvancedSelector( config.dataset, - dataSourceName, + DATASOURCE_NAME, config.language, 'cancel' ); } else { cy.setIndexAsDataset( config.dataset, - dataSourceName, + DATASOURCE_NAME, config.language, 'timestamp', 'cancel' @@ -136,4 +135,4 @@ export const runDatasetSelectorTests = () => { }); }; -runDatasetSelectorTests(); +prepareTestSuite('Dataset Selector', runDatasetSelectorTests); 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 c8144300ad07..9ef98de3b8e2 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 @@ -3,221 +3,231 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { INDEX_PATTERN_WITH_TIME, INDEX_WITH_TIME_1 } from '../../../../../utils/apps/constants'; +import { + DATASOURCE_NAME, + INDEX_PATTERN_WITH_TIME, + INDEX_WITH_TIME_1, +} from '../../../../../utils/apps/constants'; import * as docTable from '../../../../../utils/apps/query_enhancements/doc_table.js'; import { generateFieldDisplayFilteringTestConfiguration } from '../../../../../utils/apps/query_enhancements/field_display_filtering.js'; -import { SECONDARY_ENGINE, BASE_PATH } from '../../../../../utils/constants'; +import { PATHS, BASE_PATH } from '../../../../../utils/constants'; import { NEW_SEARCH_BUTTON } from '../../../../../utils/dashboards/data_explorer/elements.js'; import { generateAllTestConfigurations, getRandomizedWorkspaceName, - getRandomizedDatasourceName, setDatePickerDatesAndSearchIfRelevant, } from '../../../../../utils/apps/query_enhancements/shared'; +import { prepareTestSuite } from '../../../../../utils/helpers'; + +const workspace = getRandomizedWorkspaceName(); + +const fieldDisplayFilteringTestSuite = () => { + describe('filter for value spec', () => { + beforeEach(() => { + // Load test data + cy.osd.setupTestData( + PATHS.SECONDARY_ENGINE, + ['cypress/fixtures/query_enhancements/data_logs_1/data_logs_small_time_1.mapping.json'], + ['cypress/fixtures/query_enhancements/data_logs_1/data_logs_small_time_1.data.ndjson'] + ); + + // Add data source + cy.osd.addDataSource({ + name: DATASOURCE_NAME, + url: `${PATHS.SECONDARY_ENGINE}`, + authType: 'no_auth', + }); + // Create workspace + cy.deleteAllWorkspaces(); + cy.visit('/app/home'); + cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspace); + cy.wait(2000); + cy.createWorkspaceIndexPatterns({ + workspaceName: workspace, + indexPattern: INDEX_PATTERN_WITH_TIME.replace('*', ''), + timefieldName: 'timestamp', + indexPatternHasTimefield: true, + dataSource: DATASOURCE_NAME, + isEnhancement: true, + }); -const workspaceName = getRandomizedWorkspaceName(); -const datasourceName = getRandomizedDatasourceName(); - -describe('filter for value spec', () => { - beforeEach(() => { - // Load test data - cy.setupTestData( - SECONDARY_ENGINE.url, - ['cypress/fixtures/query_enhancements/data_logs_1/data_logs_small_time_1.mapping.json'], - ['cypress/fixtures/query_enhancements/data_logs_1/data_logs_small_time_1.data.ndjson'] - ); - - // Add data source - cy.addDataSource({ - name: datasourceName, - url: SECONDARY_ENGINE.url, - authType: 'no_auth', - }); - // Create workspace - cy.deleteWorkspaceByName(workspaceName); - cy.visit('/app/home'); - cy.osd.createInitialWorkspaceWithDataSource(datasourceName, workspaceName); - cy.createWorkspaceIndexPatterns({ - workspaceName: workspaceName, - indexPattern: INDEX_PATTERN_WITH_TIME.replace('*', ''), - timefieldName: 'timestamp', - indexPatternHasTimefield: true, - dataSource: datasourceName, - isEnhancement: true, + cy.navigateToWorkSpaceSpecificPage({ + url: BASE_PATH, + workspaceName: workspace, + page: 'discover', + isEnhancement: true, + }); + cy.getElementByTestId(NEW_SEARCH_BUTTON).click(); }); - cy.navigateToWorkSpaceSpecificPage({ - url: BASE_PATH, - workspaceName: workspaceName, - page: 'discover', - isEnhancement: true, + afterEach(() => { + cy.deleteWorkspaceByName(workspace); + cy.osd.deleteDataSourceByName(DATASOURCE_NAME); + cy.osd.deleteIndex(INDEX_WITH_TIME_1); }); - cy.getElementByTestId(NEW_SEARCH_BUTTON).click(); - }); - afterEach(() => { - cy.deleteWorkspaceByName(workspaceName); - cy.deleteDataSourceByName(datasourceName); - // TODO: Modify deleteIndex to handle an array of index and remove hard code - cy.deleteIndex(INDEX_WITH_TIME_1); - }); + 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); - generateAllTestConfigurations(generateFieldDisplayFilteringTestConfiguration).forEach( - (config) => { - it(`filter actions in table field for ${config.testName}`, () => { - cy.setDataset(config.dataset, datasourceName, 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. - 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'; + docTable.getDocTableField(0, 0).within(() => { + cy.getElementByTestId('filterForValue').should(shouldText); + cy.getElementByTestId('filterOutValue').should(shouldText); + }); - const shouldText = config.isFilterButtonsEnabled ? 'exist' : 'not.exist'; - docTable.getDocTableField(0, 0).within(() => { - cy.getElementByTestId('filterForValue').should(shouldText); - cy.getElementByTestId('filterOutValue').should(shouldText); + if (config.isFilterButtonsEnabled) { + docTable.verifyDocTableFilterAction(0, 'filterForValue', '10,000', '1', true); + docTable.verifyDocTableFilterAction(0, 'filterOutValue', '10,000', '9,999', false); + } }); - if (config.isFilterButtonsEnabled) { - docTable.verifyDocTableFilterAction(0, 'filterForValue', '10,000', '1', true); - docTable.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'; - docTable.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; + 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'; + docTable.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'; + + docTable + .getExpandedDocTableRowValue(docTableRowNumber, expandedDocumentRowNumber) + .then(($expandedDocumentRowValue) => { + const filterFieldText = $expandedDocumentRowValue.text(); + docTable + .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. + docTable + .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 + ) => { + docTable + .getExpandedDocTableRowFieldName(docTableRowNumber, expandedDocumentRowNumber) + .then(($expandedDocumentRowField) => { + const filterFieldText = $expandedDocumentRowField.text(); + docTable + .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. + docTable.toggleDocTableRow(0); + verifyFirstExpandedFieldFilterForFilterOutFilterExistsButtons(); + docTable.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' + ); } + }); + } + ); + }); +}; - const filterButtonElement = - filterButton === 'for' ? 'addInclusiveFilterButton' : 'removeInclusiveFilterButton'; - const shouldText = filterButton === 'for' ? 'have.text' : 'not.have.text'; - - docTable - .getExpandedDocTableRowValue(docTableRowNumber, expandedDocumentRowNumber) - .then(($expandedDocumentRowValue) => { - const filterFieldText = $expandedDocumentRowValue.text(); - docTable - .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. - docTable - .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 - ) => { - docTable - .getExpandedDocTableRowFieldName(docTableRowNumber, expandedDocumentRowNumber) - .then(($expandedDocumentRowField) => { - const filterFieldText = $expandedDocumentRowField.text(); - docTable - .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, datasourceName, 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. - docTable.toggleDocTableRow(0); - verifyFirstExpandedFieldFilterForFilterOutFilterExistsButtons(); - docTable.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' - ); - } - }); - } - ); -}); +prepareTestSuite('Field Display Filtering', fieldDisplayFilteringTestSuite); diff --git a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/inspect.spec.js b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/inspect.spec.js index 38d4352db1cf..fad125a830f5 100644 --- a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/inspect.spec.js +++ b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/inspect.spec.js @@ -4,17 +4,17 @@ */ import { + DATASOURCE_NAME, INDEX_PATTERN_WITH_TIME, INDEX_WITH_TIME_1, QueryLanguages, } from '../../../../../utils/apps/constants.js'; import * as docTable from '../../../../../utils/apps/query_enhancements/doc_table.js'; -import { SECONDARY_ENGINE, BASE_PATH } from '../../../../../utils/constants.js'; +import { PATHS, BASE_PATH } from '../../../../../utils/constants.js'; import { NEW_SEARCH_BUTTON } from '../../../../../utils/dashboards/data_explorer/elements.js'; import { generateAllTestConfigurations, getRandomizedWorkspaceName, - getRandomizedDatasourceName, setDatePickerDatesAndSearchIfRelevant, } from '../../../../../utils/apps/query_enhancements/shared.js'; import { @@ -25,117 +25,122 @@ import { visualizationTitlesWithNoInspectOptions, visualizationTitlesWithInspectOptions, } from '../../../../../utils/apps/query_enhancements/inspect.js'; +import { prepareTestSuite } from '../../../../../utils/helpers'; const workspaceName = getRandomizedWorkspaceName(); -const datasourceName = getRandomizedDatasourceName(); const NUMBER_OF_VISUALIZATIONS_IN_FLIGHTS_DASHBOARD = 17; -describe('inspect spec', () => { - beforeEach(() => { - // Load test data - cy.setupTestData( - SECONDARY_ENGINE.url, - ['cypress/fixtures/query_enhancements/data_logs_1/data_logs_small_time_1.mapping.json'], - ['cypress/fixtures/query_enhancements/data_logs_1/data_logs_small_time_1.data.ndjson'] - ); - - // Add data source - cy.addDataSource({ - name: datasourceName, - url: SECONDARY_ENGINE.url, - authType: 'no_auth', - }); - // Create workspace - cy.deleteWorkspaceByName(workspaceName); - cy.visit('/app/home'); - cy.osd.createInitialWorkspaceWithDataSource(datasourceName, workspaceName); - cy.createWorkspaceIndexPatterns({ - workspaceName: workspaceName, - indexPattern: INDEX_PATTERN_WITH_TIME.replace('*', ''), - timefieldName: 'timestamp', - indexPatternHasTimefield: true, - dataSource: datasourceName, - isEnhancement: true, - }); +const inspectTestSuite = () => { + describe('inspect spec', () => { + beforeEach(() => { + // Load test data + cy.osd.setupTestData( + PATHS.SECONDARY_ENGINE, + [`cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.mapping.json`], + [`cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.data.ndjson`] + ); + + // Add data source + cy.osd.addDataSource({ + name: DATASOURCE_NAME, + url: PATHS.SECONDARY_ENGINE, + authType: 'no_auth', + }); + // Create workspace + cy.deleteAllWorkspaces(); + cy.visit('/app/home'); + cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspaceName); + cy.createWorkspaceIndexPatterns({ + workspaceName: workspaceName, + indexPattern: INDEX_PATTERN_WITH_TIME.replace('*', ''), + timefieldName: 'timestamp', + indexPatternHasTimefield: true, + dataSource: DATASOURCE_NAME, + isEnhancement: true, + }); - cy.navigateToWorkSpaceSpecificPage({ - url: BASE_PATH, - workspaceName: workspaceName, - page: 'discover', - isEnhancement: true, + cy.navigateToWorkSpaceSpecificPage({ + url: BASE_PATH, + workspaceName: workspaceName, + page: 'discover', + isEnhancement: true, + }); + cy.getElementByTestId(NEW_SEARCH_BUTTON).click(); }); - cy.getElementByTestId(NEW_SEARCH_BUTTON).click(); - }); - afterEach(() => { - cy.deleteWorkspaceByName(workspaceName); - cy.deleteDataSourceByName(datasourceName); - // TODO: Modify deleteIndex to handle an array of index and remove hard code - cy.deleteIndex(INDEX_WITH_TIME_1); - }); + afterEach(() => { + cy.deleteWorkspaceByName(workspaceName); + cy.osd.deleteDataSourceByName(DATASOURCE_NAME); + cy.osd.deleteIndex(INDEX_WITH_TIME_1); + }); - generateAllTestConfigurations(generateInspectTestConfiguration).forEach((config) => { - it(`should inspect and validate the first row data for ${config.testName}`, () => { - cy.setDataset(config.dataset, datasourceName, config.datasetType); - cy.setQueryLanguage(config.language); - setDatePickerDatesAndSearchIfRelevant(config.language); - - cy.intercept('POST', '**/search/*').as('docTablePostRequest'); - - 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. - docTable.toggleDocTableRow(0); - - cy.wait('@docTablePostRequest').then((interceptedDocTableResponse) => { - const flattenedFieldsWithValues = getFlattenedFieldsWithValue( - interceptedDocTableResponse, - config.language - ); - - for (const [key, value] of Object.entries(flattenedFieldsWithValues)) { - // For SQL and PPL, this number is not accurate. https://github.com/opensearch-project/OpenSearch-Dashboards/issues/9305 - if ( - key === 'event_sequence_number' && - (config.language === QueryLanguages.SQL.name || - config.language === QueryLanguages.PPL.name) - ) { - cy.log(`Skipped for ${key}`); - continue; + generateAllTestConfigurations(generateInspectTestConfiguration).forEach((config) => { + it(`should inspect and validate the first row data for ${config.testName}`, () => { + cy.setDataset(config.dataset, DATASOURCE_NAME, config.datasetType); + cy.setQueryLanguage(config.language); + setDatePickerDatesAndSearchIfRelevant(config.language); + + cy.intercept('POST', '**/search/*').as('docTablePostRequest'); + + 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. + docTable.toggleDocTableRow(0); + + cy.wait('@docTablePostRequest').then((interceptedDocTableResponse) => { + const flattenedFieldsWithValues = getFlattenedFieldsWithValue( + interceptedDocTableResponse, + config.language + ); + + for (const [key, value] of Object.entries(flattenedFieldsWithValues)) { + // For SQL and PPL, this number is not accurate. https://github.com/opensearch-project/OpenSearch-Dashboards/issues/9305 + if ( + key === 'event_sequence_number' && + (config.language === QueryLanguages.SQL.name || + config.language === QueryLanguages.PPL.name) + ) { + cy.log(`Skipped for ${key}`); + continue; + } + docTable + .getExpandedDocTableRowFieldValue(key) + .should('have.text', value === null ? ' - ' : value); } - docTable.getExpandedDocTableRowFieldValue(key).should('have.text', value); - } + }); }); }); - }); - it('should test visualizations inspect', () => { - cy.navigateToWorkSpaceSpecificPage({ - url: BASE_PATH, - workspaceName: workspaceName, - page: 'import_sample_data', - isEnhancement: true, - }); + it('should test visualizations inspect', () => { + cy.navigateToWorkSpaceSpecificPage({ + url: BASE_PATH, + workspaceName: workspaceName, + page: 'import_sample_data', + isEnhancement: true, + }); - cy.getElementByTestId('addSampleDataSetflights').click(); - cy.getElementByTestId('sampleDataSetInstallToast').should('exist'); + cy.getElementByTestId('addSampleDataSetflights').click(); + cy.getElementByTestId('sampleDataSetInstallToast').should('exist'); - cy.navigateToWorkSpaceSpecificPage({ - url: BASE_PATH, - workspaceName: workspaceName, - page: 'dashboards', - isEnhancement: true, - }); + cy.navigateToWorkSpaceSpecificPage({ + url: BASE_PATH, + workspaceName: workspaceName, + page: 'dashboards', + isEnhancement: true, + }); - cy.getElementByTestIdLike( - 'dashboardListingTitleLink-[Flights]-Global-Flight-Dashboard' - ).click(); + cy.getElementByTestIdLike( + 'dashboardListingTitleLink-[Flights]-Global-Flight-Dashboard' + ).click(); - cy.getElementByTestId('visualizationLoader').should( - 'have.length', - NUMBER_OF_VISUALIZATIONS_IN_FLIGHTS_DASHBOARD - ); + cy.getElementByTestId('visualizationLoader').should( + 'have.length', + NUMBER_OF_VISUALIZATIONS_IN_FLIGHTS_DASHBOARD + ); - verifyVisualizationsWithNoInspectOption(visualizationTitlesWithNoInspectOptions); - verifyVisualizationsWithInspectOption(visualizationTitlesWithInspectOptions); + verifyVisualizationsWithNoInspectOption(visualizationTitlesWithNoInspectOptions); + verifyVisualizationsWithInspectOption(visualizationTitlesWithInspectOptions); + }); }); -}); +}; + +prepareTestSuite('Inspect', inspectTestSuite); diff --git a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/language_specific_display.spec.js b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/language_specific_display.spec.js index 6fc575c459bb..6a9b4ba5aa7b 100644 --- a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/language_specific_display.spec.js +++ b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/language_specific_display.spec.js @@ -4,6 +4,7 @@ */ import { + DATASOURCE_NAME, INDEX_PATTERN_WITH_TIME, INDEX_WITH_TIME_1, INDEX_WITH_TIME_2, @@ -13,22 +14,21 @@ import { import { generateAllTestConfigurations, getRandomizedWorkspaceName, - getRandomizedDatasourceName, setDatePickerDatesAndSearchIfRelevant, } from '../../../../../utils/apps/query_enhancements/shared'; import { generateDisplayTestConfiguration, getLanguageReferenceTestText, } from '../../../../../utils/apps/query_enhancements/language_specific_display'; +import { prepareTestSuite } from '../../../../../utils/helpers'; const workspaceName = getRandomizedWorkspaceName(); -const datasourceName = getRandomizedDatasourceName(); export const runDisplayTests = () => { describe('Language-Specific Display', () => { beforeEach(() => { // Load test data - cy.setupTestData( + cy.osd.setupTestData( SECONDARY_ENGINE.url, [ `cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.mapping.json`, @@ -40,31 +40,30 @@ export const runDisplayTests = () => { ] ); // Add data source - cy.addDataSource({ - name: datasourceName, + cy.osd.addDataSource({ + name: DATASOURCE_NAME, url: SECONDARY_ENGINE.url, authType: 'no_auth', }); // Create workspace - cy.deleteWorkspaceByName(workspaceName); + cy.deleteAllWorkspaces(); cy.visit('/app/home'); - cy.osd.createInitialWorkspaceWithDataSource(datasourceName, workspaceName); + cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspaceName); cy.createWorkspaceIndexPatterns({ workspaceName: workspaceName, indexPattern: INDEX_PATTERN_WITH_TIME.replace('*', ''), timefieldName: 'timestamp', - dataSource: datasourceName, + dataSource: DATASOURCE_NAME, isEnhancement: true, }); }); afterEach(() => { cy.deleteWorkspaceByName(workspaceName); - // // TODO: Modify deleteIndex to handle an array of index and remove hard code - cy.deleteDataSourceByName(datasourceName); - cy.deleteIndex(INDEX_WITH_TIME_1); - cy.deleteIndex(INDEX_WITH_TIME_2); + cy.osd.deleteDataSourceByName(DATASOURCE_NAME); + cy.osd.deleteIndex(INDEX_WITH_TIME_1); + cy.osd.deleteIndex(INDEX_WITH_TIME_2); }); generateAllTestConfigurations(generateDisplayTestConfiguration).forEach((config) => { @@ -75,7 +74,7 @@ export const runDisplayTests = () => { isEnhancement: true, }); - cy.setDataset(config.dataset, datasourceName, config.datasetType); + cy.setDataset(config.dataset, DATASOURCE_NAME, config.datasetType); cy.setQueryLanguage(config.language); setDatePickerDatesAndSearchIfRelevant(config.language); @@ -163,4 +162,4 @@ export const runDisplayTests = () => { }); }; -runDisplayTests(); +prepareTestSuite('Language Specific Display', runDisplayTests); 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 e27e4cd40f41..f12c58b16fbd 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,133 +3,144 @@ * SPDX-License-Identifier: Apache-2.0 */ -import { DATASOURCE_NAME, START_TIME, END_TIME } from '../../../../../utils/apps/constants'; -import { SECONDARY_ENGINE } from '../../../../../utils/constants'; +import { + INDEX_WITH_TIME_1, + DATASOURCE_NAME, + START_TIME, + END_TIME, +} from '../../../../../utils/apps/constants'; +import { PATHS } from '../../../../../utils/constants'; import { getRandomizedWorkspaceName } from '../../../../../utils/apps/query_enhancements/shared'; +import { prepareTestSuite } from '../../../../../utils/helpers'; const workspace = getRandomizedWorkspaceName(); -describe('query enhancement queries', { scrollBehavior: false }, () => { - before(() => { - // Load test data - cy.setupTestData( - SECONDARY_ENGINE.url, - ['cypress/fixtures/query_enhancements/data_logs_1/data_logs_small_time_1.mapping.json'], - ['cypress/fixtures/query_enhancements/data_logs_1/data_logs_small_time_1.data.ndjson'] - ); - - // Add data source - cy.addDataSource({ - name: `${DATASOURCE_NAME}`, - url: `${SECONDARY_ENGINE.url}`, - authType: 'no_auth', - }); - - // Create workspace and set up index pattern - cy.deleteWorkspaceByName(workspace); - cy.visit('/app/home'); - cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspace); - - // Create and select index pattern for data_logs_small_time_1* - cy.createWorkspaceIndexPatterns({ - workspaceName: workspace, - indexPattern: 'data_logs_small_time_1', - timefieldName: 'timestamp', - indexPatternHasTimefield: true, - dataSource: DATASOURCE_NAME, - isEnhancement: true, - }); - - // Go to discover page - cy.navigateToWorkSpaceSpecificPage({ - workspaceName: workspace, - page: 'discover', - isEnhancement: true, - }); - }); - - after(() => { - cy.deleteWorkspaceByName(workspace); - cy.deleteDataSourceByName(`${DATASOURCE_NAME}`); - cy.deleteIndex('data_logs_small_time_1'); - }); - - describe('send queries', () => { - it('with DQL', function () { - cy.setQueryLanguage('DQL'); - cy.setTopNavDate(START_TIME, END_TIME); - - const query = `_id:N9srQ8opwBxGdIoQU3TW`; - cy.setQueryEditor(query); - cy.waitForLoader(true); - cy.waitForSearch(); - cy.verifyHitCount(1); - - // Query should persist across refresh - cy.reload(); - cy.verifyHitCount(1); - }); - - it('with Lucene', function () { - cy.setQueryLanguage('Lucene'); - cy.setTopNavDate(START_TIME, END_TIME); - - const query = `_id:N9srQ8opwBxGdIoQU3TW`; - cy.setQueryEditor(query); - cy.waitForLoader(true); - cy.waitForSearch(); - cy.verifyHitCount(1); +const queriesTestSuite = () => { + describe('query enhancement queries', { scrollBehavior: false }, () => { + beforeEach(() => { + // Load test data + cy.osd.setupTestData( + PATHS.SECONDARY_ENGINE, + [`cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.mapping.json`], + [`cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.data.ndjson`] + ); - // Query should persist across refresh - cy.reload(); - cy.verifyHitCount(1); + // Add data source + cy.osd.addDataSource({ + name: DATASOURCE_NAME, + url: PATHS.SECONDARY_ENGINE, + authType: 'no_auth', + }); + + // Create workspace and set up index pattern + cy.deleteAllWorkspaces(); + cy.visit('/app/home'); + cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspace); + + // Create and select index pattern for ${INDEX_WITH_TIME_1}* + cy.createWorkspaceIndexPatterns({ + workspaceName: workspace, + indexPattern: INDEX_WITH_TIME_1, + timefieldName: 'timestamp', + indexPatternHasTimefield: true, + dataSource: DATASOURCE_NAME, + isEnhancement: true, + }); + + // Go to discover page + cy.navigateToWorkSpaceSpecificPage({ + workspaceName: workspace, + page: 'discover', + isEnhancement: true, + }); }); - it('with SQL', function () { - cy.setQueryLanguage('OpenSearch SQL'); - - // Default SQL query should be set - cy.waitForLoader(true); - cy.getElementByTestId(`osdQueryEditor__multiLine`).contains( - `SELECT * FROM data_logs_small_time_1* LIMIT 10` - ); - cy.getElementByTestId(`queryResultCompleteMsg`).should('be.visible'); - - // Query should persist across refresh - cy.reload(); - cy.getElementByTestId(`queryResultCompleteMsg`).should('be.visible'); - - cy.getElementByTestId('osdQueryEditor__multiLine') - .find('.monaco-editor') - .should('be.visible') - // Ensure editor is in the correct visual state ('vs' is Monaco's default theme) - // This helps verify the editor is fully initialized and ready - .should('have.class', 'vs') - .click() - .find('textarea.inputarea') - .focus() - .type('{backspace}', { force: true }); - - cy.getElementByTestId(`querySubmitButton`).click(); - cy.waitForSearch(); - cy.getElementByTestId(`queryResultCompleteMsg`).should('be.visible'); + afterEach(() => { + cy.deleteWorkspaceByName(workspace); + cy.osd.deleteDataSourceByName(`${DATASOURCE_NAME}`); + cy.osd.deleteIndex(INDEX_WITH_TIME_1); }); - it('with PPL', function () { - cy.setQueryLanguage('PPL'); - - // Default PPL query should be set - cy.waitForLoader(true); - cy.getElementByTestId(`osdQueryEditor__multiLine`).contains( - `source = data_logs_small_time_1*` - ); - cy.waitForSearch(); - cy.getElementByTestId(`queryResultCompleteMsg`).should('be.visible'); - - // Query should persist across refresh - cy.reload(); - cy.getElementByTestId(`queryResultCompleteMsg`).should('be.visible'); - cy.verifyHitCount('10,000'); + describe('send queries', () => { + it('with DQL', function () { + cy.setQueryLanguage('DQL'); + cy.setTopNavDate(START_TIME, END_TIME); + + const query = `_id:N9srQ8opwBxGdIoQU3TW`; + cy.setQueryEditor(query); + cy.waitForLoader(true); + cy.waitForSearch(); + cy.verifyHitCount(1); + + // Query should persist across refresh + cy.reload(); + cy.verifyHitCount(1); + }); + + it('with Lucene', function () { + cy.setQueryLanguage('Lucene'); + cy.setTopNavDate(START_TIME, END_TIME); + + const query = `_id:N9srQ8opwBxGdIoQU3TW`; + cy.setQueryEditor(query); + cy.waitForLoader(true); + cy.waitForSearch(); + cy.verifyHitCount(1); + + // Query should persist across refresh + cy.reload(); + cy.verifyHitCount(1); + }); + + it('with SQL', function () { + cy.setQueryLanguage('OpenSearch SQL'); + + // Default SQL query should be set + cy.waitForLoader(true); + cy.getElementByTestId(`osdQueryEditor__multiLine`).contains( + `SELECT * FROM ${INDEX_WITH_TIME_1}* LIMIT 10` + ); + cy.getElementByTestId(`queryResultCompleteMsg`).should('be.visible'); + + // Query should persist across refresh + cy.reload(); + cy.getElementByTestId(`queryResultCompleteMsg`).should('be.visible'); + + cy.getElementByTestId('osdQueryEditor__multiLine') + .find('.monaco-editor') + .should('be.visible') + // Ensure editor is in the correct visual state ('vs' is Monaco's default theme) + // This helps verify the editor is fully initialized and ready + .should('have.class', 'vs') + .click() + .find('textarea.inputarea') + .focus() + .type('{backspace}', { force: true }); + + cy.getElementByTestId(`querySubmitButton`).click(); + cy.waitForSearch(); + cy.getElementByTestId(`queryResultCompleteMsg`).should('be.visible'); + }); + + it('with PPL', function () { + cy.setQueryLanguage('PPL'); + cy.setTopNavDate(START_TIME, END_TIME); + + // Default PPL query should be set + cy.waitForLoader(true); + cy.getElementByTestId(`osdQueryEditor__multiLine`).contains( + `source = ${INDEX_WITH_TIME_1}*` + ); + cy.waitForSearch(); + cy.getElementByTestId(`queryResultCompleteMsg`).should('be.visible'); + + // Query should persist across refresh + cy.reload(); + cy.getElementByTestId(`queryResultCompleteMsg`).should('be.visible'); + cy.verifyHitCount('10,000'); + }); }); }); -}); +}; + +prepareTestSuite('Queries', queriesTestSuite); 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 7441d7f25b66..81a79d218d7f 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 @@ -9,136 +9,141 @@ import { S3_CLUSTER, } from '../../../../../utils/apps/query_enhancements/constants'; import { getRandomizedWorkspaceName } from '../../../../../utils/apps/query_enhancements/shared'; +import { prepareTestSuite } from '../../../../../utils/helpers'; const workspace = getRandomizedWorkspaceName(); -let dataSourceId = ''; -const definedS3Variables = !S3_CLUSTER.url; +const s3DatasetTestSuite = () => { + let dataSourceId = ''; + const definedS3Variables = !S3_CLUSTER.url; -(definedS3Variables ? describe.skip : describe)( - 'S3 Dataset', - { defaultCommandTimeout: 120000 }, - () => { - before(() => { - cy.request({ - method: 'POST', - url: `${DSM_API}`, - headers: { - 'osd-xsrf': true, - }, - body: { - dataSourceAttr: { - endpoint: S3_CLUSTER.url, - auth: { - type: 'username_password', - credentials: { - username: S3_CLUSTER.username, - password: S3_CLUSTER.password, + (definedS3Variables ? describe.skip : describe)( + 'S3 Dataset', + { defaultCommandTimeout: 120000 }, + () => { + before(() => { + cy.request({ + method: 'POST', + url: `${DSM_API}`, + headers: { + 'osd-xsrf': true, + }, + body: { + dataSourceAttr: { + endpoint: S3_CLUSTER.url, + auth: { + type: 'username_password', + credentials: { + username: S3_CLUSTER.username, + password: S3_CLUSTER.password, + }, }, }, }, - }, - }).then((metaRes) => { - if (metaRes && metaRes.body) { - cy.request({ - method: 'POST', - url: `${DS_API.CREATE_DATA_SOURCE}`, - headers: { - 'osd-xsrf': true, - 'Content-Type': 'application/json', - }, - body: { - attributes: { - title: S3_CLUSTER.name, - description: '', - ...metaRes.body, - endpoint: S3_CLUSTER.url, - auth: { - type: 'username_password', - credentials: { - username: S3_CLUSTER.username, - password: S3_CLUSTER.password, + }).then((metaRes) => { + if (metaRes && metaRes.body) { + cy.request({ + method: 'POST', + url: `${DS_API.CREATE_DATA_SOURCE}`, + headers: { + 'osd-xsrf': true, + 'Content-Type': 'application/json', + }, + body: { + attributes: { + title: S3_CLUSTER.name, + description: '', + ...metaRes.body, + endpoint: S3_CLUSTER.url, + auth: { + type: 'username_password', + credentials: { + username: S3_CLUSTER.username, + password: S3_CLUSTER.password, + }, }, }, }, - }, - }).then((resp) => { - if (resp && resp.body && resp.body.id) { - dataSourceId = resp.body.id; - } - }); - } + }).then((resp) => { + if (resp && resp.body && resp.body.id) { + dataSourceId = resp.body.id; + } + }); + } + }); }); - }); - after(() => { - cy.request({ - method: 'DELETE', - url: `${DS_API.DELETE_DATA_SOURCE}${dataSourceId}`, - body: { force: false }, - headers: { - 'osd-xsrf': true, - }, + after(() => { + cy.request({ + method: 'DELETE', + url: `${DS_API.DELETE_DATA_SOURCE}${dataSourceId}`, + body: { force: false }, + headers: { + 'osd-xsrf': true, + }, + }); }); - }); - describe('Run S3 Query', () => { - beforeEach(() => { - // Create workspace - cy.deleteWorkspaceByName(workspace); - cy.visit('/app/home'); - cy.osd.createInitialWorkspaceWithDataSource(S3_CLUSTER.name, WORKSPACE_NAME); - }); - afterEach(() => { - cy.deleteWorkspaceByName(workspace); - }); + describe('Run S3 Query', () => { + beforeEach(() => { + // Create workspace + cy.deleteWorkspaceByName(workspace); + cy.visit('/app/home'); + cy.osd.createInitialWorkspaceWithDataSource(S3_CLUSTER.name, workspace); + }); + afterEach(() => { + cy.deleteWorkspaceByName(workspace); + }); - it('with SQL', function () { - cy.getElementByTestId(`datasetSelectorButton`).click(); - cy.getElementByTestId(`datasetSelectorAdvancedButton`).click(); + it('with SQL', function () { + cy.getElementByTestId(`datasetSelectorButton`).click(); + cy.getElementByTestId(`datasetSelectorAdvancedButton`).click(); - cy.get(`[title="S3 Connections"]`).click(); - cy.get(`[title="BasicS3Connection"]`).click(); - cy.get(`[title="mys3"]`).click(); - cy.get(`[title="default"]`).click(); - cy.get(`[title="http_logs"]`).click(); - cy.getElementByTestId('datasetSelectorNext').click(); - cy.get(`[class="euiModalHeader__title"]`).should('contain', 'Step 2: Configure data'); + cy.get(`[title="S3 Connections"]`).click(); + cy.get(`[title="BasicS3Connection"]`).click(); + cy.get(`[title="mys3"]`).click(); + cy.get(`[title="default"]`).click(); + cy.get(`[title="http_logs"]`).click(); + cy.getElementByTestId('datasetSelectorNext').click(); + cy.get(`[class="euiModalHeader__title"]`).should('contain', 'Step 2: Configure data'); - cy.getElementByTestId('advancedSelectorLanguageSelect').select('OpenSearch SQL'); - cy.getElementByTestId('advancedSelectorConfirmButton').click(); - cy.waitForLoader(true); - cy.waitForSearch(); + cy.getElementByTestId('advancedSelectorLanguageSelect').select('OpenSearch SQL'); + cy.getElementByTestId('advancedSelectorConfirmButton').click(); + cy.waitForLoader(true); + cy.waitForSearch(); - cy.getElementByTestId('queryEditorLanguageSelector').should('contain', 'OpenSearch SQL'); - cy.get(`[data-test-subj="queryResultCompleteMsg"]`).should('be.visible'); - cy.getElementByTestId('docTable').should('be.visible'); - cy.getElementByTestId('docTable').find('tr').should('have.length', 11); - }); + cy.getElementByTestId('queryEditorLanguageSelector').should('contain', 'OpenSearch SQL'); + cy.get(`[data-test-subj="queryResultCompleteMsg"]`).should('be.visible'); + cy.getElementByTestId('docTable').should('be.visible'); + cy.getElementByTestId('docTable').find('tr').should('have.length', 11); + }); - // Skipping until #8922 is merged in - it.skip('with PPL', function () { - cy.getElementByTestId(`datasetSelectorButton`).click(); - cy.getElementByTestId(`datasetSelectorAdvancedButton`).click(); + // Skipping until #8922 is merged in + it.skip('with PPL', function () { + cy.getElementByTestId(`datasetSelectorButton`).click(); + cy.getElementByTestId(`datasetSelectorAdvancedButton`).click(); - cy.get(`[title="S3 Connections"]`).click(); - cy.get(`[title="BasicS3Connection"]`).click(); - cy.get(`[title="mys3"]`).click(); - cy.get(`[title="default"]`).click(); - cy.get(`[title="http_logs"]`).click(); - cy.getElementByTestId('datasetSelectorNext').click(); - cy.get(`[class="euiModalHeader__title"]`).should('contain', 'Step 2: Configure data'); + cy.get(`[title="S3 Connections"]`).click(); + cy.get(`[title="BasicS3Connection"]`).click(); + cy.get(`[title="mys3"]`).click(); + cy.get(`[title="default"]`).click(); + cy.get(`[title="http_logs"]`).click(); + cy.getElementByTestId('datasetSelectorNext').click(); + cy.get(`[class="euiModalHeader__title"]`).should('contain', 'Step 2: Configure data'); - cy.getElementByTestId('advancedSelectorLanguageSelect').select('PPL'); - cy.getElementByTestId('advancedSelectorConfirmButton').click(); - cy.waitForLoader(true); - cy.waitForSearch(); + cy.getElementByTestId('advancedSelectorLanguageSelect').select('PPL'); + cy.getElementByTestId('advancedSelectorConfirmButton').click(); + cy.waitForLoader(true); + cy.waitForSearch(); - cy.getElementByTestId('queryEditorLanguageSelector').should('contain', 'PPL'); - cy.get(`[data-test-subj="queryResultCompleteMsg"]`).should('be.visible'); - cy.getElementByTestId('docTable').should('be.visible'); - cy.getElementByTestId('docTable').find('tr').should('have.length', 11); + cy.getElementByTestId('queryEditorLanguageSelector').should('contain', 'PPL'); + cy.get(`[data-test-subj="queryResultCompleteMsg"]`).should('be.visible'); + cy.getElementByTestId('docTable').should('be.visible'); + cy.getElementByTestId('docTable').find('tr').should('have.length', 11); + }); }); - }); - } -); + } + ); +}; + +prepareTestSuite('S3 Dataset', s3DatasetTestSuite); diff --git a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_queries.spec.js b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_queries.spec.js index 062ac35c2481..eeac79928b83 100644 --- a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_queries.spec.js +++ b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_queries.spec.js @@ -4,10 +4,11 @@ */ import { + DATASOURCE_NAME, INDEX_PATTERN_WITH_TIME, INDEX_WITH_TIME_1, INDEX_WITH_TIME_2, - SECONDARY_ENGINE, + PATHS, } from '../../../../../utils/constants'; import { @@ -21,15 +22,14 @@ import { import { getRandomizedWorkspaceName, - getRandomizedDatasourceName, setDatePickerDatesAndSearchIfRelevant, generateAllTestConfigurations, } from '../../../../../utils/apps/query_enhancements/shared'; import { generateSavedTestConfiguration } from '../../../../../utils/apps/query_enhancements/saved'; +import { prepareTestSuite } from '../../../../../utils/helpers'; const workspaceName = getRandomizedWorkspaceName(); -const datasourceName = getRandomizedDatasourceName(); const createSavedQuery = (config) => { cy.navigateToWorkSpaceSpecificPage({ @@ -38,7 +38,7 @@ const createSavedQuery = (config) => { isEnhancement: true, }); - cy.setDataset(config.dataset, datasourceName, config.datasetType); + cy.setDataset(config.dataset, DATASOURCE_NAME, config.datasetType); cy.setQueryLanguage(config.language); setDatePickerDatesAndSearchIfRelevant(config.language); @@ -58,7 +58,7 @@ const loadSavedQuery = (config) => { cy.getElementByTestId('discoverNewButton').click(); // Todo - Date Picker sometimes does not load when expected. Have to set dataset and query language again. - cy.setDataset(config.dataset, datasourceName, config.datasetType); + cy.setDataset(config.dataset, DATASOURCE_NAME, config.datasetType); cy.setQueryLanguage(config.language); setDatePickerDatesAndSearchIfRelevant( @@ -102,13 +102,12 @@ const deleteSavedQuery = (saveAsNewQueryName) => { verifyQueryDoesNotExistInSavedQueries(saveAsNewQueryName); }; -// This spec assumes data.savedQueriesNewUI.enabled is true. -export const runSavedQueriesUITests = () => { +const runSavedQueriesUITests = () => { describe('saved queries UI', () => { beforeEach(() => { // Load test data - cy.setupTestData( - SECONDARY_ENGINE.url, + cy.osd.setupTestData( + PATHS.SECONDARY_ENGINE, [ `cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.mapping.json`, `cypress/fixtures/query_enhancements/data_logs_2/${INDEX_WITH_TIME_2}.mapping.json`, @@ -119,21 +118,21 @@ export const runSavedQueriesUITests = () => { ] ); // Add data source - cy.addDataSource({ - name: datasourceName, - url: SECONDARY_ENGINE.url, + cy.osd.addDataSource({ + name: DATASOURCE_NAME, + url: PATHS.SECONDARY_ENGINE, authType: 'no_auth', }); // Create workspace - cy.deleteWorkspaceByName(workspaceName); + cy.deleteAllWorkspaces(); cy.visit('/app/home'); - cy.osd.createInitialWorkspaceWithDataSource(datasourceName, workspaceName); + cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspaceName); cy.createWorkspaceIndexPatterns({ workspaceName: workspaceName, indexPattern: INDEX_PATTERN_WITH_TIME.replace('*', ''), timefieldName: 'timestamp', - dataSource: datasourceName, + dataSource: DATASOURCE_NAME, isEnhancement: true, }); }); @@ -141,10 +140,9 @@ export const runSavedQueriesUITests = () => { 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 - cy.deleteDataSourceByName(datasourceName); - cy.deleteIndex(INDEX_WITH_TIME_1); - cy.deleteIndex(INDEX_WITH_TIME_2); + cy.osd.deleteDataSourceByName(DATASOURCE_NAME); + cy.osd.deleteIndex(INDEX_WITH_TIME_1); + cy.osd.deleteIndex(INDEX_WITH_TIME_2); }); const testConfigurations = generateAllTestConfigurations(generateSavedTestConfiguration); @@ -163,4 +161,4 @@ export const runSavedQueriesUITests = () => { }); }; -runSavedQueriesUITests(); +prepareTestSuite('Saved Queries', runSavedQueriesUITests); 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 9494a73dd324..b1e8c3c1ca5d 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 @@ -8,12 +8,12 @@ import { INDEX_WITH_TIME_1, INDEX_WITH_TIME_2, QueryLanguages, - SECONDARY_ENGINE, + PATHS, + DATASOURCE_NAME, } from '../../../../../utils/constants'; import { generateAllTestConfigurations, getRandomizedWorkspaceName, - getRandomizedDatasourceName, setDatePickerDatesAndSearchIfRelevant, } from '../../../../../utils/apps/query_enhancements/shared'; import { @@ -24,16 +24,16 @@ import { updateSavedSearchAndSaveAndVerify, generateSavedTestConfiguration, } from '../../../../../utils/apps/query_enhancements/saved'; +import { prepareTestSuite } from '../../../../../utils/helpers'; const workspaceName = getRandomizedWorkspaceName(); -const datasourceName = getRandomizedDatasourceName(); -export const runSavedSearchTests = () => { +const runSavedSearchTests = () => { describe('saved search', () => { beforeEach(() => { // Load test data - cy.setupTestData( - SECONDARY_ENGINE.url, + cy.osd.setupTestData( + PATHS.SECONDARY_ENGINE, [ `cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.mapping.json`, `cypress/fixtures/query_enhancements/data_logs_2/${INDEX_WITH_TIME_2}.mapping.json`, @@ -44,31 +44,30 @@ export const runSavedSearchTests = () => { ] ); // Add data source - cy.addDataSource({ - name: datasourceName, - url: SECONDARY_ENGINE.url, + cy.osd.addDataSource({ + name: DATASOURCE_NAME, + url: PATHS.SECONDARY_ENGINE, authType: 'no_auth', }); // Create workspace - cy.deleteWorkspaceByName(workspaceName); + cy.deleteAllWorkspaces(); cy.visit('/app/home'); - cy.osd.createInitialWorkspaceWithDataSource(datasourceName, workspaceName); + cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspaceName); cy.createWorkspaceIndexPatterns({ workspaceName: workspaceName, indexPattern: INDEX_PATTERN_WITH_TIME.replace('*', ''), timefieldName: 'timestamp', - dataSource: datasourceName, + dataSource: DATASOURCE_NAME, isEnhancement: true, }); }); afterEach(() => { cy.deleteWorkspaceByName(workspaceName); - // // TODO: Modify deleteIndex to handle an array of index and remove hard code - cy.deleteDataSourceByName(datasourceName); - cy.deleteIndex(INDEX_WITH_TIME_1); - cy.deleteIndex(INDEX_WITH_TIME_2); + cy.osd.deleteDataSourceByName(DATASOURCE_NAME); + cy.osd.deleteIndex(INDEX_WITH_TIME_1); + cy.osd.deleteIndex(INDEX_WITH_TIME_2); }); generateAllTestConfigurations(generateSavedTestConfiguration).forEach((config) => { @@ -79,7 +78,7 @@ export const runSavedSearchTests = () => { isEnhancement: true, }); - cy.setDataset(config.dataset, datasourceName, config.datasetType); + cy.setDataset(config.dataset, DATASOURCE_NAME, config.datasetType); cy.setQueryLanguage(config.language); setDatePickerDatesAndSearchIfRelevant(config.language); @@ -120,7 +119,7 @@ export const runSavedSearchTests = () => { // This means that we are only testing loading a saved search // starting from an INDEX_PATTERN dataset, but I think testing where the // start is a permutation of other dataset is overkill - cy.setIndexPatternAsDataset(INDEX_PATTERN_WITH_TIME, datasourceName); + cy.setIndexPatternAsDataset(INDEX_PATTERN_WITH_TIME, DATASOURCE_NAME); cy.setQueryLanguage(startingLanguage); cy.loadSaveSearch(config.saveName); @@ -132,16 +131,16 @@ 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, workspaceName, datasourceName, false); + updateSavedSearchAndSaveAndVerify(config, workspaceName, DATASOURCE_NAME, 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, workspaceName, datasourceName, true); + updateSavedSearchAndSaveAndVerify(config, workspaceName, DATASOURCE_NAME, true); }); }); }); }; -runSavedSearchTests(); +prepareTestSuite('Saved Search', runSavedSearchTests); diff --git a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_search_in_dashboards.spec.js b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_search_in_dashboards.spec.js index 635276fc167c..60c2d926c610 100644 --- a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_search_in_dashboards.spec.js +++ b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/saved_search_in_dashboards.spec.js @@ -5,16 +5,16 @@ import { DatasetTypes, + DATASOURCE_NAME, INDEX_PATTERN_WITH_TIME, INDEX_WITH_TIME_1, INDEX_WITH_TIME_2, QueryLanguages, - SECONDARY_ENGINE, + PATHS, START_TIME, } from '../../../../../utils/constants'; import { getRandomizedWorkspaceName, - getRandomizedDatasourceName, setDatePickerDatesAndSearchIfRelevant, } from '../../../../../utils/apps/query_enhancements/shared'; import { @@ -24,16 +24,16 @@ import { loadSavedSearchFromDashboards, navigateToDashboardAndOpenSavedSearchPanel, } from '../../../../../utils/apps/query_enhancements/saved'; +import { prepareTestSuite } from '../../../../../utils/helpers'; const workspaceName = getRandomizedWorkspaceName(); -const datasourceName = getRandomizedDatasourceName(); export const runSavedSearchTests = () => { describe('saved search in dashboards', () => { beforeEach(() => { // Load test data - cy.setupTestData( - SECONDARY_ENGINE.url, + cy.osd.setupTestData( + PATHS.SECONDARY_ENGINE, [ `cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.mapping.json`, `cypress/fixtures/query_enhancements/data_logs_2/${INDEX_WITH_TIME_2}.mapping.json`, @@ -44,31 +44,30 @@ export const runSavedSearchTests = () => { ] ); // Add data source - cy.addDataSource({ - name: datasourceName, - url: SECONDARY_ENGINE.url, + cy.osd.addDataSource({ + name: DATASOURCE_NAME, + url: PATHS.SECONDARY_ENGINE, authType: 'no_auth', }); // Create workspace - cy.deleteWorkspaceByName(workspaceName); + cy.deleteAllWorkspaces(); cy.visit('/app/home'); - cy.osd.createInitialWorkspaceWithDataSource(datasourceName, workspaceName); + cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspaceName); cy.createWorkspaceIndexPatterns({ workspaceName: workspaceName, indexPattern: INDEX_PATTERN_WITH_TIME.replace('*', ''), timefieldName: 'timestamp', - dataSource: datasourceName, + dataSource: DATASOURCE_NAME, isEnhancement: true, }); }); afterEach(() => { cy.deleteWorkspaceByName(workspaceName); - // // TODO: Modify deleteIndex to handle an array of index and remove hard code - cy.deleteDataSourceByName(datasourceName); - cy.deleteIndex(INDEX_WITH_TIME_1); - cy.deleteIndex(INDEX_WITH_TIME_2); + cy.osd.deleteDataSourceByName(DATASOURCE_NAME); + cy.osd.deleteIndex(INDEX_WITH_TIME_1); + cy.osd.deleteIndex(INDEX_WITH_TIME_2); }); it('Load a saved search', () => { @@ -153,4 +152,4 @@ export const runSavedSearchTests = () => { }); }; -runSavedSearchTests(); +prepareTestSuite('Saved Search in Dashboards', runSavedSearchTests); diff --git a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/shared_links.spec.js b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/shared_links.spec.js index ebb8bbb2d676..03a5319eb7c5 100644 --- a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/shared_links.spec.js +++ b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/shared_links.spec.js @@ -7,11 +7,11 @@ import { DatasetTypes, INDEX_WITH_TIME_1, INDEX_PATTERN_WITH_TIME_1, - SECONDARY_ENGINE, + PATHS, + DATASOURCE_NAME, } from '../../../../../utils/constants'; import { getRandomizedWorkspaceName, - getRandomizedDatasourceName, generateAllTestConfigurations, setDatePickerDatesAndSearchIfRelevant, setHistogramIntervalIfRelevant, @@ -20,9 +20,9 @@ import { QueryLanguages } from '../../../../../utils/apps/query_enhancements/con import { selectFieldFromSidebar } from '../../../../../utils/apps/query_enhancements/sidebar'; import { verifyShareUrl } from '../../../../../utils/apps/query_enhancements/shared_links'; import { setSort } from '../../../../../utils/apps/query_enhancements/table'; +import { prepareTestSuite } from '../../../../../utils/helpers'; const workspaceName = getRandomizedWorkspaceName(); -const datasourceName = getRandomizedDatasourceName(); const generateShareUrlsTestConfiguration = (dataset, datasetType, language) => { const baseConfig = { @@ -62,25 +62,25 @@ export const runSharedLinksTests = () => { filter: ['category', 'Network'], }; beforeEach(() => { - cy.setupTestData( - SECONDARY_ENGINE.url, + cy.osd.setupTestData( + PATHS.SECONDARY_ENGINE, [`cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.mapping.json`], [`cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.data.ndjson`] ); - cy.addDataSource({ - name: datasourceName, - url: SECONDARY_ENGINE.url, + cy.osd.addDataSource({ + name: DATASOURCE_NAME, + url: PATHS.SECONDARY_ENGINE, authType: 'no_auth', }); cy.deleteWorkspaceByName(workspaceName); cy.visit('/app/home'); - cy.osd.createInitialWorkspaceWithDataSource(datasourceName, workspaceName); + cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspaceName); }); afterEach(() => { cy.deleteWorkspaceByName(workspaceName); - cy.deleteDataSourceByName(datasourceName); - cy.deleteIndex(INDEX_WITH_TIME_1); + cy.osd.deleteDataSourceByName(DATASOURCE_NAME); + cy.osd.deleteIndex(INDEX_WITH_TIME_1); }); generateAllTestConfigurations(generateShareUrlsTestConfiguration, { @@ -94,7 +94,7 @@ export const runSharedLinksTests = () => { workspaceName: workspaceName, indexPattern: INDEX_WITH_TIME_1, timefieldName: 'timestamp', - dataSource: datasourceName, + dataSource: DATASOURCE_NAME, isEnhancement: true, }); } @@ -109,7 +109,7 @@ export const runSharedLinksTests = () => { it(`should handle shared document links correctly for ${config.testName}`, () => { // Setup - cy.setDataset(config.dataset, datasourceName, config.datasetType); + cy.setDataset(config.dataset, DATASOURCE_NAME, config.datasetType); cy.setQueryLanguage(config.language); setDatePickerDatesAndSearchIfRelevant(config.language); @@ -154,7 +154,7 @@ export const runSharedLinksTests = () => { it(`should persist state in shared links for ${config.testName}`, () => { // Set dataset and language - cy.setDataset(config.dataset, datasourceName, config.datasetType); + cy.setDataset(config.dataset, DATASOURCE_NAME, config.datasetType); cy.setQueryLanguage(config.language); setDatePickerDatesAndSearchIfRelevant(config.language); @@ -182,7 +182,7 @@ export const runSharedLinksTests = () => { cy.getElementByTestId('copyShareUrlButton') .invoke('attr', 'data-share-url') .then((url) => { - verifyShareUrl(url, config, testData, datasourceName, queryString); + verifyShareUrl(url, config, testData, DATASOURCE_NAME, queryString); }); // Test short url @@ -199,7 +199,7 @@ export const runSharedLinksTests = () => { }) .then((response) => { const redirectUrl = response.headers.location; - verifyShareUrl(redirectUrl, config, testData, datasourceName, queryString); + verifyShareUrl(redirectUrl, config, testData, DATASOURCE_NAME, queryString); }); // Test saved object url @@ -230,4 +230,4 @@ export const runSharedLinksTests = () => { }); }; -runSharedLinksTests(); +prepareTestSuite('Shared Links', runSharedLinksTests); diff --git a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/sidebar.spec.js b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/sidebar.spec.js index 1598aa263d80..05940f25d384 100644 --- a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/sidebar.spec.js +++ b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/sidebar.spec.js @@ -7,20 +7,20 @@ import { DatasetTypes, INDEX_WITH_TIME_1, INDEX_PATTERN_WITH_TIME_1, - SECONDARY_ENGINE, + PATHS, + DATASOURCE_NAME, } from '../../../../../utils/constants'; import { generateAllTestConfigurations, getRandomizedWorkspaceName, - getRandomizedDatasourceName, setDatePickerDatesAndSearchIfRelevant, } from '../../../../../utils/apps/query_enhancements/shared'; import { getDocTableField } from '../../../../../utils/apps/query_enhancements/doc_table'; import * as sideBar from '../../../../../utils/apps/query_enhancements/sidebar'; import { generateSavedTestConfiguration } from '../../../../../utils/apps/query_enhancements/saved'; +import { prepareTestSuite } from '../../../../../utils/helpers'; const workspaceName = getRandomizedWorkspaceName(); -const datasourceName = getRandomizedDatasourceName(); const addSidebarFieldsAndCheckDocTableColumns = ( testFields, @@ -143,25 +143,25 @@ export const runSideBarTests = () => { }; beforeEach(() => { - cy.setupTestData( - SECONDARY_ENGINE.url, + cy.osd.setupTestData( + PATHS.SECONDARY_ENGINE, [`cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.mapping.json`], [`cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.data.ndjson`] ); - cy.addDataSource({ - name: datasourceName, - url: SECONDARY_ENGINE.url, + cy.osd.addDataSource({ + name: DATASOURCE_NAME, + url: PATHS.SECONDARY_ENGINE, authType: 'no_auth', }); cy.deleteWorkspaceByName(workspaceName); cy.visit('/app/home'); - cy.osd.createInitialWorkspaceWithDataSource(datasourceName, workspaceName); + cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspaceName); }); afterEach(() => { cy.deleteWorkspaceByName(workspaceName); - cy.deleteDataSourceByName(datasourceName); - cy.deleteIndex(INDEX_WITH_TIME_1); + cy.osd.deleteDataSourceByName(DATASOURCE_NAME); + cy.osd.deleteIndex(INDEX_WITH_TIME_1); cy.window().then((win) => { win.localStorage.clear(); win.sessionStorage.clear(); @@ -179,7 +179,7 @@ export const runSideBarTests = () => { workspaceName: workspaceName, indexPattern: INDEX_WITH_TIME_1, timefieldName: 'timestamp', - dataSource: datasourceName, + dataSource: DATASOURCE_NAME, isEnhancement: true, }); } @@ -188,7 +188,7 @@ export const runSideBarTests = () => { page: 'discover', isEnhancement: true, }); - cy.setDataset(config.dataset, datasourceName, config.datasetType); + cy.setDataset(config.dataset, DATASOURCE_NAME, config.datasetType); cy.setQueryLanguage(config.language); setDatePickerDatesAndSearchIfRelevant(config.language); sideBar.removeAllSelectedFields(); @@ -200,7 +200,7 @@ export const runSideBarTests = () => { testData.simpleFields.expectedValues, testData.pplQuery(config.dataset), testData.sqlQuery(config.dataset), - cconfig.datasetType === DatasetTypes.INDEX_PATTERN.name, + config.datasetType === DatasetTypes.INDEX_PATTERN.name, config ); }); @@ -228,4 +228,4 @@ export const runSideBarTests = () => { }); }; -runSideBarTests(); +prepareTestSuite('Sidebar', runSideBarTests); diff --git a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/simple_dataset_selector.spec.js b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/simple_dataset_selector.spec.js index 9a61a067aee9..2347ebd8d876 100644 --- a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/simple_dataset_selector.spec.js +++ b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/simple_dataset_selector.spec.js @@ -8,11 +8,11 @@ import { INDEX_WITH_TIME_1, INDEX_PATTERN_WITH_NO_TIME, INDEX_WITHOUT_TIME_1, - SECONDARY_ENGINE, + PATHS, + DATASOURCE_NAME, } from '../../../../../utils/constants'; import { getRandomizedWorkspaceName, - getRandomizedDatasourceName, getDefaultQuery, setDatePickerDatesAndSearchIfRelevant, } from '../../../../../utils/apps/query_enhancements/shared'; @@ -21,17 +21,17 @@ import { generateSimpleDatasetSelectorTestConfigurations, validateItemsInSimpleDatasetSelectorDropDown, } from '../../../../../utils/apps/query_enhancements/simple_dataset_selector'; +import { prepareTestSuite } from '../../../../../utils/helpers'; const workspaceName = getRandomizedWorkspaceName(); -const datasourceName = getRandomizedDatasourceName(); const noIndexPatterns = 5; // Determines the no of index patterns that should be in the dropdown for filtering test case export const runSimpleDatasetSelectorTests = () => { describe('simple dataset selector selecting an index pattern', () => { beforeEach(() => { // Load test data - cy.setupTestData( - SECONDARY_ENGINE.url, + cy.osd.setupTestData( + PATHS.SECONDARY_ENGINE, [ `cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.mapping.json`, `cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITHOUT_TIME_1}.mapping.json`, @@ -42,28 +42,28 @@ export const runSimpleDatasetSelectorTests = () => { ] ); // Add data source - cy.addDataSource({ - name: datasourceName, - url: SECONDARY_ENGINE.url, + cy.osd.addDataSource({ + name: DATASOURCE_NAME, + url: PATHS.SECONDARY_ENGINE, authType: 'no_auth', }); // Create workspace - cy.deleteWorkspaceByName(workspaceName); + cy.deleteAllWorkspaces(); cy.visit('/app/home'); - cy.osd.createInitialWorkspaceWithDataSource(datasourceName, workspaceName); + cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspaceName); cy.createWorkspaceIndexPatterns({ workspaceName: workspaceName, indexPattern: INDEX_PATTERN_WITH_TIME.replace('*', ''), timefieldName: 'timestamp', - dataSource: datasourceName, + dataSource: DATASOURCE_NAME, isEnhancement: true, }); cy.createWorkspaceIndexPatterns({ workspaceName: workspaceName, indexPattern: INDEX_PATTERN_WITH_NO_TIME.replace('*', ''), timefieldName: '', - dataSource: datasourceName, + dataSource: DATASOURCE_NAME, isEnhancement: true, indexPatternHasTimefield: false, }); @@ -71,10 +71,9 @@ export const runSimpleDatasetSelectorTests = () => { afterEach(() => { cy.deleteWorkspaceByName(workspaceName); - // TODO: Modify deleteIndex to handle an array of index and remove hard code - cy.deleteDataSourceByName(datasourceName); - cy.deleteIndex(INDEX_WITH_TIME_1); - cy.deleteIndex(INDEX_WITHOUT_TIME_1); + cy.osd.deleteDataSourceByName(DATASOURCE_NAME); + cy.osd.deleteIndex(INDEX_WITH_TIME_1); + cy.osd.deleteIndex(INDEX_WITHOUT_TIME_1); }); generateSimpleDatasetSelectorTestConfigurations([ @@ -102,7 +101,7 @@ export const runSimpleDatasetSelectorTests = () => { cy.setQueryLanguage(config.language); // Select the index pattern - cy.setIndexPatternAsDataset(config.indexPattern, datasourceName); + cy.setIndexPatternAsDataset(config.indexPattern, DATASOURCE_NAME); // Verify if the language is unchanged, we get a default query populated, and correct dataset is set verifyDiscoverPageState({ @@ -129,8 +128,8 @@ export const runSimpleDatasetSelectorTests = () => { describe('filtering index pattern in simple dataset selector', () => { beforeEach(() => { // Load test data - cy.setupTestData( - SECONDARY_ENGINE.url, + cy.osd.setupTestData( + PATHS.SECONDARY_ENGINE, [ `cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.mapping.json`, `cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITHOUT_TIME_1}.mapping.json`, @@ -141,23 +140,23 @@ export const runSimpleDatasetSelectorTests = () => { ] ); // Add data source - cy.addDataSource({ - name: datasourceName, - url: SECONDARY_ENGINE.url, + cy.osd.addDataSource({ + name: DATASOURCE_NAME, + url: PATHS.SECONDARY_ENGINE, authType: 'no_auth', }); // Create workspace cy.deleteWorkspaceByName(workspaceName); cy.visit('/app/home'); - cy.osd.createInitialWorkspaceWithDataSource(datasourceName, workspaceName); + cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspaceName); for (let i = 1; i <= noIndexPatterns; i++) { cy.createWorkspaceIndexPatterns({ workspaceName: workspaceName, indexPattern: INDEX_PATTERN_WITH_TIME.slice(0, i), timefieldName: 'timestamp', - dataSource: datasourceName, + dataSource: DATASOURCE_NAME, isEnhancement: true, }); } @@ -165,10 +164,9 @@ export const runSimpleDatasetSelectorTests = () => { afterEach(() => { cy.deleteWorkspaceByName(workspaceName); - // TODO: Modify deleteIndex to handle an array of index and remove hard code - cy.deleteDataSourceByName(datasourceName); - cy.deleteIndex(INDEX_WITH_TIME_1); - cy.deleteIndex(INDEX_WITHOUT_TIME_1); + cy.osd.deleteDataSourceByName(DATASOURCE_NAME); + cy.osd.deleteIndex(INDEX_WITH_TIME_1); + cy.osd.deleteIndex(INDEX_WITHOUT_TIME_1); }); it('validate filtering index pattern in simple dataset selector', () => { @@ -188,4 +186,4 @@ export const runSimpleDatasetSelectorTests = () => { }); }; -runSimpleDatasetSelectorTests(); +prepareTestSuite('Simple Dataset Selector', runSimpleDatasetSelectorTests); diff --git a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/table.spec.js b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/table.spec.js index 64cd43dfb120..76630bdb73ea 100644 --- a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/table.spec.js +++ b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/table.spec.js @@ -4,25 +4,25 @@ */ import { + DATASOURCE_NAME, DatasetTypes, INDEX_WITH_TIME_1, INDEX_WITHOUT_TIME_1, INDEX_PATTERN_WITH_TIME_1, INDEX_PATTERN_WITH_NO_TIME_1, - SECONDARY_ENGINE, + PATHS, } from '../../../../../utils/constants'; import { getRandomizedWorkspaceName, - getRandomizedDatasourceName, generateAllTestConfigurations, generateIndexPatternTestConfigurations, setDatePickerDatesAndSearchIfRelevant, } from '../../../../../utils/apps/query_enhancements/shared'; import { QueryLanguages } from '../../../../../utils/apps/query_enhancements/constants'; import { selectFieldFromSidebar } from '../../../../../utils/apps/query_enhancements/sidebar'; +import { prepareTestSuite } from '../../../../../utils/helpers'; const workspaceName = getRandomizedWorkspaceName(); -const datasourceName = getRandomizedDatasourceName(); const generateTableTestConfiguration = (dataset, datasetType, language) => { const baseConfig = { @@ -40,8 +40,8 @@ const generateTableTestConfiguration = (dataset, datasetType, language) => { export const runTableTests = () => { describe('discover table tests', () => { beforeEach(() => { - cy.setupTestData( - SECONDARY_ENGINE.url, + cy.osd.setupTestData( + PATHS.SECONDARY_ENGINE, [ `cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.mapping.json`, `cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITHOUT_TIME_1}.mapping.json`, @@ -51,19 +51,19 @@ export const runTableTests = () => { `cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITHOUT_TIME_1}.data.ndjson`, ] ); - cy.addDataSource({ - name: datasourceName, - url: SECONDARY_ENGINE.url, + cy.osd.addDataSource({ + name: DATASOURCE_NAME, + url: PATHS.SECONDARY_ENGINE, authType: 'no_auth', }); - cy.deleteWorkspaceByName(workspaceName); + cy.deleteAllWorkspaces(); cy.visit('/app/home'); - cy.osd.createInitialWorkspaceWithDataSource(datasourceName, workspaceName); + cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspaceName); }); afterEach(() => { cy.deleteWorkspaceByName(workspaceName); - cy.deleteDataSourceByName(datasourceName); + cy.osd.deleteDataSourceByName(DATASOURCE_NAME); cy.window().then((win) => { win.localStorage.clear(); win.sessionStorage.clear(); @@ -81,7 +81,7 @@ export const runTableTests = () => { workspaceName: workspaceName, indexPattern: INDEX_WITH_TIME_1, timefieldName: 'timestamp', - dataSource: datasourceName, + dataSource: DATASOURCE_NAME, isEnhancement: true, }); } @@ -92,12 +92,12 @@ export const runTableTests = () => { }); }); afterEach(() => { - cy.deleteIndex(INDEX_WITH_TIME_1); + cy.osd.deleteIndex(INDEX_WITH_TIME_1); }); it(`should allow expand multiple documents for ${config.testName}`, () => { // Setup - cy.setDataset(config.dataset, datasourceName, config.datasetType); + cy.setDataset(config.dataset, DATASOURCE_NAME, config.datasetType); cy.setQueryLanguage(config.language); setDatePickerDatesAndSearchIfRelevant(config.language); // expanding a document in the table @@ -143,7 +143,7 @@ export const runTableTests = () => { indexPattern: INDEX_WITHOUT_TIME_1, timefieldName: '', indexPatternHasTimefield: false, - dataSource: datasourceName, + dataSource: DATASOURCE_NAME, isEnhancement: true, }); } @@ -154,14 +154,14 @@ export const runTableTests = () => { }); }); afterEach(() => { - cy.deleteIndex(INDEX_WITHOUT_TIME_1); + cy.osd.deleteIndex(INDEX_WITHOUT_TIME_1); }); // TODO: Currently sort is not applicable for nested field. Should include and test nested field if sort can support. const testFields = ['category', 'response_time']; it(`sort for ${config.testName}`, () => { // Setup - cy.setDataset(config.dataset, datasourceName, config.datasetType); + cy.setDataset(config.dataset, DATASOURCE_NAME, config.datasetType); cy.setQueryLanguage(config.language); // Add fields testFields.forEach((field) => { @@ -193,4 +193,4 @@ export const runTableTests = () => { }); }; -runTableTests(); +prepareTestSuite('Table', runTableTests); diff --git a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/time_range_selection.spec.js b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/time_range_selection.spec.js index 187520b76eb6..3849ec7750f6 100644 --- a/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/time_range_selection.spec.js +++ b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/time_range_selection.spec.js @@ -4,27 +4,27 @@ */ import { + DATASOURCE_NAME, INDEX_PATTERN_WITH_TIME, INDEX_WITH_TIME_1, INDEX_WITH_TIME_2, - SECONDARY_ENGINE, + PATHS, } from '../../../../../utils/constants'; import { generateAllTestConfigurations, getRandomizedWorkspaceName, - getRandomizedDatasourceName, } from '../../../../../utils/apps/query_enhancements/shared'; import { generateTimeRangeTestConfiguration } from '../../../../../utils/apps/query_enhancements/time_range_selection'; +import { prepareTestSuite } from '../../../../../utils/helpers'; const workspaceName = getRandomizedWorkspaceName(); -const datasourceName = getRandomizedDatasourceName(); export const runTimeRangeSelectionTests = () => { describe('Time Range Selection Tests', () => { beforeEach(() => { // Load test data - cy.setupTestData( - SECONDARY_ENGINE.url, + cy.osd.setupTestData( + PATHS.SECONDARY_ENGINE, [ `cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.mapping.json`, `cypress/fixtures/query_enhancements/data_logs_2/${INDEX_WITH_TIME_2}.mapping.json`, @@ -35,31 +35,30 @@ export const runTimeRangeSelectionTests = () => { ] ); // Add data source - cy.addDataSource({ - name: datasourceName, - url: SECONDARY_ENGINE.url, + cy.osd.addDataSource({ + name: DATASOURCE_NAME, + url: PATHS.SECONDARY_ENGINE, authType: 'no_auth', }); // Create workspace - cy.deleteWorkspaceByName(workspaceName); + cy.deleteAllWorkspaces(); cy.visit('/app/home'); - cy.osd.createInitialWorkspaceWithDataSource(datasourceName, workspaceName); + cy.osd.createInitialWorkspaceWithDataSource(DATASOURCE_NAME, workspaceName); cy.createWorkspaceIndexPatterns({ workspaceName: workspaceName, indexPattern: INDEX_PATTERN_WITH_TIME.replace('*', ''), timefieldName: 'timestamp', - dataSource: datasourceName, + dataSource: DATASOURCE_NAME, isEnhancement: true, }); }); afterEach(() => { cy.deleteWorkspaceByName(workspaceName); - // TODO: Modify deleteIndex to handle an array of index and remove hard code - cy.deleteDataSourceByName(datasourceName); - cy.deleteIndex(INDEX_WITH_TIME_1); - cy.deleteIndex(INDEX_WITH_TIME_2); + cy.osd.deleteDataSourceByName(DATASOURCE_NAME); + cy.osd.deleteIndex(INDEX_WITH_TIME_1); + cy.osd.deleteIndex(INDEX_WITH_TIME_2); }); generateAllTestConfigurations(generateTimeRangeTestConfiguration).forEach((config) => { @@ -70,7 +69,7 @@ export const runTimeRangeSelectionTests = () => { isEnhancement: true, }); - cy.setDataset(config.dataset, datasourceName, config.datasetType); + cy.setDataset(config.dataset, DATASOURCE_NAME, config.datasetType); cy.setQueryLanguage(config.language.name); @@ -91,7 +90,7 @@ export const runTimeRangeSelectionTests = () => { isEnhancement: true, }); - cy.setDataset(config.dataset, datasourceName, config.datasetType); + cy.setDataset(config.dataset, DATASOURCE_NAME, config.datasetType); cy.setQueryLanguage(config.language.name); @@ -112,7 +111,7 @@ export const runTimeRangeSelectionTests = () => { isEnhancement: true, }); - cy.setDataset(config.dataset, datasourceName, config.datasetType); + cy.setDataset(config.dataset, DATASOURCE_NAME, config.datasetType); cy.setQueryLanguage(config.language.name); @@ -129,4 +128,4 @@ export const runTimeRangeSelectionTests = () => { }); }; -runTimeRangeSelectionTests(); +prepareTestSuite('Time Range Selection', runTimeRangeSelectionTests); diff --git a/cypress/support/e2e.js b/cypress/support/e2e.js index b8f16fe07937..34f318276f77 100644 --- a/cypress/support/e2e.js +++ b/cypress/support/e2e.js @@ -4,6 +4,7 @@ */ import '../utils/commands'; +import '../utils/commands.osd'; import '../utils/apps/commands'; import '../utils/dashboards/workspace-plugin/commands'; import '../utils/dashboards/commands'; diff --git a/cypress/utils/apps/data_explorer/commands.js b/cypress/utils/apps/data_explorer/commands.js index 54f30c682e62..7e826f4ae078 100644 --- a/cypress/utils/apps/data_explorer/commands.js +++ b/cypress/utils/apps/data_explorer/commands.js @@ -5,18 +5,6 @@ export const toTestId = (str, replace = '-') => str.replace(/\s+/g, replace); -Cypress.Commands.add('verifyTimeConfig', (start, end) => { - const opts = { log: false }; - - cy.getElementByTestId('superDatePickerstartDatePopoverButton', opts) - .should('be.visible') - .should('have.text', start); - - cy.getElementByTestId('superDatePickerendDatePopoverButton', opts) - .should('be.visible') - .should('have.text', end); -}); - Cypress.Commands.add('saveSearch', (name, saveAsNew = false) => { cy.log('in func save search'); const opts = { log: false }; @@ -64,20 +52,6 @@ Cypress.Commands.add('waitForSearch', () => { cy.getElementByTestId('docTable'); }); -Cypress.Commands.add('prepareTest', (fromTime, toTime, interval) => { - cy.setTopNavDate(fromTime, toTime); - cy.waitForLoader(); - // wait until the search has been finished - cy.waitForSearch(); - cy.get('select').select(`${interval}`); - cy.waitForLoader(); - cy.waitForSearch(); -}); - -Cypress.Commands.add('verifyMarkCount', (count) => { - cy.getElementByTestId('docTable').find('mark').should('have.length', count); -}); - Cypress.Commands.add( 'submitFilterFromDropDown', (field, operator, value, isEnhancement = false) => { @@ -211,36 +185,3 @@ Cypress.Commands.add('deleteSaveQuery', (name) => { cy.getElementByTestId('confirmModalConfirmButton').click(); }); - -Cypress.Commands.add('switchDiscoverTable', (name) => { - cy.getElementByTestId('discoverOptionsButton') - .then(($button) => { - cy.wrap($button).click({ force: true }); - - cy.getElementByTestId('discoverOptionsLegacySwitch').then(($switchButton) => { - if (name === 'new') { - cy.wrap($switchButton).click({ force: true }); - } - if (name === 'legacy') { - cy.wrap($switchButton).click({ force: true }); - } - cy.waitForLoader(); - }); - }) - .then(() => { - checkForElementVisibility(); - }); -}); - -function checkForElementVisibility() { - cy.getElementsByTestIds('queryInput') - .should('be.visible') - .then(($element) => { - if ($element.is(':visible')) { - return; - } else { - cy.wait(500); // Wait for half a second before checking again - checkForElementVisibility(); // Recursive call - } - }); -} diff --git a/cypress/utils/apps/data_explorer/index.d.ts b/cypress/utils/apps/data_explorer/index.d.ts index 95805f36e5a5..4246d9699ea2 100644 --- a/cypress/utils/apps/data_explorer/index.d.ts +++ b/cypress/utils/apps/data_explorer/index.d.ts @@ -5,14 +5,10 @@ declare namespace Cypress { interface Chainable { - verifyTimeConfig(start: string, end: string): Chainable; saveSearch(name: string, saveAsNew?: boolean): Chainable; loadSaveSearch(name: string): Chainable; verifyHitCount(count: string): Chainable; waitForSearch(): Chainable; - prepareTest(fromTime: string, toTime: string, interval: string): Chainable; - submitQuery(query: string): Chainable; - verifyMarkCount(count: string): Chainable; submitFilterFromDropDown( field: string, operator: string, @@ -56,6 +52,5 @@ declare namespace Cypress { loadSaveQuery(name: string): Chainable; clearSaveQuery(): Chainable; deleteSaveQuery(name: string): Chainable; - switchDiscoverTable(name: string): Chainable; } } diff --git a/cypress/utils/apps/query_enhancements/commands.js b/cypress/utils/apps/query_enhancements/commands.js index 4a28218233d5..5ce71f043f7e 100644 --- a/cypress/utils/apps/query_enhancements/commands.js +++ b/cypress/utils/apps/query_enhancements/commands.js @@ -42,103 +42,6 @@ Cypress.Commands.add('setQueryLanguage', (value) => { }); }); -/** - * Creates a new data source connection with basic auth - * It also saves the created data source's id to the alias @DATASOURCE_ID - * @param {Object} options Configuration options for the data source - * @param {string} options.name The name/title for the data source - * @param {string} options.url The endpoint URL for the data source - * @param {string} options.authType The authentication type (e.g. 'no_auth', 'basic_auth', etc.) - * @param {Object} [options.credentials] Optional credentials for auth types that require them - * @param {string} [options.credentials.username] Username for basic auth - * @param {string} [options.credentials.password] Password for basic auth - */ -Cypress.Commands.add('addDataSource', (options) => { - const { name, url, authType = 'no_auth', credentials = {} } = options; - - // Visit the create data source page - cy.visit('app/management/opensearch-dashboards/dataSources/create'); - - // Intercept the create request to verify success - cy.intercept('POST', '/api/saved_objects/data-source').as('createDataSourceRequest'); - - // Select OpenSearch card - cy.getElementByTestId('datasource_card_opensearch').click(); - - // Fill in basic info - cy.get('[name="dataSourceTitle"]').type(name); - cy.get('[name="endpoint"]').type(url); - - // Select auth type - cy.getElementByTestId('createDataSourceFormAuthTypeSelect').click(); - cy.get(`button[id="${authType}"]`).click(); - - // Handle credentials if provided and required - if (authType === 'basic_auth' && credentials.username && credentials.password) { - cy.get('[name="username"]').type(credentials.username); - cy.get('[name="password"]').type(credentials.password); - } - - // 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) => { - expect(interception.response.statusCode).to.equal(200); - // save the created data source ID as an alias - cy.wrap(interception.response.body.id).as('DATASOURCE_ID'); - }); - - // Verify redirect to data sources list page - cy.location('pathname', { timeout: 6000 }).should( - 'include', - 'app/management/opensearch-dashboards/dataSources' - ); -}); - -Cypress.Commands.add('deleteDataSourceByName', (dataSourceName) => { - // Navigate to the dataSource Management page - cy.visit('app/dataSources'); - - // Find the anchor text corresponding to specified dataSource - cy.get('a').contains(dataSourceName).click(); - - // Delete the dataSource connection - cy.getElementByTestId('editDatasourceDeleteIcon').click(); - cy.getElementByTestId('confirmModalConfirmButton').click(); -}); - -// Deletes all data sources. This command should only be used for convenience during development -// and should never be used in production -Cypress.Commands.add('deleteAllDataSources', () => { - cy.visit('app/dataSources'); - cy.waitForLoader(true); - cy.wait(2000); - - cy.get('body').then(($body) => { - const hasEmptyState = $body.find('[data-test-subj="datasourceTableEmptyState"]').length > 0; - const hasDataSources = $body.find('[data-test-subj="checkboxSelectAll"]').length > 0; - cy.log('hasEmptyState'); - cy.log(hasEmptyState); - cy.log('hasDataSources'); - cy.log(hasDataSources); - - if (hasEmptyState) { - cy.log('No data sources to delete'); - } else if (hasDataSources) { - cy.log('Need to clean out data sources'); - cy.getElementByTestId('checkboxSelectAll') - .should('exist') - .should('not.be.disabled') - .check({ force: true }); - - cy.getElementByTestId('deleteDataSourceConnections').should('be.visible').click(); - - cy.getElementByTestId('confirmModalConfirmButton').should('be.visible').click(); - } - }); -}); - Cypress.Commands.add( 'setIndexAsDataset', (index, dataSourceName, language, timeFieldName = 'timestamp', finalAction = 'submit') => { @@ -181,6 +84,19 @@ Cypress.Commands.add('setIndexPatternAsDataset', (indexPattern, dataSourceName) ); }); +Cypress.Commands.add('setDataset', (dataset, dataSourceName, type) => { + switch (type) { + case 'INDEX_PATTERN': + cy.setIndexPatternAsDataset(dataset, dataSourceName); + break; + case 'INDEXES': + cy.setIndexAsDataset(dataset, dataSourceName); + break; + default: + throw new Error(`setIndexPatternAsDataset encountered unknown type: ${type}`); + } +}); + Cypress.Commands.add( 'setIndexPatternFromAdvancedSelector', (indexPattern, dataSourceName, language, finalAction = 'submit') => { @@ -211,19 +127,6 @@ Cypress.Commands.add( } ); -Cypress.Commands.add('setDataset', (dataset, dataSourceName, type) => { - switch (type) { - case 'INDEX_PATTERN': - cy.setIndexPatternAsDataset(dataset, dataSourceName); - break; - case 'INDEXES': - cy.setIndexAsDataset(dataset, dataSourceName); - break; - default: - throw new Error(`setIndexPatternAsDataset encountered unknown type: ${type}`); - } -}); - Cypress.Commands.add('setQuickSelectTime', (direction, time, timeUnit) => { cy.getElementByTestId('superDatePickerToggleQuickMenuButton').click(); cy.get('[aria-label="Time tense"]').select(direction); diff --git a/cypress/utils/apps/query_enhancements/index.d.ts b/cypress/utils/apps/query_enhancements/index.d.ts index e8d415907c9b..d3a0e73be5f0 100644 --- a/cypress/utils/apps/query_enhancements/index.d.ts +++ b/cypress/utils/apps/query_enhancements/index.d.ts @@ -10,25 +10,34 @@ declare namespace Cypress { opts?: { parseSpecialCharSequences?: boolean }, 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; - deleteAllDataSources(): Chainable; + setIndexAsDataset( index: string, dataSourceName: string, - language?: 'OpenSearch SQL' | 'PPL' + language?: 'OpenSearch SQL' | 'PPL', + timeFieldName?: string, + finalAction?: string ): Chainable; + setIndexPatternAsDataset(indexPattern: string, dataSourceName: string): Chainable; + setDataset( dataset: string, dataSourceName: string, type: 'INDEXES' | 'INDEX_PATTERN' ): Chainable; + + setIndexPatternFromAdvancedSelector( + indexPattern: string, + datraSourceName: string, + language: string, + finalAction?: string + ): Chainable; + + setQuickSelectTime(direction: string, time: number, timeUnit: string): Chainable; + + setRelativeTopNavDate(time: number, timeUnit: string): Chainable; } } diff --git a/cypress/utils/apps/query_enhancements/shared.js b/cypress/utils/apps/query_enhancements/shared.js index c2aff51292b1..a1766e788847 100644 --- a/cypress/utils/apps/query_enhancements/shared.js +++ b/cypress/utils/apps/query_enhancements/shared.js @@ -5,7 +5,6 @@ import { DatasetTypes, - DATASOURCE_NAME, END_TIME, INDEX_PATTERN_WITH_TIME, INDEX_WITH_TIME_1, @@ -27,13 +26,6 @@ const getRandomString = () => Math.random().toString(36); 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 diff --git a/cypress/utils/apps/workspace/commands.js b/cypress/utils/apps/workspace/commands.js index fd7eeb98b1d8..8b639d6c6e6a 100644 --- a/cypress/utils/apps/workspace/commands.js +++ b/cypress/utils/apps/workspace/commands.js @@ -9,9 +9,13 @@ Cypress.Commands.add( (workspaceName) => { // Selecting the correct workspace cy.visit('/app/workspace_list#'); - cy.osd.openWorkspaceDashboard(workspaceName); + cy.openWorkspaceDashboard(workspaceName); // wait until page loads - cy.getElementByTestId('headerAppActionMenu').should('be.visible'); + if (Cypress.env('CYPRESS_RUNTIME_ENV') === 'osd') { + cy.getElementByTestId('headerAppActionMenu').should('be.visible'); + } else { + cy.getElementByTestId('breadcrumbs').should('be.visible'); + } } ); diff --git a/cypress/utils/commands.js b/cypress/utils/commands.js index 30c23d9eaf71..e3adadbe74cd 100644 --- a/cypress/utils/commands.js +++ b/cypress/utils/commands.js @@ -2,25 +2,6 @@ * Copyright OpenSearch Contributors * SPDX-License-Identifier: Apache-2.0 */ -/* - * Copyright OpenSearch Contributors - * SPDX-License-Identifier: Apache-2.0 - */ - -import { BASE_PATH } from './constants'; -import { TestFixtureHandler } from '../lib/test_fixture_handler'; -import initCommandNamespace from './command_namespace'; - -initCommandNamespace(cy, 'osd'); - -// This function does not delete all indices -Cypress.Commands.add('deleteAllIndices', () => { - cy.log('Deleting all indices'); - cy.request( - 'DELETE', - `${Cypress.env('openSearchUrl')}/index*,sample*,opensearch_dashboards*,test*,cypress*` - ); -}); // --- Typed commands -- @@ -28,14 +9,6 @@ Cypress.Commands.add('getElementByTestId', (testId, options = {}) => { return cy.get(`[data-test-subj="${testId}"]`, options); }); -/** - * Get element with a data-test-subj id containing the testId. - * @param {string} testId data-test-subj value. - * @param {object} options get options. Default: {} - * @example - * // returns all DOM elements that has a data-test-subj including the string 'table' - * cy.getElementsByTestIdLike('table') - */ Cypress.Commands.add('getElementByTestIdLike', (testId, options = {}) => { return cy.get(`[data-test-subj*="${testId}"]`, options); }); @@ -45,15 +18,6 @@ Cypress.Commands.add('getElementsByTestIds', (testIds, options = {}) => { return cy.get(selectors.join(','), options); }); -/** - * Find element from previous chained element with a data-test-subj id containing the testId. - * @param {string} subject DOM object to find within. - * @param {string} testId data-test-subj value. - * @param {object} options get options. Default: {} - * @example - * // returns all DOM elements within subject that has a data-test-subj including the string 'table' - * subject.findElementsByTestIdLike('table') - */ Cypress.Commands.add( 'findElementByTestIdLike', { prevSubject: true }, @@ -62,12 +26,6 @@ Cypress.Commands.add( } ); -/** - * Find element from previous chained element by data-test-subj id. - * @param {string} subject DOM object to find within. - * @param {string} testId data-test-subj value. - * @param {object} options get options. Default: {} - */ Cypress.Commands.add( 'findElementByTestId', { prevSubject: true }, @@ -83,251 +41,6 @@ Cypress.Commands.add('whenTestIdNotFound', (testIds, callbackFn, options = {}) = }); }); -Cypress.Commands.add('createIndex', (index, policyID = null, settings = {}) => { - cy.request('PUT', `${Cypress.env('openSearchUrl')}/${index}`, settings); - if (policyID != null) { - const body = { policy_id: policyID }; - - cy.request('POST', `${Cypress.env('openSearchUrl')}${IM_API.ADD_POLICY_BASE}/${index}`, body); - } -}); - -Cypress.Commands.add('deleteIndex', (indexName, options = {}) => { - cy.request({ - method: 'DELETE', - url: `${Cypress.env('openSearchUrl')}/${indexName}`, - failOnStatusCode: false, - ...options, - }); -}); - -Cypress.Commands.add('getIndices', (index = null, settings = {}) => { - cy.request({ - method: 'GET', - url: `${Cypress.env('openSearchUrl')}/_cat/indices/${index ? index : ''}`, - failOnStatusCode: false, - ...settings, - }); -}); - -// TODO: Impliment chunking -Cypress.Commands.add('bulkUploadDocs', (fixturePath, index) => { - const sendBulkAPIRequest = (ndjson) => { - const url = index - ? `${Cypress.env('openSearchUrl')}/${index}/_bulk` - : `${Cypress.env('openSearchUrl')}/_bulk`; - cy.log('bulkUploadDocs') - .request({ - method: 'POST', - url, - headers: { - 'content-type': 'application/json;charset=UTF-8', - 'osd-xsrf': true, - }, - body: ndjson, - }) - .then((response) => { - if (response.body.errors) { - console.error(response.body.items); - throw new Error('Bulk upload failed'); - } - }); - }; - - cy.fixture(fixturePath, 'utf8').then((ndjson) => { - sendBulkAPIRequest(ndjson); - }); - - cy.request({ - method: 'POST', - url: `${Cypress.env('openSearchUrl')}/_all/_refresh`, - }); -}); - -Cypress.Commands.add('importSavedObjects', (fixturePath, overwrite = true) => { - const sendImportRequest = (ndjson) => { - const url = `/api/saved_objects/_import?${overwrite ? `overwrite=true` : ''}`; - - const formData = new FormData(); - formData.append('file', ndjson, 'savedObject.ndjson'); - - cy.log('importSavedObject') - .request({ - method: 'POST', - url, - headers: { - 'content-type': 'multipart/form-data', - 'osd-xsrf': true, - }, - body: formData, - }) - .then((response) => { - if (response.body.errors) { - console.error(response.body.items); - throw new Error('Import failed'); - } - }); - }; - - cy.fixture(fixturePath) - .then((file) => Cypress.Blob.binaryStringToBlob(file)) - .then((ndjson) => { - sendImportRequest(ndjson); - }); -}); - -Cypress.Commands.add('deleteSavedObject', (type, id, options = {}) => { - const url = `/api/saved_objects/${type}/${id}`; - - return cy.request({ - method: 'DELETE', - url, - headers: { - 'osd-xsrf': true, - }, - failOnStatusCode: false, - ...options, - }); -}); - -Cypress.Commands.add('deleteSavedObjectByType', (type, search) => { - const searchParams = new URLSearchParams({ - fields: 'id', - type, - }); - - if (search) { - searchParams.set('search', search); - } - - const url = `/api/opensearch-dashboards/management/saved_objects/_find?${searchParams.toString()}`; - - return cy.request(url).then((response) => { - console.log('response', response); - response.body.saved_objects.map(({ type, id }) => { - cy.deleteSavedObject(type, id); - }); - }); -}); - -// TODO: we should really make this a helper function that if the data source does not exist, it creates it so take what you have for the dataset selector spec and move it here -Cypress.Commands.add('ifDataSourceExists', (search) => { - const searchParams = new URLSearchParams({ - fields: 'id', - type: 'data-source', - }); - - if (search) { - searchParams.set('search', search); - } - - const url = `/api/opensearch-dashboards/management/saved_objects/_find?${searchParams.toString()}`; - - return cy.request(url).then((response) => { - console.log('response', response); - return response.body.saved_objects.length > 0; - }); -}); - -Cypress.Commands.add('createIndexPattern', (id, attributes, header = {}) => { - const url = `/api/saved_objects/index-pattern/${id}`; - - cy.request({ - method: 'POST', - url, - headers: { - 'content-type': 'application/json;charset=UTF-8', - 'osd-xsrf': true, - ...header, - }, - body: JSON.stringify({ - attributes, - references: [], - }), - }); -}); - -Cypress.Commands.add('createDashboard', (attributes = {}, headers = {}) => { - const url = '/api/saved_objects/dashboard'; - - cy.request({ - method: 'POST', - url, - headers: { - 'content-type': 'application/json;charset=UTF-8', - 'osd-xsrf': true, - ...headers, - }, - body: JSON.stringify({ - attributes, - }), - }); -}); - -Cypress.Commands.add('changeDefaultTenant', (attributes, header = {}) => { - const url = Cypress.env('openSearchUrl') + '/_plugins/_security/api/tenancy/config'; - - cy.request({ - method: 'PUT', - url, - headers: { - 'content-type': 'application/json;charset=UTF-8', - 'osd-xsrf': true, - ...header, - }, - body: JSON.stringify(attributes), - }); -}); - -Cypress.Commands.add('deleteIndexPattern', (id, options = {}) => - cy.deleteSavedObject('index-pattern', id, options) -); - -Cypress.Commands.add('setAdvancedSetting', (changes) => { - const url = '/api/opensearch-dashboards/settings'; - cy.log('setAdvancedSetting') - .request({ - method: 'POST', - url, - qs: Cypress.env('SECURITY_ENABLED') - ? { - security_tenant: CURRENT_TENANT.defaultTenant, - } - : {}, - headers: { - 'content-type': 'application/json;charset=UTF-8', - 'osd-xsrf': true, - }, - body: { changes }, - }) - .then((response) => { - if (response.body.errors) { - console.error(response.body.items); - throw new Error('Setting advanced setting failed'); - } - }); -}); - -// type: logs, ecommerce, flights -Cypress.Commands.add('loadSampleData', (type) => { - cy.request({ - method: 'POST', - headers: { 'osd-xsrf': 'opensearch-dashboards' }, - url: `${BASE_PATH}/api/sample_data/${type}`, - }); -}); - -Cypress.Commands.add('fleshTenantSettings', () => { - if (Cypress.env('SECURITY_ENABLED')) { - // Use xhr request is good enough to flesh tenant - cy.request({ - url: `${BASE_PATH}/app/home?security_tenant=${CURRENT_TENANT.defaultTenant}`, - method: 'GET', - failOnStatusCode: false, - }); - } -}); - Cypress.Commands.add('deleteWorkspace', (workspaceName) => { cy.wait(3000); cy.getElementByTestId('workspace-detail-delete-button').should('be.visible').click(); @@ -337,35 +50,7 @@ Cypress.Commands.add('deleteWorkspace', (workspaceName) => { cy.contains(/successfully/); }); -cy.osd.add('createInitialWorkspaceWithDataSource', (dataSourceTitle, workspaceName) => { - cy.intercept('POST', '/api/workspaces').as('createWorkspaceInterception'); - cy.getElementByTestId('workspace-initial-card-createWorkspace-button') - .should('be.visible') - .click(); - cy.getElementByTestId('workspace-initial-button-create-observability-workspace') - .should('be.visible') - .click(); - cy.getElementByTestId('workspaceForm-workspaceDetails-nameInputText') - .should('be.visible') - .type(workspaceName); - cy.getElementByTestId('workspace-creator-dataSources-assign-button') - .scrollIntoView() - .should('be.visible') - .click(); - cy.get(`.euiSelectableListItem[title="${dataSourceTitle}"]`) - .should('be.visible') - .trigger('click'); - cy.getElementByTestId('workspace-detail-dataSources-associateModal-save-button').click(); - cy.getElementByTestId('workspaceForm-bottomBar-createButton').should('be.visible').click(); - - cy.wait('@createWorkspaceInterception').then((interception) => { - // save the created workspace ID as an alias - cy.wrap(interception.response.body.result.id).as('WORKSPACE_ID'); - }); - cy.contains(/successfully/); -}); - -cy.osd.add('openWorkspaceDashboard', (workspaceName) => { +Cypress.Commands.add('openWorkspaceDashboard', (workspaceName) => { cy.getElementByTestId('workspace-select-button').should('exist').click(); cy.getElementByTestId('workspace-menu-manage-button').should('exist').click(); cy.get('.euiBasicTable') @@ -376,24 +61,3 @@ cy.osd.add('openWorkspaceDashboard', (workspaceName) => { .find('a.euiLink') .click(); }); - -Cypress.Commands.add('setupTestData', (endpoint, mappingFiles, dataFiles) => { - if (!Array.isArray(mappingFiles) || !Array.isArray(dataFiles)) { - throw new Error('Both mappingFiles and dataFiles must be arrays'); - } - - if (mappingFiles.length !== dataFiles.length) { - throw new Error('The number of mapping files must match the number of data files'); - } - - const handler = new TestFixtureHandler(cy, endpoint); - - let chain = cy.wrap(null); - mappingFiles.forEach((mappingFile, index) => { - chain = chain - .then(() => handler.importMapping(mappingFile)) - .then(() => handler.importData(dataFiles[index])); - }); - - return chain; -}); diff --git a/cypress/utils/commands.osd.js b/cypress/utils/commands.osd.js new file mode 100644 index 000000000000..47149182c131 --- /dev/null +++ b/cypress/utils/commands.osd.js @@ -0,0 +1,193 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { TestFixtureHandler } from '../lib/test_fixture_handler'; +import initCommandNamespace from './command_namespace'; + +/** + * This file houses all the commands specific to OSD. For commands that are used across the project please move it to the general commands file + */ + +initCommandNamespace(cy, 'osd'); + +cy.osd.add('createInitialWorkspaceWithDataSource', (dataSourceTitle, workspaceName) => { + cy.intercept('POST', '/api/workspaces').as('createWorkspaceInterception'); + cy.getElementByTestId('workspace-initial-card-createWorkspace-button') + .should('be.visible') + .click(); + cy.getElementByTestId('workspace-initial-button-create-observability-workspace') + .should('be.visible') + .click(); + cy.getElementByTestId('workspaceForm-workspaceDetails-nameInputText') + .should('be.visible') + .type(workspaceName); + cy.getElementByTestId('workspace-creator-dataSources-assign-button') + .scrollIntoView() + .should('be.visible') + .click(); + cy.get(`.euiSelectableListItem[title="${dataSourceTitle}"]`) + .should('be.visible') + .trigger('click'); + cy.getElementByTestId('workspace-detail-dataSources-associateModal-save-button').click(); + cy.getElementByTestId('workspaceForm-bottomBar-createButton').should('be.visible').click(); + + cy.wait('@createWorkspaceInterception').then((interception) => { + // save the created workspace ID as an alias + cy.wrap(interception.response.body.result.id).as('WORKSPACE_ID'); + }); + cy.contains(/successfully/); +}); + +cy.osd.add('deleteIndex', (indexName, options = {}) => { + // This function should only run in OSD environment + if (Cypress.env('CYPRESS_RUNTIME_ENV') !== 'osd') { + return; + } + + cy.request({ + method: 'DELETE', + url: `${Cypress.env('openSearchUrl')}/${indexName}`, + failOnStatusCode: false, + ...options, + }); +}); + +cy.osd.add('setupTestData', (endpoint, mappingFiles, dataFiles) => { + // This function should only run in OSD environment + if (Cypress.env('CYPRESS_RUNTIME_ENV') !== 'osd') { + return; + } + + if (!Array.isArray(mappingFiles) || !Array.isArray(dataFiles)) { + throw new Error('Both mappingFiles and dataFiles must be arrays'); + } + + if (mappingFiles.length !== dataFiles.length) { + throw new Error('The number of mapping files must match the number of data files'); + } + + const handler = new TestFixtureHandler(cy, endpoint); + + let chain = cy.wrap(null); + mappingFiles.forEach((mappingFile, index) => { + chain = chain + .then(() => handler.importMapping(mappingFile)) + .then(() => handler.importData(dataFiles[index])); + }); + + return chain; +}); + +/** + * Creates a new data source connection with basic auth + * It also saves the created data source's id to the alias @DATASOURCE_ID + * @param {Object} options Configuration options for the data source + * @param {string} options.name The name/title for the data source + * @param {string} options.url The endpoint URL for the data source + * @param {string} options.authType The authentication type (e.g. 'no_auth', 'basic_auth', etc.) + * @param {Object} [options.credentials] Optional credentials for auth types that require them + * @param {string} [options.credentials.username] Username for basic auth + * @param {string} [options.credentials.password] Password for basic auth + */ +cy.osd.add('addDataSource', (options) => { + // This function should only run in OSD environment + if (Cypress.env('CYPRESS_RUNTIME_ENV') !== 'osd') { + return; + } + + const { name, url, authType = 'no_auth', credentials = {} } = options; + + // Visit the create data source page + cy.visit('app/management/opensearch-dashboards/dataSources/create'); + + // Intercept the create request to verify success + cy.intercept('POST', '/api/saved_objects/data-source').as('createDataSourceRequest'); + + // Select OpenSearch card + cy.getElementByTestId('datasource_card_opensearch').click(); + + // Fill in basic info + cy.get('[name="dataSourceTitle"]').type(name); + cy.get('[name="endpoint"]').type(url); + + // Select auth type + cy.getElementByTestId('createDataSourceFormAuthTypeSelect').click(); + cy.get(`button[id="${authType}"]`).click(); + + // Handle credentials if provided and required + if (authType === 'basic_auth' && credentials.username && credentials.password) { + cy.get('[name="username"]').type(credentials.username); + cy.get('[name="password"]').type(credentials.password); + } + + // 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) => { + expect(interception.response.statusCode).to.equal(200); + // save the created data source ID as an alias + cy.wrap(interception.response.body.id).as('DATASOURCE_ID'); + }); + + // Verify redirect to data sources list page + cy.location('pathname', { timeout: 6000 }).should( + 'include', + 'app/management/opensearch-dashboards/dataSources' + ); +}); + +cy.osd.add('deleteDataSourceByName', (dataSourceName) => { + // This function should only run in OSD environment + if (Cypress.env('CYPRESS_RUNTIME_ENV') !== 'osd') { + return; + } + + // Navigate to the dataSource Management page + cy.visit('app/dataSources'); + + // Find the anchor text corresponding to specified dataSource + cy.get('a').contains(dataSourceName).click(); + + // Delete the dataSource connection + cy.getElementByTestId('editDatasourceDeleteIcon').click(); + cy.getElementByTestId('confirmModalConfirmButton').click(); +}); + +// Deletes all data sources. This command should only be used for convenience during development +// and should never be used in production +cy.osd.add('deleteAllDataSources', () => { + // This function should only run in OSD environment + if (Cypress.env('CYPRESS_RUNTIME_ENV') !== 'osd') { + return; + } + + cy.visit('app/dataSources'); + cy.waitForLoader(true); + cy.wait(2000); + + cy.get('body').then(($body) => { + const hasEmptyState = $body.find('[data-test-subj="datasourceTableEmptyState"]').length > 0; + const hasDataSources = $body.find('[data-test-subj="checkboxSelectAll"]').length > 0; + cy.log('hasEmptyState'); + cy.log(hasEmptyState); + cy.log('hasDataSources'); + cy.log(hasDataSources); + + if (hasEmptyState) { + cy.log('No data sources to delete'); + } else if (hasDataSources) { + cy.log('Need to clean out data sources'); + cy.getElementByTestId('checkboxSelectAll') + .should('exist') + .should('not.be.disabled') + .check({ force: true }); + + cy.getElementByTestId('deleteDataSourceConnections').should('be.visible').click(); + + cy.getElementByTestId('confirmModalConfirmButton').should('be.visible').click(); + } + }); +}); diff --git a/cypress/utils/dashboards/remove_workspace.js b/cypress/utils/dashboards/remove_workspace.js index 416eefbe0b2f..89b7191b42dc 100644 --- a/cypress/utils/dashboards/remove_workspace.js +++ b/cypress/utils/dashboards/remove_workspace.js @@ -7,7 +7,7 @@ export function removeSampleDataAndWorkspace(url, workspaceName) { describe('removing workspace/sampledata', () => { it('remove workspace', () => { cy.visit(`${url}/app/workspace_list`); - cy.osd.openWorkspaceDashboard(workspaceName); + cy.openWorkspaceDashboard(workspaceName); cy.getElementByTestId('toggleNavButton').eq(0).should('exist').click(); cy.wait(3000); cy.getElementByTestId('collapsibleNavAppLink-workspace_detail').should('exist').click(); diff --git a/cypress/utils/dashboards/setup_workspace.js b/cypress/utils/dashboards/setup_workspace.js index 9a96766c41bf..647207b1a9f2 100644 --- a/cypress/utils/dashboards/setup_workspace.js +++ b/cypress/utils/dashboards/setup_workspace.js @@ -25,7 +25,7 @@ export function createWorkspaceAndSampleData(url, workspaceName) { describe('adding sample data to workspace', () => { it('add sample data to data source', () => { cy.visit(`${url}/app/workspace_list`); - cy.osd.openWorkspaceDashboard(workspaceName); + cy.openWorkspaceDashboard(workspaceName); cy.openSampleDataPage(); cy.addSampleDataToDataSource(dataSourceTitle); }); diff --git a/cypress/utils/helpers.js b/cypress/utils/helpers.js index 9624e8b408a6..f04a9f499f38 100644 --- a/cypress/utils/helpers.js +++ b/cypress/utils/helpers.js @@ -3,29 +3,38 @@ * SPDX-License-Identifier: Apache-2.0 */ -export const apiRequest = (url, method = 'POST', body = undefined, qs = undefined) => - cy.request({ - method: method, - failOnStatusCode: false, - url: url, - headers: { - 'content-type': 'application/json', - 'osd-xsrf': true, - }, - body: body, - qs: qs, - }); +/** + * Callback for prepareTestSuite + * @callback PrepareTestSuiteCallback + * @returns {void} + */ + +const loginMethods = [ + { + name: 'IAM Auth Session', + method: 'iamAuthLogin', + }, +]; + +/** + Sets up the test suite depending on the codebase + * @param {string} testSuiteName - name of test suite + * @param {PrepareTestSuiteCallback} runTestSuiteCallback - function that run's the test suite's tests + */ +export const prepareTestSuite = (testSuiteName, runTestSuiteCallback) => { + if (Cypress.env('CYPRESS_RUNTIME_ENV') === 'osd') { + runTestSuiteCallback(); + } else { + loginMethods.forEach(({ name, method }) => { + describe(`${testSuiteName} Test with ${name}`, () => { + beforeEach(() => { + cy.session(name, () => { + cy[method](); + }); + }); -export const devToolsRequest = (url, method = 'POST', body = undefined, qs = undefined) => - cy.request({ - method: 'POST', - form: false, - failOnStatusCode: false, - url: encodeURI(`api/console/proxy?path=${url}&method=${method}`), - headers: { - 'content-type': 'application/json;charset=UTF-8', - 'osd-xsrf': true, - }, - body: body, - qs: qs, - }); + runTestSuiteCallback(); + }); + }); + } +}; diff --git a/cypress/utils/index.d.ts b/cypress/utils/index.d.ts index f6696c8c16e2..821bd77406a9 100644 --- a/cypress/utils/index.d.ts +++ b/cypress/utils/index.d.ts @@ -6,24 +6,15 @@ declare namespace Cypress { interface Chainable { /** - * Call a function when an element with a test id cannot be found - * @example - * cy.whenTestIdNotFound(['query', 'puery'], () => {...}) - */ - whenTestIdNotFound( - testIds: string | string[], - callbackFn: void, - options?: Partial - ): Chainable; - /** - * Get elements by their test ids + * Get an element by its test id * @example - * cy.getElementsByTestIds(['query', 'puery']) + * cy.getElementByTestId('query') */ - getElementsByTestIds( - testIds: string | string[], + getElementByTestId( + testId: string, options?: Partial ): Chainable; + /** * Get an element which contains testId * @example @@ -33,13 +24,14 @@ declare namespace Cypress { testId: string, options?: Partial ): Chainable; + /** - * Get an element by its test id + * Get elements by their test ids * @example - * cy.getElementByTestId('query') + * cy.getElementsByTestIds(['query', 'puery']) */ - getElementByTestId( - testId: string, + getElementsByTestIds( + testIds: string | string[], options?: Partial ): Chainable; @@ -69,127 +61,27 @@ declare namespace Cypress { ): Chainable; /** - * Create an index - * @example - * cy.createIndex('indexID') - * cy.createIndex('indexID', 'policy') - */ - createIndex(index: string, policyID?: string, settings?: any): Chainable; - - /** - * Delete an index - * @example - * cy.deleteIndex('indexID') - */ - deleteIndex(index: string): Chainable; - - /** - * Bulk upload NDJSON fixture data - * @example - * cy.bulkUploadDocs('plugins/test/test_data.txt') - */ - bulkUploadDocs( - fixturePath: string, - index: string - // options?: Partial - ): Chainable; - - /** - * Import saved objects - * @example - * cy.importSavedObject('plugins/test/exported_data.ndjson') - */ - importSavedObjects(fixturePath: string, overwrite?: boolean): Chainable; - - /** - * Delete a saved object - * @example - * cy.deleteSavedObject('index-pattern', 'id') - */ - deleteSavedObject(type: string, id: string): Chainable; - - /** - * Test if data source exists - * @example - * cy.ifDataSourceExists('data-source') - */ - ifDataSourceExists(search: string): Chainable; - - /** - * Delete all saved objects of a particular type - * Optionally, narrow down the results using search - * @example - * cy.deleteSavedObjectByType('index-pattern') - * cy.deleteSavedObjectByType('index-pattern', 'search string') - */ - deleteSavedObjectByType(type: string, search?: string): Chainable; - - /** - * Adds an index pattern - * @example - * cy.createIndexPattern('patterId', { title: 'patt*', timeFieldName: 'timestamp' }) - */ - createIndexPattern( - id: string, - attributes: { - title: string; - timeFieldName?: string; - [key: string]: any; - }, - header: string - ): Chainable; - - /** - * Adds a dashboard - * @example - * cy.createDashboard({ title: 'My dashboard'}) - */ - createDashboard( - attributes: { - title: string; - [key: string]: any; - }, - headers?: { - [key: string]: any; - } - ): Chainable; - - /** - * Changes the Default tenant for the domain. + * Call a function when an element with a test id cannot be found * @example - * cy.changeDefaultTenant({multitenancy_enabled: true, private_tenant_enabled: true, default_tenant: tenantName, }); + * cy.whenTestIdNotFound(['query', 'puery'], () => {...}) */ - changeDefaultTenant( - attributes: { - multitenancy_enabled: boolean; - private_tenant_enabled: boolean; - default_tenant: string; - } - // header: string, - // default_tenant: string + whenTestIdNotFound( + testIds: string | string[], + callbackFn: void, + options?: Partial ): Chainable; /** - * Delete an index pattern + * Deletes a workspace * @example - * cy.createIndexPattern('patterId') + * cy.deleteWorkspace('workspace-name'); */ - deleteIndexPattern(id: string): Chainable; + deleteWorkspace(workspaceName: string): Chainable; /** - * Set advanced setting values - * tip: setting the value to null set's it to its default value - * @example - * cy.setAdvancedSetting({ 'visualize:enableLabs' : true }) + * Opens workspace dashboard */ - setAdvancedSetting(changes: { [key: string]: any }): Chainable; - - /** - * Performs drag and drop action - * @example - * cy.get('sourceSelector').drag('targetSelector') - */ - drag(targetSelector: string): Chainable; + openWorkspaceDashboard(workspaceName: string): Chainable; // osd namespace osd: { @@ -203,9 +95,31 @@ declare namespace Cypress { ): Chainable; /** - * Opens workspace dashboard + * Delete an index + * @example + * cy.deleteIndex('indexID') + */ + deleteIndex(index: string): Chainable; + + /** + * Sets up test data */ - openWorkspaceDashboard(workspaceName: string): Chainable; + setupTestData( + endpoint: string, + mappingFiles: string[], + dataFiles: string[] + ): Chainable; + + addDataSource(opts: { + name: string; + url: string; + auth_type?: string; + credentials?: { username: string; password: string }; + }): Chainable; + + deleteDataSourceByName(dataSourceName: string): Chainable; + + deleteAllDataSources(): Chainable; }; } } diff --git a/docs/_sidebar.md b/docs/_sidebar.md index 8fc7e380e6b6..27442c2e608b 100644 --- a/docs/_sidebar.md +++ b/docs/_sidebar.md @@ -171,6 +171,7 @@ - [Opensearch dashboards.release notes 2.17.0](../release-notes/opensearch-dashboards.release-notes-2.17.0.md) - [Opensearch dashboards.release notes 2.17.1](../release-notes/opensearch-dashboards.release-notes-2.17.1.md) - [Opensearch dashboards.release notes 2.18.0](../release-notes/opensearch-dashboards.release-notes-2.18.0.md) + - [Opensearch dashboards.release notes 2.19.0](../release-notes/opensearch-dashboards.release-notes-2.19.0.md) - [Opensearch dashboards.release notes 2.2.0](../release-notes/opensearch-dashboards.release-notes-2.2.0.md) - [Opensearch dashboards.release notes 2.2.1](../release-notes/opensearch-dashboards.release-notes-2.2.1.md) - [Opensearch dashboards.release notes 2.3.0](../release-notes/opensearch-dashboards.release-notes-2.3.0.md)