[ML] Anomaly detection: Adds functional test for delayed data chart flyout (#109026)

* wip add delayed data functional test

* adds delayed data functional test

* add menu check for stability and reorganize functions

* ensure describe block is self contained
This commit is contained in:
Melissa Alvarez 2021-08-19 14:33:29 -04:00 committed by GitHub
parent 91910dbecd
commit 63db90b0c4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 193 additions and 121 deletions

View file

@ -185,8 +185,9 @@ export const DatafeedChartFlyout: FC<DatafeedChartFlyoutProps> = ({ jobId, end,
aria-label={i18n.translate('xpack.ml.jobsList.datafeedChart.datafeedChartFlyoutAriaLabel', {
defaultMessage: 'Datafeed chart flyout',
})}
data-test-subj="mlAnnotationsViewDatafeedFlyout"
>
<EuiFlyoutHeader hasBorder>
<EuiFlyoutHeader hasBorder data-test-subj="mlAnnotationsViewDatafeedFlyoutTitle">
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween" gutterSize="xl">
<EuiFlexItem grow={false}>
<EuiFlexGroup alignItems="center" gutterSize="s">
@ -308,143 +309,145 @@ export const DatafeedChartFlyout: FC<DatafeedChartFlyoutProps> = ({ jobId, end,
</EuiToolTip>
</EuiFlexItem>
<EuiFlexItem>
<Chart size={CHART_SIZE}>
<Settings
showLegend
legendPosition={Position.Bottom}
theme={{
lineSeriesStyle: {
point: {
visible: false,
},
},
}}
/>
<Axis
id="bottom"
position={Position.Bottom}
showOverlappingTicks
tickFormat={dateFormatter}
title={i18n.translate('xpack.ml.jobsList.datafeedChart.xAxisTitle', {
defaultMessage: 'Bucket span ({bucketSpan})',
values: { bucketSpan },
})}
/>
<Axis
id="left"
title={i18n.translate('xpack.ml.jobsList.datafeedChart.yAxisTitle', {
defaultMessage: 'Count',
})}
position={Position.Left}
/>
{showModelSnapshots ? (
<LineAnnotation
id={i18n.translate(
'xpack.ml.jobsList.datafeedChart.modelSnapshotsLineSeriesId',
{
defaultMessage: 'Model snapshots',
}
)}
key="model-snapshots-results-line"
domainType={AnnotationDomainType.XDomain}
dataValues={modelSnapshotData}
marker={<EuiIcon type="asterisk" />}
markerPosition={Position.Top}
style={{
line: {
strokeWidth: 3,
stroke: euiTheme.euiColorVis1,
opacity: 0.5,
<div data-test-subj="mlAnnotationsViewDatafeedFlyoutChart">
<Chart size={CHART_SIZE}>
<Settings
showLegend
legendPosition={Position.Bottom}
theme={{
lineSeriesStyle: {
point: {
visible: false,
},
},
}}
/>
) : null}
{showAnnotations ? (
<>
<Axis
id="bottom"
position={Position.Bottom}
showOverlappingTicks
tickFormat={dateFormatter}
title={i18n.translate('xpack.ml.jobsList.datafeedChart.xAxisTitle', {
defaultMessage: 'Bucket span ({bucketSpan})',
values: { bucketSpan },
})}
/>
<Axis
id="left"
title={i18n.translate('xpack.ml.jobsList.datafeedChart.yAxisTitle', {
defaultMessage: 'Count',
})}
position={Position.Left}
/>
{showModelSnapshots ? (
<LineAnnotation
id={i18n.translate(
'xpack.ml.jobsList.datafeedChart.annotationLineSeriesId',
'xpack.ml.jobsList.datafeedChart.modelSnapshotsLineSeriesId',
{
defaultMessage: 'Annotations line result',
defaultMessage: 'Model snapshots',
}
)}
key="annotation-results-line"
key="model-snapshots-results-line"
domainType={AnnotationDomainType.XDomain}
dataValues={annotationData.line}
marker={<EuiIcon type="annotation" />}
dataValues={modelSnapshotData}
marker={<EuiIcon type="asterisk" />}
markerPosition={Position.Top}
style={{
line: {
strokeWidth: 3,
stroke: euiTheme.euiColorDangerText,
stroke: euiTheme.euiColorVis1,
opacity: 0.5,
},
}}
/>
<RectAnnotation
key="annotation-results-rect"
dataValues={annotationData.rect}
id={i18n.translate(
'xpack.ml.jobsList.datafeedChart.annotationRectSeriesId',
{
defaultMessage: 'Annotations rectangle result',
}
)}
style={{ fill: euiTheme.euiColorDangerText }}
/>
</>
) : null}
{messageData.length > 0 ? (
<>
<LineAnnotation
id={i18n.translate(
'xpack.ml.jobsList.datafeedChart.messageLineAnnotationId',
{
defaultMessage: 'Job messages line result',
}
)}
key="messages-results-line"
domainType={AnnotationDomainType.XDomain}
dataValues={messageData}
marker={<EuiIcon type="tableDensityNormal" />}
markerPosition={Position.Top}
style={{
line: {
strokeWidth: 3,
stroke: euiTheme.euiColorAccent,
opacity: 0.5,
},
}}
/>
</>
) : null}
<LineSeries
key={'source-results'}
color={euiTheme.euiColorPrimary}
id={i18n.translate('xpack.ml.jobsList.datafeedChart.sourceSeriesId', {
defaultMessage: 'Source indices',
})}
xScaleType={ScaleType.Time}
yScaleType={ScaleType.Linear}
xAccessor={0}
yAccessors={[1]}
data={sourceData}
curve={CurveType.LINEAR}
/>
<LineSeries
key={'job-results'}
color={euiTheme.euiColorAccentText}
id={i18n.translate('xpack.ml.jobsList.datafeedChart.bucketSeriesId', {
defaultMessage: 'Job results',
})}
xScaleType={ScaleType.Time}
yScaleType={ScaleType.Linear}
xAccessor={0}
yAccessors={[1]}
data={bucketData}
curve={CurveType.LINEAR}
/>
</Chart>
) : null}
{showAnnotations ? (
<>
<LineAnnotation
id={i18n.translate(
'xpack.ml.jobsList.datafeedChart.annotationLineSeriesId',
{
defaultMessage: 'Annotations line result',
}
)}
key="annotation-results-line"
domainType={AnnotationDomainType.XDomain}
dataValues={annotationData.line}
marker={<EuiIcon type="annotation" />}
markerPosition={Position.Top}
style={{
line: {
strokeWidth: 3,
stroke: euiTheme.euiColorDangerText,
opacity: 0.5,
},
}}
/>
<RectAnnotation
key="annotation-results-rect"
dataValues={annotationData.rect}
id={i18n.translate(
'xpack.ml.jobsList.datafeedChart.annotationRectSeriesId',
{
defaultMessage: 'Annotations rectangle result',
}
)}
style={{ fill: euiTheme.euiColorDangerText }}
/>
</>
) : null}
{messageData.length > 0 ? (
<>
<LineAnnotation
id={i18n.translate(
'xpack.ml.jobsList.datafeedChart.messageLineAnnotationId',
{
defaultMessage: 'Job messages line result',
}
)}
key="messages-results-line"
domainType={AnnotationDomainType.XDomain}
dataValues={messageData}
marker={<EuiIcon type="tableDensityNormal" />}
markerPosition={Position.Top}
style={{
line: {
strokeWidth: 3,
stroke: euiTheme.euiColorAccent,
opacity: 0.5,
},
}}
/>
</>
) : null}
<LineSeries
key={'source-results'}
color={euiTheme.euiColorPrimary}
id={i18n.translate('xpack.ml.jobsList.datafeedChart.sourceSeriesId', {
defaultMessage: 'Source indices',
})}
xScaleType={ScaleType.Time}
yScaleType={ScaleType.Linear}
xAccessor={0}
yAccessors={[1]}
data={sourceData}
curve={CurveType.LINEAR}
/>
<LineSeries
key={'job-results'}
color={euiTheme.euiColorAccentText}
id={i18n.translate('xpack.ml.jobsList.datafeedChart.bucketSeriesId', {
defaultMessage: 'Job results',
})}
xScaleType={ScaleType.Time}
yScaleType={ScaleType.Linear}
xAccessor={0}
yAccessors={[1]}
data={bucketData}
curve={CurveType.LINEAR}
/>
</Chart>
</div>
</EuiFlexItem>
<EuiFlexItem grow={false}>
<EuiToolTip

View file

@ -185,6 +185,29 @@ export default function ({ getService }: FtrProviderContext) {
});
});
describe('data feed flyout', function () {
const annotationId = `data-feed-flyout-annotation-id-${Date.now()}`;
before(async () => {
await ml.api.indexAnnotation(annotation as Partial<Annotation>, annotationId);
});
it('displays delayed data chart for annotation', async () => {
await ml.testExecution.logTestStep(
'should display delayed data action in annotations table'
);
await ml.navigation.navigateToMl();
await ml.navigation.navigateToJobManagement();
await ml.jobTable.waitForJobsToLoad();
await ml.jobTable.filterWithSearchString(jobId, 1);
await ml.jobTable.openAnnotationsTab(jobId);
await ml.jobAnnotations.openDatafeedChartFlyout(annotationId, jobId);
await ml.jobAnnotations.assertDelayedDataChartExists();
});
});
describe('deleting', function () {
const annotationId = `delete-annotation-id-${Date.now()}`;

View file

@ -341,5 +341,51 @@ export function MachineLearningJobAnnotationsProvider({ getService }: FtrProvide
await this.setAnnotationText(text);
});
}
public async assertAnnotationsDelayedDataChartActionExists() {
await retry.tryForTime(1000, async () => {
await testSubjects.existOrFail('mlAnnotationsActionViewDatafeed');
});
}
public async ensureAllMenuPopoversClosed() {
await retry.tryForTime(5000, async () => {
await browser.pressKeys(browser.keys.ESCAPE);
const popoverExists = await find.existsByCssSelector('euiContextMenuPanel');
expect(popoverExists).to.eql(false, 'All popovers should be closed');
});
}
public async ensureAnnotationsActionsMenuOpen(annotationId: string) {
await retry.tryForTime(10 * 1000, async () => {
await this.ensureAllMenuPopoversClosed();
await testSubjects.click(
`mlAnnotationsTableRow row-${annotationId} > euiCollapsedItemActionsButton`,
30 * 1000
);
await find.existsByCssSelector('euiContextMenuPanel');
});
}
public async openDatafeedChartFlyout(annotationId: string, jobId: string) {
await retry.tryForTime(10 * 1000, async () => {
await this.ensureAnnotationsActionsMenuOpen(annotationId);
await this.assertAnnotationsDelayedDataChartActionExists();
await testSubjects.clickWhenNotDisabled('mlAnnotationsActionViewDatafeed');
await testSubjects.existOrFail('mlAnnotationsViewDatafeedFlyout');
await testSubjects.existOrFail('mlAnnotationsViewDatafeedFlyoutTitle');
const title = await testSubjects.getVisibleText('mlAnnotationsViewDatafeedFlyoutTitle');
expect(title).to.eql(
`Datafeed chart for ${jobId}`,
`Expected annotations flyout title to be 'Datafeed chart for ${jobId}' but got ${title}`
);
});
}
public async assertDelayedDataChartExists() {
await testSubjects.existOrFail('mlAnnotationsViewDatafeedFlyoutChart');
}
})();
}