diff --git a/changelogs/fragments/9285.yml b/changelogs/fragments/9285.yml new file mode 100644 index 000000000000..ab3f15e23d0c --- /dev/null +++ b/changelogs/fragments/9285.yml @@ -0,0 +1,2 @@ +test: +- [Cypress][TESTID-147] Add tests for table canvas in discover ([#9285](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/9285)) \ No newline at end of file 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 0531145feec7..ebb8bbb2d676 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 @@ -4,6 +4,7 @@ */ import { + DatasetTypes, INDEX_WITH_TIME_1, INDEX_PATTERN_WITH_TIME_1, SECONDARY_ENGINE, @@ -88,7 +89,7 @@ export const runSharedLinksTests = () => { }).forEach((config) => { describe(`${config.testName}`, () => { beforeEach(() => { - if (config.datasetType === 'INDEX_PATTERN') { + if (config.datasetType === DatasetTypes.INDEX_PATTERN.name) { cy.createWorkspaceIndexPatterns({ workspaceName: workspaceName, indexPattern: INDEX_WITH_TIME_1, 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 49cc38d73e41..7a2e2f05122f 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 @@ -4,6 +4,7 @@ */ import { + DatasetTypes, INDEX_WITH_TIME_1, INDEX_PATTERN_WITH_TIME_1, SECONDARY_ENGINE, @@ -173,7 +174,7 @@ export const runSideBarTests = () => { }).forEach((config) => { describe(`${config.testName}`, () => { beforeEach(() => { - if (config.datasetType === 'INDEX_PATTERN') { + if (config.datasetType === DatasetTypes.INDEX_PATTERN.name) { cy.createWorkspaceIndexPatterns({ workspaceName: workspaceName, indexPattern: INDEX_WITH_TIME_1, @@ -199,7 +200,7 @@ export const runSideBarTests = () => { testData.simpleFields.expectedValues, testData.pplQuery(config.dataset), testData.sqlQuery(config.dataset), - config.datasetType === 'INDEX_PATTERN', + cconfig.datasetType === DatasetTypes.INDEX_PATTERN.name, config ); }); @@ -210,7 +211,7 @@ export const runSideBarTests = () => { testData.nestedFields.expectedValues, testData.pplQuery(config.dataset), testData.sqlQuery(config.dataset), - config.datasetType === 'INDEX_PATTERN', + config.datasetType === DatasetTypes.INDEX_PATTERN.name, config ); }); 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 new file mode 100644 index 000000000000..64cd43dfb120 --- /dev/null +++ b/cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements/table.spec.js @@ -0,0 +1,196 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + DatasetTypes, + INDEX_WITH_TIME_1, + INDEX_WITHOUT_TIME_1, + INDEX_PATTERN_WITH_TIME_1, + INDEX_PATTERN_WITH_NO_TIME_1, + SECONDARY_ENGINE, +} 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'; + +const workspaceName = getRandomizedWorkspaceName(); +const datasourceName = getRandomizedDatasourceName(); + +const generateTableTestConfiguration = (dataset, datasetType, language) => { + const baseConfig = { + dataset, + datasetType, + language: language.name, + testName: `${language.name}-${datasetType}`, + }; + + return { + ...baseConfig, + }; +}; + +export const runTableTests = () => { + describe('discover table tests', () => { + beforeEach(() => { + cy.setupTestData( + SECONDARY_ENGINE.url, + [ + `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`, + ], + [ + `cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITH_TIME_1}.data.ndjson`, + `cypress/fixtures/query_enhancements/data_logs_1/${INDEX_WITHOUT_TIME_1}.data.ndjson`, + ] + ); + cy.addDataSource({ + name: datasourceName, + url: SECONDARY_ENGINE.url, + authType: 'no_auth', + }); + cy.deleteWorkspaceByName(workspaceName); + cy.visit('/app/home'); + cy.osd.createInitialWorkspaceWithDataSource(datasourceName, workspaceName); + }); + + afterEach(() => { + cy.deleteWorkspaceByName(workspaceName); + cy.deleteDataSourceByName(datasourceName); + cy.window().then((win) => { + win.localStorage.clear(); + win.sessionStorage.clear(); + }); + }); + + generateAllTestConfigurations(generateTableTestConfiguration, { + indexPattern: INDEX_PATTERN_WITH_TIME_1, + index: INDEX_WITH_TIME_1, + }).forEach((config) => { + describe(`${config.testName}`, () => { + beforeEach(() => { + if (config.datasetType === DatasetTypes.INDEX_PATTERN.name) { + cy.createWorkspaceIndexPatterns({ + workspaceName: workspaceName, + indexPattern: INDEX_WITH_TIME_1, + timefieldName: 'timestamp', + dataSource: datasourceName, + isEnhancement: true, + }); + } + cy.navigateToWorkSpaceSpecificPage({ + workspaceName: workspaceName, + page: 'discover', + isEnhancement: true, + }); + }); + afterEach(() => { + cy.deleteIndex(INDEX_WITH_TIME_1); + }); + + it(`should allow expand multiple documents for ${config.testName}`, () => { + // Setup + cy.setDataset(config.dataset, datasourceName, config.datasetType); + cy.setQueryLanguage(config.language); + setDatePickerDatesAndSearchIfRelevant(config.language); + // expanding a document in the table + cy.get('[data-test-subj="docTableExpandToggleColumn"]') + .find('[type="button"]') + .eq(2) + .click(); + + // expanding a document in the table + cy.get('[data-test-subj="docTableExpandToggleColumn"]') + .find('[type="button"]') + .eq(3) + .click(); + + // checking the number of exapnded documents visible on screen + cy.get('[data-test-subj="tableDocViewRow-_index"]').should('have.length', 2); + + // switch query should keep expanded state + // TODO: allow switch to other languages + if (config.language === QueryLanguages.DQL.name) { + cy.setQueryLanguage('Lucene'); + } else if (config.language === QueryLanguages.Lucene.name) { + cy.setQueryLanguage('DQL'); + } else if (config.language === QueryLanguages.SQL.name) { + cy.setQueryLanguage('PPL'); + } else { + cy.setQueryLanguage('OpenSearch SQL'); + } + cy.get('[data-test-subj="tableDocViewRow-_index"]').should('have.length', 2); + }); + }); + }); + + generateIndexPatternTestConfigurations(generateTableTestConfiguration, { + indexPattern: INDEX_PATTERN_WITH_NO_TIME_1, + supportedLanguages: [QueryLanguages.DQL, QueryLanguages.Lucene], + }).forEach((config) => { + describe(`${config.testName}`, () => { + beforeEach(() => { + if (config.datasetType === DatasetTypes.INDEX_PATTERN.name) { + cy.createWorkspaceIndexPatterns({ + workspaceName: workspaceName, + indexPattern: INDEX_WITHOUT_TIME_1, + timefieldName: '', + indexPatternHasTimefield: false, + dataSource: datasourceName, + isEnhancement: true, + }); + } + cy.navigateToWorkSpaceSpecificPage({ + workspaceName: workspaceName, + page: 'discover', + isEnhancement: true, + }); + }); + afterEach(() => { + cy.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.setQueryLanguage(config.language); + // Add fields + testFields.forEach((field) => { + selectFieldFromSidebar(field); + // Default is no sort + cy.getElementByTestId(`docTableHeaderFieldSort_${field}`).should( + 'have.attr', + 'aria-label', + `Sort ${field} ascending` + ); + }); + // Sort asc + cy.getElementByTestId(`docTableHeaderFieldSort_${testFields[0]}`).should('exist').click(); + cy.getElementByTestId('osdDocTableCellDataField') + .eq(0) + .should('have.text', 'Application'); + // Sort desc + cy.getElementByTestId(`docTableHeaderFieldSort_${testFields[0]}`).should('exist').click(); + cy.getElementByTestId('osdDocTableCellDataField').eq(0).should('have.text', 'Security'); + // Sort asc on the 2nd col + cy.getElementByTestId(`docTableHeaderFieldSort_${testFields[1]}`).should('exist').click(); + cy.getElementByTestId('osdDocTableCellDataField').eq(1).should('have.text', '0.1'); + // Sort desc on the 2nd col + cy.getElementByTestId(`docTableHeaderFieldSort_${testFields[1]}`).should('exist').click(); + cy.getElementByTestId('osdDocTableCellDataField').eq(1).should('have.text', '5'); + }); + }); + }); + }); +}; + +runTableTests(); diff --git a/cypress/utils/apps/query_enhancements/constants.js b/cypress/utils/apps/query_enhancements/constants.js index 8cefd76e355b..7fc00cdecb99 100644 --- a/cypress/utils/apps/query_enhancements/constants.js +++ b/cypress/utils/apps/query_enhancements/constants.js @@ -27,6 +27,7 @@ export const INDEX_WITH_TIME_2 = 'data_logs_small_time_2'; export const INDEX_PATTERN_WITH_TIME = 'data_logs_small_time_*'; export const INDEX_PATTERN_WITH_NO_TIME = 'data_logs_small_no_time_*'; export const INDEX_PATTERN_WITH_TIME_1 = 'data_logs_small_time_1*'; +export const INDEX_PATTERN_WITH_NO_TIME_1 = 'data_logs_small_no_time_1*'; /** * The dataset type in discover diff --git a/cypress/utils/apps/query_enhancements/shared.js b/cypress/utils/apps/query_enhancements/shared.js index 73bd9e0032b9..3cbc1dd52937 100644 --- a/cypress/utils/apps/query_enhancements/shared.js +++ b/cypress/utils/apps/query_enhancements/shared.js @@ -73,6 +73,32 @@ export const generateAllTestConfigurations = (generateTestConfigurationCallback, ); }; +/** + * Returns an array of test configurations for every query language + index pattern permutation + * @param {GenerateTestConfigurationCallback} generateTestConfigurationCallback - cb function that generates a test case for the particular permutation + * @param {Object} [options] - Optional configuration options + * @param {string} [options.indexPattern] - Custom index pattern name (defaults to INDEX_PATTERN_WITH_TIME) + * @param {string} [options.supportedLanguages] - Custom supported languages (defaults to all four supported languages) + * @returns {object[]} + */ +export const generateIndexPatternTestConfigurations = ( + generateTestConfigurationCallback, + options = {} +) => { + const { + indexPattern = INDEX_PATTERN_WITH_TIME, + supportedLanguages = DatasetTypes.INDEX_PATTERN.supportedLanguages, + } = options; + const indexPatternDatasets = Object.values(DatasetTypes).filter( + (dataset) => dataset.name === DatasetTypes.INDEX_PATTERN.name + ); + return indexPatternDatasets.flatMap((dataset) => + supportedLanguages.map((language) => { + return generateTestConfigurationCallback(indexPattern, dataset.name, language); + }) + ); +}; + /** * Sets the top nav date if it is relevant for the passed language * @param {QueryEnhancementLanguage} language - query language diff --git a/package.json b/package.json index 851c88a4a27d..ca8da299fffd 100644 --- a/package.json +++ b/package.json @@ -86,7 +86,7 @@ "release_note:generate": "scripts/use_node scripts/generate_release_note", "cypress:run-without-security": "env TZ=America/Los_Angeles NO_COLOR=1 cypress run --env SECURITY_ENABLED=false", "cypress:run-with-security": "env TZ=America/Los_Angeles NO_COLOR=1 cypress run --env SECURITY_ENABLED=true,openSearchUrl=https://localhost:9200,WAIT_FOR_LOADER_BUFFER_MS=500", - "osd:ciGroup10": "BASE_PATH='cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements' && echo \"$BASE_PATH/saved_search.spec.js,$BASE_PATH/queries.spec.js,$BASE_PATH/a_check.spec.js,$BASE_PATH/dataset_selector.spec.js,$BASE_PATH/s3_dataset.spec.js,$BASE_PATH/simple_dataset_selector.spec.js,$BASE_PATH/sidebar.spec.js,$BASE_PATH/shared_links.spec.js\"", + "osd:ciGroup10": "BASE_PATH='cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements' && echo \"$BASE_PATH/saved_search.spec.js,$BASE_PATH/queries.spec.js,$BASE_PATH/a_check.spec.js,$BASE_PATH/dataset_selector.spec.js,$BASE_PATH/s3_dataset.spec.js,$BASE_PATH/simple_dataset_selector.spec.js,$BASE_PATH/sidebar.spec.js,$BASE_PATH/shared_links.spec.js,$BASE_PATH/table.spec.js\"", "osd:ciGroup11": "echo \"cypress/integration/dashboard_sanity_test.spec.ts\"", "osd:ciGroup12": "BASE_PATH='cypress/integration/core_opensearch_dashboards/opensearch_dashboards/apps/query_enhancements' && echo \"$BASE_PATH/time_range_selection.spec.js,$BASE_PATH/saved_queries.spec.js,$BASE_PATH/language_specific_display.spec.js,$BASE_PATH/field_display_filtering.spec.js\"", "generate:opensearchsqlantlr": "./node_modules/antlr4ng-cli/index.js -Dlanguage=TypeScript -o ./src/plugins/data/public/antlr/opensearch_sql/.generated -visitor -no-listener -Xexact-output-dir ./src/plugins/data/public/antlr/opensearch_sql/grammar/OpenSearchSQLLexer.g4 ./src/plugins/data/public/antlr/opensearch_sql/grammar/OpenSearchSQLParser.g4",