mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[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:
parent
91910dbecd
commit
63db90b0c4
3 changed files with 193 additions and 121 deletions
|
@ -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
|
||||
|
|
|
@ -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()}`;
|
||||
|
||||
|
|
|
@ -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');
|
||||
}
|
||||
})();
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue