From 15af715628b17f6056b28517ce1bfae6ceea8e5b Mon Sep 17 00:00:00 2001 From: Argus Li <43020525+ArgusLi@users.noreply.github.com> Date: Sun, 5 Jan 2025 15:01:08 -0800 Subject: [PATCH] [Discover 2.0 Testing] Create Filtering Test (TestId-69: Filtering) (#9119) * Add test for filtering functionality for discover, which enables query enhancement * Make test more robust: Add logic to use date picker start and end buttons if set to absolute times. Check the table length directly instead of number of hits to avoid bug where not all results load. --------- Signed-off-by: Argus Li Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com> --- .../field_display_filtering.spec.js | 250 ++++++++++++++++++ .../utils/field_display_filtering.js | 188 +++++++++++++ .../apps/query_enhancements/constants.js | 26 ++ cypress/utils/commands.js | 12 - .../dashboards/data_explorer/elements.js | 41 +++ cypress/utils/index.d.ts | 25 ++ 6 files changed, 530 insertions(+), 12 deletions(-) create mode 100644 cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/field_display_filtering.spec.js create mode 100644 cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/utils/field_display_filtering.js create mode 100644 cypress/utils/dashboards/data_explorer/elements.js 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 new file mode 100644 index 000000000000..1069f2077db0 --- /dev/null +++ b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/field_display_filtering.spec.js @@ -0,0 +1,250 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +import { + WORKSPACE_NAME, + DATASOURCE_NAME, + INDEX_NAME, + INDEX_PATTERN_NAME, + START_TIME, + END_TIME, + DATASET_CONFIGS, +} from '../../../../../utils/apps/constants'; +import * as dataExplorer from '../../../../../integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/utils/field_display_filtering.js'; +import { SECONDARY_ENGINE, BASE_PATH } from '../../../../../utils/constants'; +import { NEW_SEARCH_BUTTON } from '../../../../../utils/dashboards/data_explorer/elements.js'; + +const randomString = Math.random().toString(36).substring(7); +const workspace = `${WORKSPACE_NAME}-${randomString}`; + +const selectDataset = (datasetType, language) => { + switch (datasetType) { + case 'index': + dataExplorer.selectIndexDataset(DATASOURCE_NAME, INDEX_NAME, language); + break; + case 'index_pattern': + dataExplorer.selectIndexPatternDataset(INDEX_PATTERN_NAME, language); + break; + } +}; +const setDateRange = (datasetType, language) => { + if (language === 'OpenSearch SQL') { + return; + } else { + cy.setTopNavDate(START_TIME, END_TIME); + } +}; +const verifyTableFieldFilterActions = (datasetType, language, shouldExist) => { + selectDataset(datasetType, language); + setDateRange(datasetType, language); + + cy.getElementByTestId('docTable').get('tbody tr').should('have.length.above', 3); // To ensure it waits until a full table is loaded into the DOM, instead of a bug where table only has 1 hit. + + const shouldText = shouldExist ? 'exist' : 'not.exist'; + dataExplorer.getDocTableField(0, 0).within(() => { + cy.getElementByTestId('filterForValue').should(shouldText); + cy.getElementByTestId('filterOutValue').should(shouldText); + }); + + if (shouldExist) { + dataExplorer.verifyDocTableFilterAction(0, 'filterForValue', '10,000', '1', true); + dataExplorer.verifyDocTableFilterAction(0, 'filterOutValue', '10,000', '9,999', false); + } +}; +const verifyExpandedTableFilterActions = (datasetType, language, isFilterButtonsEnabled) => { + // Check if the first expanded Doc Table Field's first row's Filter For, Filter Out and Exists Filter buttons are disabled. + const verifyFirstExpandedFieldFilterForFilterOutFilterExistsButtons = () => { + const shouldText = isFilterButtonsEnabled ? 'be.enabled' : 'be.disabled'; + dataExplorer.getExpandedDocTableRow(0, 0).within(() => { + cy.getElementByTestId('addInclusiveFilterButton').should(shouldText); + cy.getElementByTestId('removeInclusiveFilterButton').should(shouldText); + cy.getElementByTestId('addExistsFilterButton').should(shouldText); + }); + }; + + /** + * Check the Filter For or Out buttons in the expandedDocumentRowNumberth field in the expanded Document filters the correct value. + * @param {string} filterButton For or Out + * @param {number} docTableRowNumber Integer starts from 0 for the first row + * @param {number} expandedDocumentRowNumber Integer starts from 0 for the first row + * @param {string} expectedQueryHitsWithoutFilter expected number of hits in string after the filter is removed Note you should add commas when necessary e.g. 9,999 + * @param {string} expectedQueryHitsAfterFilterApplied expected number of hits in string after the filter is applied. Note you should add commas when necessary e.g. 9,999 + * @example verifyDocTableFirstExpandedFieldFirstRowFilterForButtonFiltersCorrectField('for', 0, 0, '10,000', '1'); + */ + const verifyDocTableFirstExpandedFieldFirstRowFilterForOutButtonFiltersCorrectField = ( + filterButton, + docTableRowNumber, + expandedDocumentRowNumber, + expectedQueryHitsWithoutFilter, + expectedQueryHitsAfterFilterApplied + ) => { + if (filterButton !== 'for' || filterButton !== 'out') { + cy.log('Filter button must be for or or.'); + return; + } + + const filterButtonElement = + filterButton === 'for' ? 'addInclusiveFilterButton' : 'removeInclusiveFilterButton'; + const shouldText = filterButton === 'for' ? 'have.text' : 'not.have.text'; + + dataExplorer + .getExpandedDocTableRowValue(docTableRowNumber, expandedDocumentRowNumber) + .then(($expandedDocumentRowValue) => { + const filterFieldText = $expandedDocumentRowValue.text(); + dataExplorer + .getExpandedDocTableRow(docTableRowNumber, expandedDocumentRowNumber) + .within(() => { + cy.getElementByTestId(filterButtonElement).click(); + }); + // Verify pill text + cy.getElementByTestId('globalFilterLabelValue').should('have.text', filterFieldText); + cy.getElementByTestId('discoverQueryHits').should( + 'have.text', + expectedQueryHitsAfterFilterApplied + ); // checkQueryHitText must be in front of checking first line text to give time for DocTable to update. + dataExplorer + .getExpandedDocTableRowValue(docTableRowNumber, expandedDocumentRowNumber) + .should(shouldText, filterFieldText); + }); + cy.getElementByTestId('globalFilterBar').find('[aria-label="Delete"]').click(); + cy.getElementByTestId('discoverQueryHits').should('have.text', expectedQueryHitsWithoutFilter); + }; + + /** + * Check the first expanded Doc Table Field's first row's Exists Filter button filters the correct Field. + * @param {number} docTableRowNumber Integer starts from 0 for the first row + * @param {number} expandedDocumentRowNumber Integer starts from 0 for the first row + * @param {string} expectedQueryHitsWithoutFilter expected number of hits in string after the filter is removed Note you should add commas when necessary e.g. 9,999 + * @param {string} expectedQueryHitsAfterFilterApplied expected number of hits in string after the filter is applied. Note you should add commas when necessary e.g. 9,999 + */ + const verifyDocTableFirstExpandedFieldFirstRowExistsFilterButtonFiltersCorrectField = ( + docTableRowNumber, + expandedDocumentRowNumber, + expectedQueryHitsWithoutFilter, + expectedQueryHitsAfterFilterApplied + ) => { + dataExplorer + .getExpandedDocTableRowFieldName(docTableRowNumber, expandedDocumentRowNumber) + .then(($expandedDocumentRowField) => { + const filterFieldText = $expandedDocumentRowField.text(); + dataExplorer + .getExpandedDocTableRow(docTableRowNumber, expandedDocumentRowNumber) + .within(() => { + cy.getElementByTestId('addExistsFilterButton').click(); + }); + // Verify full pill text + // globalFilterLabelValue gives the inner element, but we may want all the text in the filter pill + cy.getElementByTestId('globalFilterLabelValue', { + timeout: 10000, + }) + .parent() + .should('have.text', filterFieldText + ': ' + 'exists'); + cy.getElementByTestId('discoverQueryHits').should( + 'have.text', + expectedQueryHitsAfterFilterApplied + ); + }); + cy.getElementByTestId('globalFilterBar').find('[aria-label="Delete"]').click(); + cy.getElementByTestId('discoverQueryHits').should('have.text', expectedQueryHitsWithoutFilter); + }; + + selectDataset(datasetType, language); + setDateRange(datasetType, language); + + cy.getElementByTestId('docTable').get('tbody tr').should('have.length.above', 3); // To ensure it waits until a full table is loaded into the DOM, instead of a bug where table only has 1 hit. + dataExplorer.toggleDocTableRow(0); + verifyFirstExpandedFieldFilterForFilterOutFilterExistsButtons(); + dataExplorer.verifyDocTableFirstExpandedFieldFirstRowToggleColumnButtonHasIntendedBehavior(); + + if (isFilterButtonsEnabled) { + verifyDocTableFirstExpandedFieldFirstRowFilterForOutButtonFiltersCorrectField( + 'for', + 0, + 0, + '10,000', + '1' + ); + verifyDocTableFirstExpandedFieldFirstRowFilterForOutButtonFiltersCorrectField( + 'out', + 0, + 0, + '10,000', + '9,999' + ); + verifyDocTableFirstExpandedFieldFirstRowExistsFilterButtonFiltersCorrectField( + 0, + 0, + '10,000', + '10,000' + ); + } +}; +describe('filter for value spec', () => { + before(() => { + // 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 + cy.deleteWorkspaceByName(`${workspace}`); + cy.visit('/app/home'); + cy.createInitialWorkspaceWithDataSource(`${DATASOURCE_NAME}`, `${workspace}`); + cy.wait(2000); + cy.createWorkspaceIndexPatterns({ + url: `${BASE_PATH}`, + workspaceName: `${workspace}`, + indexPattern: INDEX_NAME, + timefieldName: 'timestamp', + indexPatternHasTimefield: true, + dataSource: DATASOURCE_NAME, + isEnhancement: true, + }); + }); + + beforeEach(() => { + cy.navigateToWorkSpaceSpecificPage({ + url: BASE_PATH, + workspaceName: `${workspace}`, + page: 'discover', + isEnhancement: true, + }); + cy.getElementByTestId(NEW_SEARCH_BUTTON).click(); + }); + + after(() => { + cy.deleteWorkspaceByName(`${WORKSPACE_NAME}`); + cy.deleteDataSourceByName(`${DATASOURCE_NAME}`); + // TODO: Modify deleteIndex to handle an array of index and remove hard code + cy.deleteIndex(INDEX_PATTERN_NAME); + }); + + const testCases = [ + { name: 'table field', verifyFn: verifyTableFieldFilterActions }, + { name: 'expanded table', verifyFn: verifyExpandedTableFilterActions }, + ]; + + testCases.forEach(({ name, verifyFn }) => { + describe(`filter actions in ${name}`, () => { + Object.entries(DATASET_CONFIGS).forEach(([type, config]) => { + describe(`${type} dataset`, () => { + config.languages.forEach(({ name: language, isFilterButtonsEnabled }) => { + it(`${language}`, () => { + verifyFn(type, language, isFilterButtonsEnabled); + }); + }); + }); + }); + }); + }); +}); diff --git a/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/utils/field_display_filtering.js b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/utils/field_display_filtering.js new file mode 100644 index 000000000000..910250f6338f --- /dev/null +++ b/cypress/integration/core-opensearch-dashboards/opensearch-dashboards/apps/query_enhancements/utils/field_display_filtering.js @@ -0,0 +1,188 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +/** + * Get specific row of DocTable. + * @param {number} rowNumber Integer starts from 0 for the first row + */ +export function getDocTableRow(rowNumber) { + return cy.getElementByTestId('docTable').get('tbody tr').eq(rowNumber); +} + +/** + * Get specific field of DocTable. + * @param {number} columnNumber Integer starts from 0 for the first column + * @param {number} rowNumber Integer starts from 0 for the first row + */ +export function getDocTableField(columnNumber, rowNumber) { + return getDocTableRow(rowNumber).findElementByTestId('docTableField').eq(columnNumber); +} + +/** + * find all Rows in Doc Table Field Expanded Document. + * @param expandedDocument cypress representation of the Doc Table Field Expanded Document + */ +export function findExpandedDocTableRows(expandedDocument) { + return expandedDocument.findElementByTestIdLike('tableDocViewRow-'); +} + +/** + * Get the "expandedDocumentRowNumber"th row from the expanded document from the "docTableRowNumber"th row of the DocTable. + * @param {number} docTableRowNumber Integer starts from 0 for the first row + * @param {number} expandedDocumentRowNumber Integer starts from 0 for the first row + * @example + * // returns the first row from the expanded document from the second row of the DocTable. + * getExpandedDocTableRow(1, 0); + */ +export function getExpandedDocTableRow(docTableRowNumber, expandedDocumentRowNumber) { + return findExpandedDocTableRows(getDocTableRow(docTableRowNumber + 1)).eq( + expandedDocumentRowNumber + ); +} + +/** + * Get the value for the "expandedDocumentRowNumber"th row from the expanded document from the "docTableRowNumber"th row of the DocTable. + * @param {number} docTableRowNumber Integer starts from 0 for the first row + * @param {number} expandedDocumentRowNumber Integer starts from 0 for the first row + * @example + * // returns the value of the field from the first row from the expanded document from the second row of the DocTable. + * getExpandedDocTableRowValue(1, 0); + */ +export function getExpandedDocTableRowValue(docTableRowNumber, expandedDocumentRowNumber) { + return getExpandedDocTableRow(docTableRowNumber, expandedDocumentRowNumber) + .find(`[data-test-subj*="tableDocViewRow-"]`) + .find('span'); +} + +/** + * Get the field name for the "expandedDocumentRowNumber"th row from the expanded document from the "docTableRowNumber"th row of the DocTable. + * @param {number} docTableRowNumber Integer starts from 0 for the first row + * @param {number} expandedDocumentRowNumber Integer starts from 0 for the first row + * @example + * // returns the name of the field from the first row from the expanded document from the second row of the DocTable. + * getExpandedDocTableRowFieldName(1, 0); + */ +export function getExpandedDocTableRowFieldName(docTableRowNumber, expandedDocumentRowNumber) { + return getExpandedDocTableRow(docTableRowNumber, expandedDocumentRowNumber) + .find('td') + .eq(1) // Field name is in the second column. + .find('span[class*="textTruncate"]'); +} + +/** + * Select a language in the Dataset Selector for Index + * @param {string} datasetLanguage Index supports "OpenSearch SQL" and "PPL" + */ +export function selectIndexDatasetLanguage(datasetLanguage) { + cy.getElementByTestId('advancedSelectorLanguageSelect').select(datasetLanguage); + cy.getElementByTestId('advancedSelectorTimeFieldSelect').select('timestamp'); + cy.getElementByTestId('advancedSelectorConfirmButton').click(); +} + +/** + * Select an index dataset. + * @param {string} indexClusterName Name of the cluster to be used for the Index. + * @param {string} indexName Name of the index dataset to be used. + * @param {string} datasetLanguage Index supports "OpenSearch SQL" and "PPL". + */ +export function selectIndexDataset(indexClusterName, indexName, datasetLanguage) { + cy.getElementByTestId('datasetSelectorButton').click(); + cy.getElementByTestId('datasetSelectorAdvancedButton').click(); + cy.getElementByTestId('datasetExplorerWindow').contains('Indexes').click(); + cy.getElementByTestId('datasetExplorerWindow').contains(indexClusterName).click(); + cy.getElementByTestId('datasetExplorerWindow').contains(indexName).click(); + cy.getElementByTestId('datasetSelectorNext').click(); + selectIndexDatasetLanguage(datasetLanguage); +} + +/** + * Select a language in the Dataset Selector for Index Pattern + * @param {string} datasetLanguage Index Pattern supports "DQL", "Lucene", "OpenSearch SQL" and "PPL" + */ +export function selectIndexPatternDatasetLanguage(datasetLanguage) { + cy.getElementByTestId('advancedSelectorLanguageSelect').select(datasetLanguage); + cy.getElementByTestId('advancedSelectorConfirmButton').click(); +} + +/** + * Select an index pattern dataset. + * @param {string} indexPatternName Name of the index pattern to be used. + * @param {string} datasetLanguage Index Pattern supports "DQL", "Lucene", "OpenSearch SQL" and "PPL" + */ +export function selectIndexPatternDataset(indexPatternName, datasetLanguage) { + cy.getElementByTestId('datasetSelectorButton').click(); + cy.getElementByTestId('datasetSelectorAdvancedButton').click(); + cy.getElementByTestId('datasetExplorerWindow').contains('Index Patterns').click(); + cy.getElementByTestId('datasetExplorerWindow').contains(indexPatternName).click(); + cy.getElementByTestId('datasetSelectorNext').click(); + selectIndexPatternDatasetLanguage(datasetLanguage); +} + +/** + * Toggle expansion of row rowNumber of Doc Table. + * @param {number} rowNumber rowNumber of Doc Table starts at 0 for row 1. + */ +export function toggleDocTableRow(rowNumber) { + getDocTableRow(rowNumber).within(() => { + cy.getElementByTestId('docTableExpandToggleColumn').find('button').click(); + }); +} + +/** + * Check the Doc Table rowNumberth row's Filter buttons filters the correct value. + * @param {number} rowNumber Doc table row number to check (First row is row 0) + * @param {string} filterElement data-test-sub element for filter. + * @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 + * @param {boolean} shouldMatch boolean to determine if same rowNumber text should match after filter is applied + * @example verifyDocTableFilterAction(0, 'filterForValue', '10,000', '1', true) + */ +export function verifyDocTableFilterAction( + rowNumber, + filterElement, + expectedQueryHitsWithoutFilter, + expectedQueryHitsAfterFilterApplied, + shouldMatch +) { + getDocTableField(0, rowNumber).then(($field) => { + const shouldText = shouldMatch ? 'have.text' : 'not.have.text'; + + const filterFieldText = $field.find('span span').text(); + $field.find(`[data-test-subj="${filterElement}"]`).click(); + // Verify pill text + cy.getElementByTestId('globalFilterLabelValue', { + timeout: 10000, + }).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. + getDocTableField(0, rowNumber).find('span span').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 Toggle Column button has intended behavior. + */ +export function verifyDocTableFirstExpandedFieldFirstRowToggleColumnButtonHasIntendedBehavior() { + getExpandedDocTableRowFieldName(0, 0).then(($expandedDocumentRowFieldText) => { + const fieldText = $expandedDocumentRowFieldText.text(); + getExpandedDocTableRow(0, 0).within(() => { + cy.getElementByTestId('docTableHeader-' + fieldText).should('not.exist'); + cy.getElementByTestId('toggleColumnButton').click(); + }); + cy.getElementByTestId('fieldList-selected').within(() => { + cy.getElementByTestId('field-' + fieldText).should('exist'); + }); + cy.getElementByTestId('docTableHeader-' + fieldText).should('exist'); + cy.getElementByTestId('fieldToggle-' + fieldText).click(); + cy.getElementByTestId('fieldList-selected').within(() => { + cy.getElementByTestId('field-' + fieldText).should('not.exist'); + }); + cy.getElementByTestId('docTableHeader-' + fieldText).should('not.exist'); + }); +} diff --git a/cypress/utils/apps/query_enhancements/constants.js b/cypress/utils/apps/query_enhancements/constants.js index 63d128ed0864..f85267e47d73 100644 --- a/cypress/utils/apps/query_enhancements/constants.js +++ b/cypress/utils/apps/query_enhancements/constants.js @@ -7,6 +7,32 @@ export const DATASOURCE_NAME = 'data-logs-1'; export const WORKSPACE_NAME = 'query-workspace'; export const START_TIME = 'Jan 1, 2020 @ 00:00:00.000'; export const END_TIME = 'Jan 1, 2024 @ 00:00:00.000'; +export const INDEX_NAME = 'data_logs_small_time_1'; +export const DEFAULT_TIME_INDEX_PATTERN_NAME = 'data_logs_small_time_1*'; +export const DEFAULT_NO_TIME_INDEX_PATTERN_NAME = 'data_logs_small_no_time_1*'; +export const INDEX_PATTERN_NAME = `${DATASOURCE_NAME}::${DEFAULT_TIME_INDEX_PATTERN_NAME}`; + +export const DATASET_CONFIGS = { + index_pattern: { + type: 'index_pattern', + name: INDEX_PATTERN_NAME, + languages: [ + // isFilterButtonsEnabled signifies if the filter buttons are supposed to be enabled. + { name: 'DQL', isFilterButtonsEnabled: true }, + { name: 'Lucene', isFilterButtonsEnabled: true }, + { name: 'OpenSearch SQL', isFilterButtonsEnabled: false }, + { name: 'PPL', isFilterButtonsEnabled: false }, + ], + }, + index: { + type: 'index', + name: INDEX_NAME, + languages: [ + { name: 'OpenSearch SQL', isFilterButtonsEnabled: false }, + { name: 'PPL', isFilterButtonsEnabled: false }, + ], + }, +}; export const clusterName = 'test_cluster'; export const clusterConnection = 'http://localhost:9200'; diff --git a/cypress/utils/commands.js b/cypress/utils/commands.js index 1782a31e90af..51501f574ffa 100644 --- a/cypress/utils/commands.js +++ b/cypress/utils/commands.js @@ -30,18 +30,6 @@ Cypress.Commands.add('getElementsByTestIds', (testIds, options = {}) => { return cy.get(selectors.join(','), options); }); -/** - * Get DOM elements 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('getElementsByTestIdLike', (partialTestId, options = {}) => { - return cy.get(`[data-test-subj*="${partialTestId}"]`, options); -}); - /** * Find element from previous chained element with a data-test-subj id containing the testId. * @param {string} subject DOM object to find within. diff --git a/cypress/utils/dashboards/data_explorer/elements.js b/cypress/utils/dashboards/data_explorer/elements.js new file mode 100644 index 000000000000..50918fd5f714 --- /dev/null +++ b/cypress/utils/dashboards/data_explorer/elements.js @@ -0,0 +1,41 @@ +/* + * Copyright OpenSearch Contributors + * SPDX-License-Identifier: Apache-2.0 + */ + +export const NEW_SEARCH_BUTTON = 'discoverNewButton'; +export const DISCOVER_QUERY_HITS = 'discoverQueryHits'; +export const DATASET_SELECTOR_BUTTON = 'datasetSelectorButton'; +export const ALL_DATASETS_BUTTON = 'datasetSelectorAdvancedButton'; +export const DATASET_EXPLORER_WINDOW = 'datasetExplorerWindow'; +export const DATASET_SELECTOR_NEXT_BUTTON = 'datasetSelectorNext'; +export const DATASET_SELECTOR_LANGUAGE_SELECTOR = 'advancedSelectorLanguageSelect'; +export const DATASET_SELECTOR_TIME_SELECTOR = 'advancedSelectorTimeFieldSelect'; +export const DATASET_SELECTOR_SELECT_DATA_BUTTON = 'advancedSelectorConfirmButton'; +export const DOC_TABLE = 'docTable'; +export const DOC_TABLE_ROW_FIELD = 'docTableField'; +export const DOC_TABLE_EXPAND_TOGGLE_COLUMN_BUTTON = 'docTableExpandToggleColumn'; +export const DOC_TABLE_EXPANDED_DOC_COLUMN_ROW_PREFIX = 'tableDocViewRow-'; +export const DOC_TABLE_EXPANDED_DOC_TOGGLE_COLUMN_BUTTON = 'toggleColumnButton'; +export const DOC_TABLE_EXPANDED_DOC_COLUMN_ADD_INCLUSIVE_FILTER_BUTTON = 'addInclusiveFilterButton'; +export const DOC_TABLE_EXPANDED_DOC_COLUMN_REMOVE_INCLUSIVE_FILTER_BUTTON = + 'removeInclusiveFilterButton'; +export const DOC_TABLE_EXPANDED_DOC_COLUMN_EXISTS_FILTER_BUTTON = 'addExistsFilterButton'; +export const DOC_TABLE_HEADER_FIELD_PREFIX = 'docTableHeader-'; +export const TABLE_FIELD_FILTER_FOR_BUTTON = 'filterForValue'; +export const TABLE_FIELD_FILTER_OUT_BUTTON = 'filterOutValue'; +export const SEARCH_DATE_PICKER_BUTTON = 'superDatePickerShowDatesButton'; +export const SEARCH_DATE_PICKER_START_DATE_BUTTON = 'superDatePickerstartDatePopoverButton'; +export const SEARCH_DATE_PICKER_END_DATE_BUTTON = 'superDatePickerendDatePopoverButton'; +export const SEARCH_DATE_PICKER_RELATIVE_TAB = 'superDatePickerRelativeTab'; +export const SEARCH_DATE_RELATIVE_PICKER_INPUT = 'superDatePickerRelativeDateInputNumber'; +export const SEARCH_DATE_RELATIVE_PICKER_UNIT_SELECTOR = + 'superDatePickerRelativeDateInputUnitSelector'; +export const SEARCH_DATE_PICKER_ABSOLUTE_TAB = 'superDatePickerAbsoluteTab'; +export const SEARCH_DATE_PICKER_ABSOLUTE_DATE_INPUT = 'superDatePickerAbsoluteDateInput'; +export const SIDE_BAR_SELECTED_FIELDS_LIST = 'fieldList-selected'; +export const SIDE_BAR_FIELD_PREFIX = 'field-'; +export const SIDE_BAR_SELECTED_FIELD_REMOVE_BUTTON_PREFIX = 'fieldToggle-'; +export const QUERY_SUBMIT_BUTTON = 'querySubmitButton'; +export const GLOBAL_QUERY_EDITOR_FILTER_VALUE = 'globalFilterLabelValue'; +export const GLOBAL_FILTER_BAR = 'globalFilterBar'; diff --git a/cypress/utils/index.d.ts b/cypress/utils/index.d.ts index 9c3b23d3fc6e..bce04cf80697 100644 --- a/cypress/utils/index.d.ts +++ b/cypress/utils/index.d.ts @@ -34,6 +34,31 @@ declare namespace Cypress { options?: Partial ): Chainable; + /** + * 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 that has a data-test-subj including the string 'table' + * cy.findElementsByTestIdLike('table') + */ + findElementByTestIdLike( + partialTestId: string, + options?: Partial + ): Chainable; + + /** + * 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: {} + */ + findElementByTestId( + testId: string, + options?: Partial + ): Chainable; + /** * Create an index * @example