-
Notifications
You must be signed in to change notification settings - Fork 937
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[TESTID-58,59] Inspect functionality for Discover and Visualizations #9292
base: main
Are you sure you want to change the base?
Changes from all commits
4ad1c29
b54606b
b10a007
b1af62b
e9246d5
d7544fb
9cd640e
eae1e4c
6577482
e11b5b8
be827ba
94270d4
57c9f63
4924170
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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}`); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. do we need this? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I want to keep this here. These are skipped because of a bug (#9305), and I want to make it clear they are skipped. I'll add the link to the bug to the comment as well. |
||
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 |
---|---|---|
@@ -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) => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit: maybe call it expandDocTableRow is more straightforward? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would prefer that name, but it can also shrink the tableRow, so I think toggle is a better word. |
||
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'); | ||
}); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why this toggleDocTableRow is to
// To ensure it waits until a full table is loaded into the DOM, instead of a bug where table only has 1 hit.
?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The comment is for
cy.getElementByTestId('docTable').get('tbody tr').should('have.length.above', 3);
. I can move the comment above the line instead if it makes it more legible?