Skip to content

Commit

Permalink
[TESTID-58,59] Inspect functionality for Discover and Visualizations (o…
Browse files Browse the repository at this point in the history
…pensearch-project#9292)

* Complete discover inspect tests.

Signed-off-by: Argus Li <[email protected]>

* Complete visualizations and fix PPL array type.

Signed-off-by: Argus Li <[email protected]>

* Changeset file for PR opensearch-project#9292 created/updated

* Fix docker URL for datasource.

Signed-off-by: Argus Li <[email protected]>

* Fix namespace issue.

Signed-off-by: Argus Li <[email protected]>

* Address comments.

Signed-off-by: Argus Li <[email protected]>

* Fix import

Signed-off-by: Argus Li <[email protected]>

* Fix import.

Signed-off-by: Argus Li <[email protected]>

* Add spec to cigroup 10 and 12.

Signed-off-by: Argus Li <[email protected]>

* Remove test from CI Group 10.

Signed-off-by: Argus Li <[email protected]>

* Make field display filtering use randomized datasource name

Signed-off-by: Argus Li <[email protected]>

* Address comments.

Removed a log and a wait.

Signed-off-by: Argus Li <[email protected]>

---------

Signed-off-by: Argus Li <[email protected]>
Co-authored-by: opensearch-changeset-bot[bot] <154024398+opensearch-changeset-bot[bot]@users.noreply.github.com>
  • Loading branch information
2 people authored and ruchidh committed Feb 6, 2025
1 parent 95ed059 commit 1e579d4
Show file tree
Hide file tree
Showing 10 changed files with 792 additions and 308 deletions.
2 changes: 2 additions & 0 deletions changelogs/fragments/9292.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
test:
- Add cypress integration test for the inspect functionality in the Discover and Dashboards pages. ([#9292](https://github.com/opensearch-project/OpenSearch-Dashboards/pull/9292))

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/*
* Copyright OpenSearch Contributors
* SPDX-License-Identifier: Apache-2.0
*/

import {
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 { NEW_SEARCH_BUTTON } from '../../../../../utils/dashboards/data_explorer/elements.js';
import {
generateAllTestConfigurations,
getRandomizedWorkspaceName,
getRandomizedDatasourceName,
setDatePickerDatesAndSearchIfRelevant,
} from '../../../../../utils/apps/query_enhancements/shared.js';
import {
generateInspectTestConfiguration,
getFlattenedFieldsWithValue,
verifyVisualizationsWithNoInspectOption,
verifyVisualizationsWithInspectOption,
visualizationTitlesWithNoInspectOptions,
visualizationTitlesWithInspectOptions,
} from '../../../../../utils/apps/query_enhancements/inspect.js';

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,
});

cy.navigateToWorkSpaceSpecificPage({
url: BASE_PATH,
workspaceName: workspaceName,
page: 'discover',
isEnhancement: true,
});
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(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;
}
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,
});

cy.getElementByTestId('addSampleDataSetflights').click();
cy.getElementByTestId('sampleDataSetInstallToast').should('exist');

cy.navigateToWorkSpaceSpecificPage({
url: BASE_PATH,
workspaceName: workspaceName,
page: 'dashboards',
isEnhancement: true,
});

cy.getElementByTestIdLike(
'dashboardListingTitleLink-[Flights]-Global-Flight-Dashboard'
).click();

cy.getElementByTestId('visualizationLoader').should(
'have.length',
NUMBER_OF_VISUALIZATIONS_IN_FLIGHTS_DASHBOARD
);

verifyVisualizationsWithNoInspectOption(visualizationTitlesWithNoInspectOptions);
verifyVisualizationsWithInspectOption(visualizationTitlesWithInspectOptions);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
getRandomizedDatasourceName,
setDatePickerDatesAndSearchIfRelevant,
} from '../../../../../utils/apps/query_enhancements/shared';
import { getDocTableField } from '../../../../../utils/apps/query_enhancements/field_display_filtering';
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';

Expand Down
199 changes: 199 additions & 0 deletions cypress/utils/apps/query_enhancements/doc_table.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
/*
* 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 const getDocTableRow = (rowNumber) => {
return cy.getElementByTestId('docTable').get('tbody tr').eq(rowNumber);
};

/**
* Get specific field of DocTable.
* @param {number} columnNumber Integer starts from 0 for the first column
* @param {number} rowNumber Integer starts from 0 for the first row
*/
export const getDocTableField = (columnNumber, rowNumber) => {
return getDocTableRow(rowNumber).findElementByTestId('docTableField').eq(columnNumber);
};

/**
* find all Rows in Doc Table Field Expanded Document.
* @param expandedDocument cypress representation of the Doc Table Field Expanded Document
*/
export const 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 const getExpandedDocTableRow = (docTableRowNumber, expandedDocumentRowNumber) => {
return findExpandedDocTableRows(getDocTableRow(docTableRowNumber + 1)).eq(
expandedDocumentRowNumber
);
};

/**
* Get the value for the "expandedDocumentRowNumber"th row from the expanded document from the "docTableRowNumber"th row of the DocTable.
* @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 const getExpandedDocTableRowValue = (docTableRowNumber, expandedDocumentRowNumber) => {
return getExpandedDocTableRow(docTableRowNumber, expandedDocumentRowNumber)
.find(`[data-test-subj*="tableDocViewRow-"]`)
.find('span');
};

/**
* Get the field name for the "expandedDocumentRowNumber"th row from the expanded document from the "docTableRowNumber"th row of the DocTable.
* @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 const getExpandedDocTableRowFieldName = (docTableRowNumber, expandedDocumentRowNumber) => {
return getExpandedDocTableRow(docTableRowNumber, expandedDocumentRowNumber)
.find('td')
.eq(1) // Field name is in the second column.
.find('span[class*="textTruncate"]');
};

/**
* Get the value for the row with the expandedDocumentField from the expanded document.
* @param {string} expandedDocumentField Field name
* @example
* // returns the value of the 'AvgTicketPrice' field from the expanded document.
* getExpandedDocTableRowFieldName(1, 'AvgTicketPrice');
*/
export const getExpandedDocTableRowFieldValue = (expandedDocumentField) => {
return cy.getElementByTestId(`tableDocViewRow-${expandedDocumentField}-value`);
};

/**
* Select a language in the Dataset Selector for Index
* @param {string} datasetLanguage Index supports "OpenSearch SQL" and "PPL"
*/
export const 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 const 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 const selectIndexPatternDatasetLanguage = (datasetLanguage) => {
cy.getElementByTestId('advancedSelectorLanguageSelect').select(datasetLanguage);
cy.getElementByTestId('advancedSelectorConfirmButton').click();
};

/**
* Select an index pattern dataset.
* @param {string} indexPatternName Name of the index pattern to be used.
* @param {string} datasetLanguage Index Pattern supports "DQL", "Lucene", "OpenSearch SQL" and "PPL"
*/
export const selectIndexPatternDataset = (indexPatternName, datasetLanguage) => {
cy.getElementByTestId('datasetSelectorButton').click();
cy.getElementByTestId('datasetSelectorAdvancedButton').click();
cy.getElementByTestId('datasetExplorerWindow').contains('Index Patterns').click();
cy.getElementByTestId('datasetExplorerWindow').contains(indexPatternName).click();
cy.getElementByTestId('datasetSelectorNext').click();
selectIndexPatternDatasetLanguage(datasetLanguage);
};

/**
* Toggle expansion of row rowNumber of Doc Table.
* @param {number} rowNumber rowNumber of Doc Table starts at 0 for row 1.
*/
export const toggleDocTableRow = (rowNumber) => {
getDocTableRow(rowNumber).within(() => {
cy.getElementByTestId('docTableExpandToggleColumn').find('button').click();
});
};

/**
* Check the Doc Table rowNumberth row's Filter buttons filters the correct value.
* @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 const 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 const 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');
});
};
Loading

0 comments on commit 1e579d4

Please sign in to comment.