[Uptime] [Overview Page] Only render up/down drawer badges when items > 1 (#88524)

* Only render location status badge when there are actually locations to display.

* Add aria-label to describe location section.

* Update test data to reflect real-world data better. Refactor enzyme tests.

* Refactor component test.

* Fix test names.

Co-authored-by: Kibana Machine <42973632+kibanamachine@users.noreply.github.com>
This commit is contained in:
Justin Kambic 2021-01-19 17:51:10 -05:00 committed by GitHub
parent 5f53b649c6
commit 4af5c117fa
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 186 additions and 240 deletions

View file

@ -1,97 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`MonitorStatusList component renders checks 1`] = `
<Fragment>
<EuiFlexGroup
style={
Object {
"maxWidth": 1000,
}
}
>
<EuiFlexItem>
<MonitorStatusRow
locationNames={
Set {
"Unnamed-location",
}
}
status="down"
/>
</EuiFlexItem>
<EuiFlexItem>
<MonitorStatusRow
locationNames={Set {}}
status="up"
/>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer
size="s"
/>
<EuiCallOut
color="warning"
>
<FormattedMessage
defaultMessage="Some heartbeat instances do not have a location defined. {link} to your heartbeat configuration."
id="xpack.uptime.monitorList.drawer.missingLocation"
values={
Object {
"link": <LocationLink />,
}
}
/>
</EuiCallOut>
<EuiSpacer
size="s"
/>
</Fragment>
`;
exports[`MonitorStatusList component renders null in place of child status with missing ip 1`] = `
<Fragment>
<EuiFlexGroup
style={
Object {
"maxWidth": 1000,
}
}
>
<EuiFlexItem>
<MonitorStatusRow
locationNames={
Set {
"Unnamed-location",
}
}
status="down"
/>
</EuiFlexItem>
<EuiFlexItem>
<MonitorStatusRow
locationNames={Set {}}
status="up"
/>
</EuiFlexItem>
</EuiFlexGroup>
<EuiSpacer
size="s"
/>
<EuiCallOut
color="warning"
>
<FormattedMessage
defaultMessage="Some heartbeat instances do not have a location defined. {link} to your heartbeat configuration."
id="xpack.uptime.monitorList.drawer.missingLocation"
values={
Object {
"link": <LocationLink />,
}
}
/>
</EuiCallOut>
<EuiSpacer
size="s"
/>
</Fragment>
`;

View file

@ -1,31 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`MonitorStatusRow component renders status row when status is down 1`] = `
<span>
<EuiBadge
color="danger"
/>
<EuiSpacer
size="xs"
/>
Berlin, Islamabad, London
<EuiSpacer
size="xs"
/>
</span>
`;
exports[`MonitorStatusRow component renders status row when status is up 1`] = `
<span>
<EuiBadge
color="danger"
/>
<EuiSpacer
size="xs"
/>
Berlin, Islamabad, London
<EuiSpacer
size="xs"
/>
</span>
`;

View file

@ -4,11 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { shallowWithIntl } from '@kbn/test/jest';
import React from 'react';
import { MonitorStatusList } from './monitor_status_list';
import { Ping } from '../../../../../common/runtime_types';
import { mockMoment } from '../../../../lib/helper/test_helpers';
import { render } from '../../../../lib/helper/rtl_helpers';
describe('MonitorStatusList component', () => {
let pings: Ping[];
@ -34,51 +34,6 @@ describe('MonitorStatusList component', () => {
},
timestamp: '1570538236414',
},
{
docId: '2',
monitor: {
ip: '151.101.194.217',
name: 'elastic',
status: 'up',
id: 'myMonitor',
type: 'icmp',
duration: { us: 123 },
},
observer: {
geo: {},
},
timestamp: '1570538236414',
},
{
docId: '3',
monitor: {
ip: '151.101.2.217',
name: 'elastic',
status: 'up',
id: 'myMonitor',
type: 'icmp',
duration: { us: 123 },
},
observer: {
geo: {},
},
timestamp: '1570538236414',
},
{
docId: '4',
monitor: {
ip: '151.101.66.217',
name: 'elastic',
status: 'up',
id: 'myMonitor',
type: 'icmp',
duration: { us: 123 },
},
observer: {
geo: {},
},
timestamp: '1570538236414',
},
{
docId: '4',
monitor: {
@ -95,60 +50,168 @@ describe('MonitorStatusList component', () => {
timestamp: '1570538236414',
},
{
docId: '5',
docId: '8',
monitor: {
ip: '2a04:4e42:400::729',
name: 'elastic',
status: 'down',
id: 'myMonitor',
ip: '8c94:2b92::132',
name: 'upMonitor',
status: 'up',
id: 'myUpMonitor',
type: 'icmp',
duration: { us: 123 },
duration: { us: 234 },
},
observer: {
geo: {},
geo: {
name: 'fairbanks',
},
},
timestamp: '1570538236414',
},
{
docId: '6',
monitor: {
ip: '2a04:4e42:600::729',
name: 'elastic',
status: 'down',
id: 'myMonitor',
type: 'icmp',
duration: { us: 123 },
},
observer: {
geo: {},
},
timestamp: '1570538236414',
},
{
docId: '5',
monitor: {
ip: '2a04:4e42::729',
name: 'elastic',
status: 'down',
id: 'myMonitor',
type: 'icmp',
duration: { us: 123 },
},
observer: {
geo: {},
},
timestamp: '1570538236414',
timestamp: '1570538235890',
},
];
});
it('renders checks', () => {
const component = shallowWithIntl(<MonitorStatusList summaryPings={pings} />);
expect(component).toMatchSnapshot();
it.each(['up', 'down'])(
'renders call out for monitor location if monitors have no location',
(status) => {
const { getByRole, getByText } = render(
<MonitorStatusList
summaryPings={pings.map((ping) => {
// test only up, only down
ping.monitor.status = status;
return ping;
})}
/>
);
getByText('Some heartbeat instances do not have a location defined.', {
// contains other elements/text
exact: false,
});
const docsLink = getByRole('link');
expect(docsLink.getAttribute('href')).toContain('https://www.elastic.co');
}
);
it('does not render call out for monitor location if all monitors have location', () => {
const { queryByRole, queryByText } = render(
<MonitorStatusList
summaryPings={pings.map((ping) => ({
...ping,
...{ observer: { geo: { name: 'test-name' } } },
}))}
/>
);
expect(
queryByText('Some heartbeat instances do not have a location defined.', { exact: false })
).toBeNull();
expect(queryByRole('link')).toBeNull();
});
it('renders null in place of child status with missing ip', () => {
const component = shallowWithIntl(<MonitorStatusList summaryPings={pings} />);
expect(component).toMatchSnapshot();
it.each([
[
'up',
'Up',
'A list of locations with "up" status when last checked.',
'Down',
'A list of locations with "down" status when last checked.',
],
[
'down',
'Down',
'A list of locations with "down" status when last checked.',
'Up',
'A list of locations with "up" status when last checked.',
],
])(
'renders only up badge when there are no down checks',
(
statusToFilter,
statusText,
expectedLabel,
expectedMissingStatusText,
expectedMissingLabel
) => {
const { getByText, getByLabelText, queryByText, queryByLabelText } = render(
<MonitorStatusList
summaryPings={pings.filter(({ monitor: { status } }) => status === statusToFilter)}
/>
);
expect(getByText(statusText));
expect(getByLabelText(expectedLabel));
expect(queryByText(expectedMissingStatusText)).toBeNull();
expect(queryByLabelText(expectedMissingLabel)).toBeNull();
}
);
it('displays badges for up and down locations when the results are mixed', () => {
const { getByText, getByLabelText } = render(<MonitorStatusList summaryPings={pings} />);
expect(getByText('Up'));
expect(getByLabelText('A list of locations with "up" status when last checked.'));
expect(getByText('fairbanks'));
expect(getByText('Down'));
expect(getByLabelText('A list of locations with "down" status when last checked.'));
expect(getByText('Unnamed-location'));
});
it('displays a location as "down" if any summary checks are down', () => {
const newlyUpPings = [
{
docId: '100',
monitor: {
ip: '8c94:2b92::132',
name: 'monitor',
status: 'down',
id: 'myMonitor',
type: 'icmp',
duration: { us: 234 },
},
observer: {
geo: {
name: 'fairbanks',
},
},
timestamp: '1570538235890',
},
{
docId: '101',
monitor: {
ip: '8c94:2b92::132',
name: 'monitor',
status: 'down',
id: 'myMonitor',
type: 'icmp',
duration: { us: 234 },
},
observer: {
geo: {
name: 'fairbanks',
},
},
timestamp: '1570538236890',
},
{
docId: '101',
monitor: {
ip: '8c94:2b92::132',
name: 'monitor',
status: 'up',
id: 'myMonitor',
type: 'icmp',
duration: { us: 234 },
},
observer: {
geo: {
name: 'fairbanks',
},
},
timestamp: '1570538237890',
},
];
const { getByText, getByLabelText } = render(<MonitorStatusList summaryPings={newlyUpPings} />);
expect(getByText('Down'));
const locationContainer = getByLabelText(
'A list of locations with "down" status when last checked.'
);
expect(locationContainer.innerHTML).toBe('fairbanks');
});
});

View file

@ -40,12 +40,16 @@ export const MonitorStatusList = ({ summaryPings }: MonitorStatusListProps) => {
return (
<>
<EuiFlexGroup style={{ maxWidth: 1000 }}>
<EuiFlexItem>
<MonitorStatusRow locationNames={downChecks} status={STATUS.DOWN} />
</EuiFlexItem>
<EuiFlexItem>
<MonitorStatusRow locationNames={absUpChecks} status={STATUS.UP} />
</EuiFlexItem>
{downChecks.size > 0 && (
<EuiFlexItem>
<MonitorStatusRow locationNames={downChecks} status={STATUS.DOWN} />
</EuiFlexItem>
)}
{absUpChecks.size > 0 && (
<EuiFlexItem>
<MonitorStatusRow locationNames={absUpChecks} status={STATUS.UP} />
</EuiFlexItem>
)}
</EuiFlexGroup>
{(downChecks.has(UNNAMED_LOCATION) || upChecks.has(UNNAMED_LOCATION)) && (
<>

View file

@ -4,28 +4,27 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { shallowWithIntl } from '@kbn/test/jest';
import React from 'react';
import { render } from '../../../../lib/helper/rtl_helpers';
import { MonitorStatusRow } from './monitor_status_row';
describe('MonitorStatusRow component', () => {
let locationNames: Set<string>;
it.each(['Up'])('renders status row when status is up', (expectedStatus) => {
const locationNames = new Set(['Berlin', 'Islamabad', 'London']);
const { getByLabelText } = render(
<MonitorStatusRow locationNames={locationNames} status={expectedStatus} />
);
beforeEach(() => {
locationNames = new Set(['Berlin', 'Islamabad', 'London']);
const locationElement = getByLabelText(
`A list of locations with "${expectedStatus}" status when last checked.`
);
expect(locationElement.innerHTML).toBe('Berlin, Islamabad, London');
});
it('renders status row when status is up', () => {
const component = shallowWithIntl(
<MonitorStatusRow locationNames={locationNames} status={'Up'} />
);
expect(component).toMatchSnapshot();
});
it('renders an empty set string', () => {
const { getByText } = render(<MonitorStatusRow locationNames={new Set()} status="Down" />);
it('renders status row when status is down', () => {
const component = shallowWithIntl(
<MonitorStatusRow locationNames={locationNames} status={'Down'} />
);
expect(component).toMatchSnapshot();
expect(getByText('--'));
});
});

View file

@ -5,6 +5,7 @@
*/
import React from 'react';
import { i18n } from '@kbn/i18n';
import { EuiBadge, EuiSpacer } from '@elastic/eui';
import { UNNAMED_LOCATION, STATUS } from '../../../../../common/constants';
import { getHealthMessage } from '../columns/monitor_status_column';
@ -35,7 +36,14 @@ export const MonitorStatusRow = ({ locationNames, status }: MonitorStatusRowProp
<span>
<EuiBadge color={color}>{getHealthMessage(status)}</EuiBadge>
<EuiSpacer size="xs" />
{locations || '--'}
<span
aria-label={i18n.translate('xpack.uptime.monitorList.drawer.statusRowLocationList', {
defaultMessage: 'A list of locations with "{status}" status when last checked.',
values: { status },
})}
>
{locations || '--'}
</span>
<EuiSpacer size="xs" />
</span>
);