[Uptime] Add tests for new waterfall components (#115856)

* Add `aria-label`s for icon and icon buttons.

* Fix typo.

* Create test wrapper to help with testing context-reliant components.

* Create tests for `WaterfallMarkerIcon` component.

* Create tests for `WaterfallMarkerTrend` component.

* Simplify test wrapper.

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Justin Kambic 2021-10-26 09:59:01 -04:00 committed by GitHub
parent 9c92ac881a
commit 063e30b6a8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 266 additions and 5 deletions

View file

@ -0,0 +1,58 @@
/*
* 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 React from 'react';
import { fireEvent, waitFor } from '@testing-library/dom';
import { render } from '../../../../../lib/helper/rtl_helpers';
import { WaterfallMarkerIcon } from './waterfall_marker_icon';
import { TestWrapper } from './waterfall_marker_test_helper';
describe('<WaterfallMarkerIcon />', () => {
it('renders a dot icon when `field` is an empty string', () => {
const { getByLabelText } = render(<WaterfallMarkerIcon field="" label="" />);
expect(getByLabelText('An icon indicating that this marker has no field associated with it'));
});
it('renders an embeddable when opened', async () => {
const { getByLabelText, getByText } = render(
<TestWrapper
activeStep={{
'@timestamp': '123',
_id: 'id',
synthetics: {
type: 'step/end',
step: {
index: 0,
name: 'test-name',
},
},
monitor: {
id: 'mon-id',
check_group: 'group',
timespan: {
gte: '1988-10-09T12:00:00.000Z',
lt: '1988-10-10T12:00:00.000Z',
},
},
}}
basePath="xyz"
>
<WaterfallMarkerIcon field="testField" label="Test Field" />
</TestWrapper>
);
const expandButton = getByLabelText(
'Use this icon button to show metrics for this annotation marker.'
);
fireEvent.click(expandButton);
await waitFor(() => {
getByText('Test Field');
});
});
});

View file

@ -6,6 +6,7 @@
*/
import React, { useState } from 'react';
import { i18n } from '@kbn/i18n';
import { EuiButtonIcon, EuiIcon, EuiPopover } from '@elastic/eui';
import { WaterfallMarkerTrend } from './waterfall_marker_trend';
@ -13,7 +14,15 @@ export function WaterfallMarkerIcon({ field, label }: { field: string; label: st
const [isOpen, setIsOpen] = useState(false);
if (!field) {
return <EuiIcon type="dot" size="l" />;
return (
<EuiIcon
aria-label={i18n.translate('xpack.uptime.synthetics.markers.noFieldIcon.label', {
defaultMessage: 'An icon indicating that this marker has no field associated with it',
})}
type="dot"
size="l"
/>
);
}
return (
@ -25,6 +34,9 @@ export function WaterfallMarkerIcon({ field, label }: { field: string; label: st
zIndex={100}
button={
<EuiButtonIcon
aria-label={i18n.translate('xpack.uptime.synthetics.markers.openEmbeddableButton.label', {
defaultMessage: 'Use this icon button to show metrics for this annotation marker.',
})}
iconType="dot"
iconSize="l"
color="text"

View file

@ -0,0 +1,59 @@
/*
* 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 React from 'react';
import { UptimeStartupPluginsContext } from '../../../../../contexts';
import { WaterfallContext } from '../context/waterfall_chart';
import { JourneyStep } from '../../../../../../common/runtime_types';
const EmbeddableMock = ({
title,
appendTitle,
reportType,
attributes,
}: {
title: string;
appendTitle: JSX.Element | undefined;
reportType: string;
attributes: unknown;
axisTitlesVisibility: { x: boolean; yLeft: boolean; yRight: boolean };
legendIsVisible: boolean;
}) => (
<div>
<h1>{title}</h1>
<div aria-label="append title">{appendTitle}</div>
<div>{reportType}</div>
<div aria-label="attributes">{JSON.stringify(attributes)}</div>
</div>
);
export const TestWrapper = ({
basePath,
activeStep,
children,
}: {
basePath: string;
activeStep?: JourneyStep;
children: JSX.Element;
}) => (
<UptimeStartupPluginsContext.Provider
value={{
// @ts-expect-error incomplete implementation for test purposes
observability: {
ExploratoryViewEmbeddable: jest.fn((props: any) => <EmbeddableMock {...props} />),
},
}}
>
<WaterfallContext.Provider
value={{
activeStep,
}}
>
{children}
</WaterfallContext.Provider>
</UptimeStartupPluginsContext.Provider>
);

View file

@ -0,0 +1,132 @@
/*
* 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 React from 'react';
import { render } from '../../../../../lib/helper/rtl_helpers';
import { WaterfallMarkerTrend } from './waterfall_marker_trend';
import moment from 'moment';
import { JourneyStep } from '../../../../../../common/runtime_types';
import { TestWrapper } from './waterfall_marker_test_helper';
describe('<WaterfallMarkerTrend />', () => {
const mockDiff = jest.fn();
jest.spyOn(moment.prototype, 'diff').mockImplementation(mockDiff);
let activeStep: JourneyStep | undefined;
beforeEach(() => {
activeStep = {
'@timestamp': '123',
_id: 'id',
synthetics: {
type: 'step/end',
step: {
index: 0,
name: 'test-name',
},
},
monitor: {
id: 'mon-id',
check_group: 'group',
timespan: {
gte: '1988-10-09T12:00:00.000Z',
lt: '1988-10-10T12:00:00.000Z',
},
},
};
mockDiff.mockReturnValue(0);
});
const BASE_PATH = 'xyz';
it('supplies props', () => {
const { getByLabelText, getByText, getByRole } = render(
<TestWrapper activeStep={activeStep} basePath={BASE_PATH}>
<WaterfallMarkerTrend title="test title" field="field" />
</TestWrapper>,
{
core: {
http: {
// @ts-expect-error incomplete implementation for testing purposes
basePath: {
get: () => BASE_PATH,
},
},
},
}
);
const heading = getByRole('heading');
expect(heading.innerHTML).toEqual('test title');
expect(getByLabelText('append title').innerHTML.indexOf(BASE_PATH)).not.toBe(-1);
expect(getByText('kpi-over-time'));
expect(getByLabelText('attributes').innerHTML.indexOf('0s')).not.toBe(-1);
expect(getByLabelText('attributes').innerHTML.indexOf('0h')).toBe(-1);
expect(getByLabelText('attributes').innerHTML.indexOf('0m')).toBe(-1);
expect(getByLabelText('attributes').innerHTML.indexOf('0d')).toBe(-1);
});
it('handles days', () => {
mockDiff.mockReturnValue(10);
const { getByLabelText } = render(
<TestWrapper activeStep={activeStep} basePath={BASE_PATH}>
<WaterfallMarkerTrend title="test title" field="field" />
</TestWrapper>
);
const attributesText = getByLabelText('attributes').innerHTML;
expect(attributesText.indexOf('480s')).toBe(-1);
expect(attributesText.indexOf('480h')).toBe(-1);
expect(attributesText.indexOf('480m')).toBe(-1);
expect(attributesText.indexOf('480d')).not.toBe(-1);
});
it('handles hours', () => {
mockDiff.mockReturnValueOnce(0);
mockDiff.mockReturnValue(10);
const { getByLabelText } = render(
<TestWrapper activeStep={activeStep} basePath={BASE_PATH}>
<WaterfallMarkerTrend title="test title" field="field" />
</TestWrapper>
);
const attributesText = getByLabelText('attributes').innerHTML;
expect(attributesText.indexOf('480s')).toBe(-1);
expect(attributesText.indexOf('480h')).not.toBe(-1);
expect(attributesText.indexOf('480m')).toBe(-1);
expect(attributesText.indexOf('480d')).toBe(-1);
});
it('handles minutes', () => {
mockDiff.mockReturnValueOnce(0);
mockDiff.mockReturnValueOnce(0);
mockDiff.mockReturnValue(10);
const { getByLabelText } = render(
<TestWrapper activeStep={activeStep} basePath={BASE_PATH}>
<WaterfallMarkerTrend title="test title" field="field" />
</TestWrapper>
);
const attributesText = getByLabelText('attributes').innerHTML;
expect(attributesText.indexOf('480s')).toBe(-1);
expect(attributesText.indexOf('480h')).toBe(-1);
expect(attributesText.indexOf('480m')).not.toBe(-1);
expect(attributesText.indexOf('480d')).toBe(-1);
});
it('returns null for missing active step', () => {
activeStep = undefined;
const { container } = render(
<TestWrapper activeStep={activeStep} basePath={BASE_PATH}>
<WaterfallMarkerTrend title="test title" field="field" />
</TestWrapper>
);
expect(container.innerHTML).toBe('');
});
});

View file

@ -9,8 +9,8 @@ import React from 'react';
import { EuiButton } from '@elastic/eui';
import { i18n } from '@kbn/i18n';
import moment from 'moment';
import { useKibana } from '../../../../../../../../../src/plugins/kibana_react/public';
import { useUptimeStartPlugins } from '../../../../../contexts/uptime_startup_plugins_context';
import { useUptimeSettingsContext } from '../../../../../contexts/uptime_settings_context';
import { AllSeries, createExploratoryViewUrl } from '../../../../../../../observability/public';
import { euiStyled } from '../../../../../../../../../src/plugins/kibana_react/common';
import { useWaterfallContext } from '../context/waterfall_chart';
@ -40,9 +40,9 @@ const getLast48Intervals = (activeStep: JourneyStep) => {
export function WaterfallMarkerTrend({ title, field }: { title: string; field: string }) {
const { observability } = useUptimeStartPlugins();
const EmbeddableExpVIew = observability!.ExploratoryViewEmbeddable;
const EmbeddableExpView = observability!.ExploratoryViewEmbeddable;
const { basePath } = useUptimeSettingsContext();
const basePath = useKibana().services.http?.basePath?.get();
const { activeStep } = useWaterfallContext();
@ -75,7 +75,7 @@ export function WaterfallMarkerTrend({ title, field }: { title: string; field: s
return (
<Wrapper>
<EmbeddableExpVIew
<EmbeddableExpView
title={title}
appendTitle={
<EuiButton iconType={'visArea'} href={href} target="_blank" size="s">