From 9813dbf78ddc28e174ee8cfb7c89c566dc105baf Mon Sep 17 00:00:00 2001 From: Chris Cowan Date: Wed, 10 Jun 2020 13:27:16 -0700 Subject: [PATCH] [7.8] [Metrics UI] Fix fatal error when no data is available for Metric Threshold Alerts (#68678) (#68759) * [Metrics UI] Fix fatal error when no data is available for Metric Threshold Alerts (#68678) * [Metrics UI] Fix fatal error when no data is available for Metric Threshold Alerts * Adding i18n support for error message * Adding test * Fixing tests --- .../components/expression_chart.test.tsx | 119 ++++++++++++++++++ .../components/expression_chart.tsx | 9 +- 2 files changed, 126 insertions(+), 2 deletions(-) create mode 100644 x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.test.tsx diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.test.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.test.tsx new file mode 100644 index 0000000000000..71a467e4841dc --- /dev/null +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.test.tsx @@ -0,0 +1,119 @@ +/* + * Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one + * or more contributor license agreements. Licensed under the Elastic License; + * you may not use this file except in compliance with the Elastic License. + */ + +import { mountWithIntl, nextTick } from 'test_utils/enzyme_helpers'; +import { actionTypeRegistryMock } from '../../../../../triggers_actions_ui/public/application/action_type_registry.mock'; +import { alertTypeRegistryMock } from '../../../../../triggers_actions_ui/public/application/alert_type_registry.mock'; +import { coreMock } from '../../../../../../../src/core/public/mocks'; +import { AlertsContextValue } from '../../../../../triggers_actions_ui/public/application/context/alerts_context'; +import { AlertContextMeta, MetricExpression } from '../types'; +import { IIndexPattern } from 'src/plugins/data/public'; +import { InfraSource } from '../../../../common/http_api/source_api'; +import React from 'react'; +import { ExpressionChart } from './expression_chart'; +import { act } from 'react-dom/test-utils'; +// eslint-disable-next-line @kbn/eslint/no-restricted-paths +import { Aggregators, Comparator } from '../../../../server/lib/alerting/metric_threshold/types'; +import { MetricsExplorerResponse } from '../../../../common/http_api'; + +describe('ExpressionChart', () => { + async function setup( + expression: MetricExpression, + response: MetricsExplorerResponse | null, + filterQuery?: string, + groupBy?: string + ) { + const mocks = coreMock.createSetup(); + const [ + { + application: { capabilities }, + }, + ] = await mocks.getStartServices(); + + const context: AlertsContextValue = { + http: mocks.http, + toastNotifications: mocks.notifications.toasts, + actionTypeRegistry: actionTypeRegistryMock.create() as any, + alertTypeRegistry: alertTypeRegistryMock.create() as any, + docLinks: {} as any, + capabilities: { + ...capabilities, + actions: { + delete: true, + save: true, + show: true, + }, + }, + }; + const derivedIndexPattern: IIndexPattern = { + title: 'metricbeat-*', + fields: [], + }; + + const source: InfraSource = { + id: 'default', + origin: 'fallback', + configuration: { + name: 'default', + description: 'The default configuration', + logColumns: [], + metricAlias: 'metricbeat-*', + logAlias: 'filebeat-*', + fields: { + timestamp: '@timestamp', + message: ['message'], + container: 'container.id', + host: 'host.name', + pod: 'kubernetes.pod.uid', + tiebreaker: '_doc', + }, + }, + }; + + mocks.http.fetch.mockImplementation(() => Promise.resolve(response)); + + const wrapper = mountWithIntl( + + ); + + const update = async () => + await act(async () => { + await nextTick(); + wrapper.update(); + }); + + await update(); + + return { wrapper, update, fetchMock: mocks.http.fetch }; + } + + it('should display no data message', async () => { + const expression: MetricExpression = { + aggType: Aggregators.AVERAGE, + timeSize: 1, + timeUnit: 'm', + sourceId: 'default', + threshold: [1], + comparator: Comparator.GT_OR_EQ, + }; + const response = { + pageInfo: { + afterKey: null, + total: 0, + }, + series: [{ id: 'Everything', rows: [], columns: [] }], + }; + const { wrapper } = await setup(expression, response); + expect(wrapper.find('[data-test-subj~="noChartData"]').exists()).toBeTruthy(); + }); +}); diff --git a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.tsx b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.tsx index cc6af42651f5e..035404c55ded9 100644 --- a/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.tsx +++ b/x-pack/plugins/infra/public/alerting/metric_threshold/components/expression_chart.tsx @@ -108,10 +108,15 @@ export const ExpressionChart: React.FC = ({ // Creating a custom series where the ID is changed to 0 // so that we can get a proper domian const firstSeries = first(data.series); - if (!firstSeries) { + if (!firstSeries || !firstSeries.rows || firstSeries.rows.length === 0) { return ( - Oops, no chart data available + + + ); }