diff --git a/x-pack/plugins/ml/public/application/components/entity_cell/entity_cell.tsx b/x-pack/plugins/ml/public/application/components/entity_cell/entity_cell.tsx index 92dfe83ee6653..defe64583e927 100644 --- a/x-pack/plugins/ml/public/application/components/entity_cell/entity_cell.tsx +++ b/x-pack/plugins/ml/public/application/components/entity_cell/entity_cell.tsx @@ -41,6 +41,7 @@ function getAddFilter({ entityName, entityValue, filter }: EntityCellProps) { > { filter(entityName, entityValue, ENTITY_FIELD_OPERATIONS.ADD); @@ -68,6 +69,7 @@ function getRemoveFilter({ entityName, entityValue, filter }: EntityCellProps) { > { filter(entityName, entityValue, ENTITY_FIELD_OPERATIONS.REMOVE); diff --git a/x-pack/test/functional/apps/ml/anomaly_detection_result_views/anomaly_explorer.ts b/x-pack/test/functional/apps/ml/anomaly_detection_result_views/anomaly_explorer.ts index 095e9b463fb16..29cc28993d6c2 100644 --- a/x-pack/test/functional/apps/ml/anomaly_detection_result_views/anomaly_explorer.ts +++ b/x-pack/test/functional/apps/ml/anomaly_detection_result_views/anomaly_explorer.ts @@ -151,6 +151,46 @@ export default function ({ getService, getPageObjects }: FtrProviderContext) { await ml.anomaliesTable.assertTableNotEmpty(); }); + it('should allow filtering by influencer', async () => { + const fieldName = testData.expected.influencers[0].field; + const fieldValue = testData.expected.influencers[0].labelsContained[0]; + + await ml.testExecution.logTestStep( + 'adds influencer filter by clicking on the influencer add filter button' + ); + await ml.anomalyExplorer.addFilterForInfluencer(fieldName, fieldValue); + await ml.testExecution.logTestStep('query bar and table rows reflect filter'); + await ml.anomalyExplorer.assertQueryBarContent(`${fieldName}:"${fieldValue}"`); + await ml.anomaliesTable.assertInfluencersCellsContainFilter( + `${fieldName}: ${fieldValue}` + ); + await ml.testExecution.logTestStep('influencers list and swimlane reflect filter'); + await ml.swimLane.assertAxisLabels(viewBySwimLaneTestSubj, 'y', [fieldValue]); + await ml.anomalyExplorer.assertInfluencerFieldListLength('airline', 1); + await ml.testExecution.logTestStep( + 'removes influencer filter by clicking on the influencer remove filter button' + ); + await ml.anomalyExplorer.removeFilterForInfluencer(fieldName, fieldValue); + await ml.testExecution.logTestStep('query bar reflects filter removal'); + await ml.anomalyExplorer.assertQueryBarContent(''); + await ml.testExecution.logTestStep( + 'influencers list and swimlane reflect filter removal' + ); + await ml.swimLane.assertAxisLabels(viewBySwimLaneTestSubj, 'y', [ + 'AAL', + 'EGF', + 'VRD', + 'SWR', + 'JZA', + 'AMX', + 'TRS', + 'ACA', + 'BAW', + 'ASA', + ]); + await ml.anomalyExplorer.assertInfluencerFieldListLength('airline', 10); + }); + it('has enabled Single Metric Viewer button', async () => { await ml.anomalyExplorer.assertSingleMetricViewerButtonEnabled(true); }); diff --git a/x-pack/test/functional/services/ml/anomalies_table.ts b/x-pack/test/functional/services/ml/anomalies_table.ts index 7d51539d77002..8e6c652b33d97 100644 --- a/x-pack/test/functional/services/ml/anomalies_table.ts +++ b/x-pack/test/functional/services/ml/anomalies_table.ts @@ -56,6 +56,14 @@ export function MachineLearningAnomaliesTableProvider({ getService }: FtrProvide ); }, + async assertInfluencersCellsContainFilter(filterString: string) { + const tableRows = await testSubjects.findAll('mlAnomaliesListColumnInfluencers'); + for (const row of tableRows) { + const influencerColumnCellText = await row.getVisibleText(); + expect(influencerColumnCellText).to.eql(filterString); + } + }, + async assertAnomalyActionsMenuButtonExists(rowIndex: number) { const rowSubj = await this.getRowSubjByRowIndex(rowIndex); await testSubjects.existOrFail(`${rowSubj} > mlAnomaliesListRowActionsButton`); diff --git a/x-pack/test/functional/services/ml/anomaly_explorer.ts b/x-pack/test/functional/services/ml/anomaly_explorer.ts index 8c2f8e8b09bb9..b3353556b1cc6 100644 --- a/x-pack/test/functional/services/ml/anomaly_explorer.ts +++ b/x-pack/test/functional/services/ml/anomaly_explorer.ts @@ -44,6 +44,20 @@ export function MachineLearningAnomalyExplorerProvider( return influencerFieldLabels; }, + async getQueryBarText() { + const queryBarElement = await testSubjects.find('explorerQueryInput'); + const queryBarText = await queryBarElement.getVisibleText(); + return queryBarText; + }, + + async assertQueryBarContent(contentString: string) { + const queryBarText = await this.getQueryBarText(); + expect(queryBarText).to.eql( + contentString, + `Expected influencer filter to be '${contentString}' (got '${queryBarText}')` + ); + }, + async assertInfluencerListContainsLabel(influencerField: string, label: string) { const influencerFieldLabels = await this.getInfluencerFieldLabels(influencerField); expect(influencerFieldLabels).to.contain( @@ -84,6 +98,20 @@ export function MachineLearningAnomalyExplorerProvider( }); }, + async addFilterForInfluencer(influencerField: string, influencerValue: string) { + await testSubjects.existOrFail( + `mlAnomaliesTableEntityCellAddFilterButton-${influencerValue}` + ); + await testSubjects.click(`mlAnomaliesTableEntityCellAddFilterButton-${influencerValue}`); + }, + + async removeFilterForInfluencer(influencerField: string, influencerValue: string) { + await testSubjects.existOrFail( + `mlAnomaliesTableEntityCellRemoveFilterButton-${influencerValue}` + ); + await testSubjects.click(`mlAnomaliesTableEntityCellRemoveFilterButton-${influencerValue}`); + }, + async openAddToDashboardControl() { await testSubjects.click('mlAnomalyTimelinePanelMenu'); await testSubjects.click('mlAnomalyTimelinePanelAddToDashboardButton');