Skip to content

Commit

Permalink
[ML] Functional tests for the Overview page and side nav (elastic#124793
Browse files Browse the repository at this point in the history
)

* update side nav tests for full ml access

* ML nodes tests

* assert empty states

* assert getting started callout

* assert panels with data

* assert read ml access

* waitForDatePickerIndicatorLoaded

* add missing step

* fix typo

* rename variable

(cherry picked from commit a248af0)
  • Loading branch information
darnautov authored and kibanamachine committed Feb 8, 2022
1 parent 6672ab1 commit 11765c9
Show file tree
Hide file tree
Showing 11 changed files with 196 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,7 @@ export function useSideNavItems(activeRoute: MlRoute | undefined) {
}),
pathId: ML_PAGES.SINGLE_METRIC_VIEWER,
disabled: disableLinks,
testSubj: 'mlMainTab singleMetricViewer',
},
{
id: 'settings',
Expand Down Expand Up @@ -185,7 +186,7 @@ export function useSideNavItems(activeRoute: MlRoute | undefined) {
defaultMessage: 'File',
}),
disabled: false,
testSubj: 'mlMainTab dataVisualizer fileDatavisualizer',
testSubj: 'mlMainTab fileDataVisualizer',
},
{
id: 'data_view_datavisualizer',
Expand All @@ -194,7 +195,7 @@ export function useSideNavItems(activeRoute: MlRoute | undefined) {
defaultMessage: 'Data View',
}),
disabled: false,
testSubj: 'mlMainTab dataVisualizer dataViewDatavisualizer',
testSubj: 'mlMainTab indexDataVisualizer',
},
],
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ export interface StatsBarStat {
label: string;
value: number;
show?: boolean;
'data-test-subj'?: string;
}
interface StatProps {
stat: StatsBarStat;
Expand All @@ -19,7 +20,8 @@ interface StatProps {
export const Stat: FC<StatProps> = ({ stat }) => {
return (
<span className="stat">
<span>{stat.label}</span>: <strong>{stat.value}</strong>
<span>{stat.label}</span>:{' '}
<strong data-test-subj={stat['data-test-subj']}>{stat.value}</strong>
</span>
);
};
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ export const GettingStartedCallout: FC = () => {
return (
<>
<EuiCallOut
data-test-subj={'mlGettingStartedCallout'}
title={
<FormattedMessage
id="xpack.ml.overview.gettingStartedSectionTitle"
Expand Down Expand Up @@ -72,7 +73,11 @@ export const GettingStartedCallout: FC = () => {
/>
</p>
<p>
<EuiButton color="primary" onClick={setIsCalloutDismissed.bind(null, true)}>
<EuiButton
color="primary"
onClick={setIsCalloutDismissed.bind(null, true)}
data-test-subj={'mlDismissGettingStartedCallout'}
>
<FormattedMessage
id="xpack.ml.overview.gettingStartedSectionDismiss"
defaultMessage="Dismiss"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,7 @@ export const NodesList: FC<NodesListProps> = ({ compactView = false }) => {
label: i18n.translate('xpack.ml.trainedModels.nodesList.totalAmountLabel', {
defaultMessage: 'Total machine learning nodes',
}),
'data-test-subj': 'mlTotalNodesCount',
},
};
}, [items]);
Expand Down Expand Up @@ -189,7 +190,7 @@ export const NodesList: FC<NodesListProps> = ({ compactView = false }) => {
}

return (
<>
<div data-test-subj={'mlNodesOverviewPanel'}>
<EuiSpacer size="m" />
<EuiFlexGroup justifyContent="spaceBetween">
{nodesStats && (
Expand Down Expand Up @@ -218,6 +219,6 @@ export const NodesList: FC<NodesListProps> = ({ compactView = false }) => {
data-test-subj={isLoading ? 'mlNodesTable loading' : 'mlNodesTable loaded'}
/>
</div>
</>
</div>
);
};
61 changes: 52 additions & 9 deletions x-pack/test/functional/apps/ml/permissions/full_ml_access.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { USER } from '../../../services/ml/security_common';
export default function ({ getService }: FtrProviderContext) {
const esArchiver = getService('esArchiver');
const ml = getService('ml');
const browser = getService('browser');

const testUsers = [
{ user: USER.ML_POWERUSER, discoverAvailable: true },
Expand Down Expand Up @@ -44,41 +45,68 @@ export default function ({ getService }: FtrProviderContext) {
await ml.navigation.assertKibanaNavMLEntryExists();
});

it('should display tabs in the ML app correctly', async () => {
it('should display side nav in the ML app correctly', async () => {
await ml.testExecution.logTestStep('should load the ML app');
await ml.navigation.navigateToMl();

await ml.testExecution.logTestStep('should display the enabled "Overview" tab');
await ml.navigation.assertOverviewTabEnabled(true);

await ml.testExecution.logTestStep(
'should display the enabled "Anomaly Detection" tab'
'should display the enabled "Anomaly Detection" section correctly'
);
await ml.navigation.assertAnomalyDetectionTabEnabled(true);
await ml.navigation.assertAnomalyExplorerNavItemEnabled(true);
await ml.navigation.assertSingleMetricViewerNavItemEnabled(true);
await ml.navigation.assertSettingsTabEnabled(true);

await ml.testExecution.logTestStep(
'should display the enabled "Data Frame Analytics" tab'
'should display the enabled "Data Frame Analytics" section'
);
await ml.navigation.assertDataFrameAnalyticsTabEnabled(true);

await ml.testExecution.logTestStep('should display the enabled "Data Visualizer" tab');
await ml.navigation.assertDataVisualizerTabEnabled(true);
await ml.testExecution.logTestStep(
'should display the enabled "Model Management" section'
);
await ml.navigation.assertTrainedModelsNavItemEnabled(true);
await ml.navigation.assertNodesNavItemEnabled(true);

await ml.testExecution.logTestStep('should display the enabled "Settings" tab');
await ml.navigation.assertSettingsTabEnabled(true);
await ml.testExecution.logTestStep(
'should display the enabled "Data Visualizer" section'
);
await ml.navigation.assertDataVisualizerTabEnabled(true);
await ml.navigation.assertFileDataVisualizerNavItemEnabled(true);
await ml.navigation.assertIndexDataVisualizerNavItemEnabled(true);
});

it('should display elements on ML Overview page correctly', async () => {
await ml.testExecution.logTestStep('should load the ML overview page');
await ml.navigation.navigateToOverview();

await ml.testExecution.logTestStep('should display enabled AD create job button');
await ml.commonUI.waitForDatePickerIndicatorLoaded();

await ml.testExecution.logTestStep('should display a welcome callout');
await ml.overviewPage.assertGettingStartedCalloutVisible(true);
await ml.overviewPage.dismissGettingStartedCallout();

await ml.testExecution.logTestStep('should display ML Nodes panel');
await ml.mlNodesPanel.assertNodeOverviewPanel();

await ml.testExecution.logTestStep('should display Anomaly Detection empty state');
await ml.overviewPage.assertADEmptyStateExists();
await ml.overviewPage.assertADCreateJobButtonExists();
await ml.overviewPage.assertADCreateJobButtonEnabled(true);

await ml.testExecution.logTestStep('should display enabled DFA create job button');
await ml.testExecution.logTestStep('should display DFA empty state');
await ml.overviewPage.assertDFAEmptyStateExists();
await ml.overviewPage.assertDFACreateJobButtonExists();
await ml.overviewPage.assertDFACreateJobButtonEnabled(true);

await ml.testExecution.logTestStep(
'should persist the getting started callout state after refresh'
);
await browser.refresh();
await ml.overviewPage.assertGettingStartedCalloutVisible(false);
});
});
}
Expand Down Expand Up @@ -164,6 +192,21 @@ export default function ({ getService }: FtrProviderContext) {
await ml.securityUI.logout();
});

it('should display elements on ML Overview page correctly', async () => {
await ml.testExecution.logTestStep('should load the Overview page');
await ml.navigation.navigateToMl();
await ml.navigation.navigateToOverview();

await ml.testExecution.logTestStep('should display ML Nodes panel');
await ml.mlNodesPanel.assertNodeOverviewPanel();

await ml.testExecution.logTestStep('should display Anomaly Detection panel');
await ml.overviewPage.assertAdJobsOverviewPanelExist();

await ml.testExecution.logTestStep('should display DFA panel');
await ml.overviewPage.assertDFAJobsOverviewPanelExist();
});

it('should display elements on Anomaly Detection page correctly', async () => {
await ml.testExecution.logTestStep('should load the AD job management page');
await ml.navigation.navigateToMl();
Expand Down
33 changes: 27 additions & 6 deletions x-pack/test/functional/apps/ml/permissions/read_ml_access.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,32 +52,53 @@ export default function ({ getService }: FtrProviderContext) {
await ml.navigation.assertOverviewTabEnabled(true);

await ml.testExecution.logTestStep(
'should display the enabled "Anomaly Detection" tab'
'should display the enabled "Anomaly Detection" section correctly'
);
await ml.navigation.assertAnomalyDetectionTabEnabled(true);
await ml.navigation.assertAnomalyExplorerNavItemEnabled(true);
await ml.navigation.assertSingleMetricViewerNavItemEnabled(true);
await ml.navigation.assertSettingsTabEnabled(true);

await ml.testExecution.logTestStep(
'should display the enabled "Data Frame Analytics" tab'
'should display the enabled "Data Frame Analytics" section'
);
await ml.navigation.assertDataFrameAnalyticsTabEnabled(true);

await ml.testExecution.logTestStep('should display the enabled "Data Visualizer" tab');
await ml.navigation.assertDataVisualizerTabEnabled(true);
await ml.testExecution.logTestStep(
'should display the enabled "Model Management" section'
);
await ml.navigation.assertTrainedModelsNavItemEnabled(true);
await ml.navigation.assertNodesNavItemEnabled(false);

await ml.testExecution.logTestStep('should display the enabled "Settings" tab');
await ml.navigation.assertSettingsTabEnabled(true);
await ml.testExecution.logTestStep(
'should display the enabled "Data Visualizer" section'
);
await ml.navigation.assertDataVisualizerTabEnabled(true);
await ml.navigation.assertFileDataVisualizerNavItemEnabled(true);
await ml.navigation.assertIndexDataVisualizerNavItemEnabled(true);
});

it('should display elements on ML Overview page correctly', async () => {
await ml.testExecution.logTestStep('should load the ML overview page');
await ml.navigation.navigateToMl();
await ml.navigation.navigateToOverview();

await ml.commonUI.waitForDatePickerIndicatorLoaded();

await ml.testExecution.logTestStep('should display a welcome callout');
await ml.overviewPage.assertGettingStartedCalloutVisible(true);
await ml.overviewPage.dismissGettingStartedCallout();

await ml.testExecution.logTestStep('should not display ML Nodes panel');
await ml.mlNodesPanel.assertNodesOverviewPanelExists(false);

await ml.testExecution.logTestStep('should display disabled AD create job button');
await ml.overviewPage.assertADEmptyStateExists();
await ml.overviewPage.assertADCreateJobButtonExists();
await ml.overviewPage.assertADCreateJobButtonEnabled(false);

await ml.testExecution.logTestStep('should display disabled DFA create job button');
await ml.overviewPage.assertDFAEmptyStateExists();
await ml.overviewPage.assertDFACreateJobButtonExists();
await ml.overviewPage.assertDFACreateJobButtonEnabled(false);
});
Expand Down
4 changes: 4 additions & 0 deletions x-pack/test/functional/services/ml/common_ui.ts
Original file line number Diff line number Diff line change
Expand Up @@ -334,5 +334,9 @@ export function MachineLearningCommonUIProvider({
await PageObjects.spaceSelector.goToSpecificSpace(spaceId);
await PageObjects.spaceSelector.expectHomePage(spaceId);
},

async waitForDatePickerIndicatorLoaded() {
await testSubjects.waitForEnabled('superDatePickerApplyTimeButton');
},
};
}
3 changes: 3 additions & 0 deletions x-pack/test/functional/services/ml/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ import { MachineLearningDashboardEmbeddablesProvider } from './dashboard_embedda
import { TrainedModelsProvider } from './trained_models';
import { TrainedModelsTableProvider } from './trained_models_table';
import { MachineLearningJobAnnotationsProvider } from './job_annotations_table';
import { MlNodesPanelProvider } from './ml_nodes_list';

export function MachineLearningProvider(context: FtrProviderContext) {
const commonAPI = MachineLearningCommonAPIProvider(context);
Expand Down Expand Up @@ -124,6 +125,7 @@ export function MachineLearningProvider(context: FtrProviderContext) {
const swimLane = SwimLaneProvider(context);
const trainedModels = TrainedModelsProvider(context, api, commonUI);
const trainedModelsTable = TrainedModelsTableProvider(context);
const mlNodesPanel = MlNodesPanelProvider(context);

return {
anomaliesTable,
Expand Down Expand Up @@ -173,5 +175,6 @@ export function MachineLearningProvider(context: FtrProviderContext) {
testResources,
trainedModels,
trainedModelsTable,
mlNodesPanel,
};
}
41 changes: 41 additions & 0 deletions x-pack/test/functional/services/ml/ml_nodes_list.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the Elastic License
* 2.0; you may not use this file except in compliance with the Elastic License
* 2.0.
*/

import expect from '@kbn/expect';
import { FtrProviderContext } from '../../ftr_provider_context';

export function MlNodesPanelProvider({ getService }: FtrProviderContext) {
const testSubjects = getService('testSubjects');

return {
async assertNodesOverviewPanelExists(expectPanelExits: boolean = true) {
if (expectPanelExits) {
await testSubjects.existOrFail('mlNodesOverviewPanel');
} else {
await testSubjects.missingOrFail('mlNodesOverviewPanel');
}
},

async assertNodesListLoaded() {
await testSubjects.existOrFail('mlNodesTable loaded', { timeout: 5000 });
},

async assertMlNodesCount(minCount: number = 1) {
const actualCount = parseInt(await testSubjects.getVisibleText('mlTotalNodesCount'), 10);
expect(actualCount).to.not.be.lessThan(
minCount,
`Total ML nodes count should be at least '${minCount}' (got '${actualCount}')`
);
},

async assertNodeOverviewPanel() {
await this.assertNodesOverviewPanelExists();
await this.assertNodesListLoaded();
await this.assertMlNodesCount();
},
};
}
24 changes: 24 additions & 0 deletions x-pack/test/functional/services/ml/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -106,14 +106,38 @@ export function MachineLearningNavigationProvider({
await this.assertTabEnabled('~mlMainTab & ~anomalyDetection', expectedValue);
},

async assertAnomalyExplorerNavItemEnabled(expectedValue: boolean) {
await this.assertTabEnabled('~mlMainTab & ~anomalyExplorer', expectedValue);
},

async assertSingleMetricViewerNavItemEnabled(expectedValue: boolean) {
await this.assertTabEnabled('~mlMainTab & ~singleMetricViewer', expectedValue);
},

async assertDataFrameAnalyticsTabEnabled(expectedValue: boolean) {
await this.assertTabEnabled('~mlMainTab & ~dataFrameAnalytics', expectedValue);
},

async assertTrainedModelsNavItemEnabled(expectedValue: boolean) {
await this.assertTabEnabled('~mlMainTab & ~trainedModels', expectedValue);
},

async assertNodesNavItemEnabled(expectedValue: boolean) {
await this.assertTabEnabled('~mlMainTab & ~nodesOverview', expectedValue);
},

async assertDataVisualizerTabEnabled(expectedValue: boolean) {
await this.assertTabEnabled('~mlMainTab & ~dataVisualizer', expectedValue);
},

async assertFileDataVisualizerNavItemEnabled(expectedValue: boolean) {
await this.assertTabEnabled('~mlMainTab & ~fileDataVisualizer', expectedValue);
},

async assertIndexDataVisualizerNavItemEnabled(expectedValue: boolean) {
await this.assertTabEnabled('~mlMainTab & ~indexDataVisualizer', expectedValue);
},

async assertSettingsTabEnabled(expectedValue: boolean) {
await this.assertTabEnabled('~mlMainTab & ~settings', expectedValue);
},
Expand Down
Loading

0 comments on commit 11765c9

Please sign in to comment.