[Uptime] Added tests for pages (#56736)

* added test for pages

* fixed types

* update types

* update snap

* PR feedback

* PR feedback
This commit is contained in:
Shahzad 2020-02-11 22:48:22 +01:00 committed by GitHub
parent f305fe0168
commit 5bfbf5f530
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
30 changed files with 1916 additions and 224 deletions

View file

@ -4,6 +4,10 @@
* you may not use this file except in compliance with the Elastic License.
*/
export const MONITOR_ROUTE = '/monitor/:monitorId?';
export const OVERVIEW_ROUTE = '/';
export enum STATUS {
UP = 'up',
DOWN = 'down',

View file

@ -7,7 +7,6 @@
export { PingHistogram } from './charts/ping_histogram';
export { Snapshot } from './charts/snapshot_container';
export { KueryBar } from './kuerybar/kuery_bar_container';
export { OverviewPage } from './pages/overview_container';
export { FilterGroup } from './filter_group/filter_group_container';
export { MonitorStatusDetails } from './monitor/status_details_container';
export { MonitorStatusBar } from './monitor/status_bar_container';

View file

@ -0,0 +1,16 @@
/*
* 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 { connect } from 'react-redux';
import { selectSelectedMonitor } from '../../../state/selectors';
import { AppState } from '../../../state';
import { PageHeaderComponent } from '../../../pages/page_header';
const mapStateToProps = (state: AppState) => ({
monitorStatus: selectSelectedMonitor(state),
});
export const PageHeader = connect(mapStateToProps, null)(PageHeaderComponent);

View file

@ -6,10 +6,9 @@
import React from 'react';
import DateMath from '@elastic/datemath';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { MonitorChartsComponent } from '../monitor_charts';
import { MonitorChart } from '../../../../common/graphql/types';
import { renderWithRouter } from '../../../lib';
import { shallowWithRouter } from '../../../lib';
describe('MonitorCharts component', () => {
let dateMathSpy: any;
@ -63,18 +62,16 @@ describe('MonitorCharts component', () => {
};
it('renders the component without errors', () => {
const component = shallowWithIntl(
renderWithRouter(
<MonitorChartsComponent
danger="dangerColor"
data={{ monitorChartsData: chartResponse.monitorChartsData }}
loading={false}
mean="mean"
range="range"
success="success"
monitorId="something"
/>
)
const component = shallowWithRouter(
<MonitorChartsComponent
danger="dangerColor"
data={{ monitorChartsData: chartResponse.monitorChartsData }}
loading={false}
mean="mean"
range="range"
success="success"
monitorId="something"
/>
);
expect(component).toMatchSnapshot();
});

View file

@ -4,19 +4,18 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { shallowWithIntl, renderWithIntl } from 'test_utils/enzyme_helpers';
import React from 'react';
import { UptimeDatePicker } from '../uptime_date_picker';
import { renderWithRouter } from '../../../lib';
import { renderWithRouter, shallowWithRouter } from '../../../lib';
describe('UptimeDatePicker component', () => {
it('validates props with shallow render', () => {
const component = shallowWithIntl(renderWithRouter(<UptimeDatePicker />));
const component = shallowWithRouter(<UptimeDatePicker />);
expect(component).toMatchSnapshot();
});
it('renders properly with mock data', () => {
const component = renderWithIntl(renderWithRouter(<UptimeDatePicker />));
const component = renderWithRouter(<UptimeDatePicker />);
expect(component).toMatchSnapshot();
});
});

View file

@ -5,9 +5,8 @@
*/
import React from 'react';
import { renderWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers';
import { MonitorBarSeries, MonitorBarSeriesProps } from '../monitor_bar_series';
import { renderWithRouter } from '../../../../lib';
import { renderWithRouter, shallowWithRouter } from '../../../../lib';
import { SummaryHistogramPoint } from '../../../../../common/graphql/types';
describe('MonitorBarSeries component', () => {
@ -161,13 +160,13 @@ describe('MonitorBarSeries component', () => {
});
it('shallow renders a series when there are down items', () => {
const component = shallowWithIntl(renderWithRouter(<MonitorBarSeries {...props} />));
const component = shallowWithRouter(<MonitorBarSeries {...props} />);
expect(component).toMatchSnapshot();
});
it('shallow renders null when there are no down items', () => {
props.histogramSeries = [];
const component = shallowWithIntl(renderWithRouter(<MonitorBarSeries {...props} />));
const component = shallowWithRouter(<MonitorBarSeries {...props} />);
expect(component).toEqual({});
});
@ -189,20 +188,20 @@ describe('MonitorBarSeries component', () => {
up: 0,
},
];
const component = shallowWithIntl(renderWithRouter(<MonitorBarSeries {...props} />));
const component = shallowWithRouter(<MonitorBarSeries {...props} />);
expect(component).toEqual({});
});
it('shallow renders nothing if the data series is null', () => {
const component = shallowWithIntl(
renderWithRouter(<MonitorBarSeries dangerColor="danger" histogramSeries={null} />)
const component = shallowWithRouter(
<MonitorBarSeries dangerColor="danger" histogramSeries={null} />
);
expect(component).toEqual({});
});
it('renders if the data series is present', () => {
const component = renderWithIntl(
renderWithRouter(<MonitorBarSeries dangerColor="danger" histogramSeries={histogramSeries} />)
const component = renderWithRouter(
<MonitorBarSeries dangerColor="danger" histogramSeries={histogramSeries} />
);
expect(component).toMatchSnapshot();
});

View file

@ -5,9 +5,8 @@
*/
import React from 'react';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import { FilterStatusButton, FilterStatusButtonProps } from '../filter_status_button';
import { renderWithRouter } from '../../../../lib/';
import { shallowWithRouter } from '../../../../lib/';
describe('FilterStatusButton', () => {
let props: FilterStatusButtonProps;
@ -21,7 +20,7 @@ describe('FilterStatusButton', () => {
});
it('renders without errors for valid props', () => {
const wrapper = shallowWithIntl(renderWithRouter(<FilterStatusButton {...props} />));
const wrapper = shallowWithRouter(<FilterStatusButton {...props} />);
expect(wrapper).toMatchSnapshot();
});
});

View file

@ -42,15 +42,15 @@ exports[`LocationMap component doesnt shows warning if geo is provided 1`] = `
}
/>
</Styled(EuiFlexItem)>
<EuiFlexItem
grow={false}
<EuiHideFor
sizes={
Array [
"xs",
]
}
>
<EuiHideFor
sizes={
Array [
"xs",
]
}
<EuiFlexItem
grow={false}
>
<styled.div>
<EmbeddedMap
@ -69,8 +69,8 @@ exports[`LocationMap component doesnt shows warning if geo is provided 1`] = `
}
/>
</styled.div>
</EuiHideFor>
</EuiFlexItem>
</EuiFlexItem>
</EuiHideFor>
</Styled(EuiFlexGroup)>
</EuiErrorBoundary>
`;
@ -127,15 +127,15 @@ exports[`LocationMap component renders correctly against snapshot 1`] = `
}
/>
</Styled(EuiFlexItem)>
<EuiFlexItem
grow={false}
<EuiHideFor
sizes={
Array [
"xs",
]
}
>
<EuiHideFor
sizes={
Array [
"xs",
]
}
<EuiFlexItem
grow={false}
>
<LocationMissingWarning />
<styled.div>
@ -155,8 +155,8 @@ exports[`LocationMap component renders correctly against snapshot 1`] = `
}
/>
</styled.div>
</EuiHideFor>
</EuiFlexItem>
</EuiFlexItem>
</EuiHideFor>
</Styled(EuiFlexGroup)>
</EuiErrorBoundary>
`;
@ -186,15 +186,15 @@ exports[`LocationMap component renders named locations that have missing geo dat
}
/>
</Styled(EuiFlexItem)>
<EuiFlexItem
grow={false}
<EuiHideFor
sizes={
Array [
"xs",
]
}
>
<EuiHideFor
sizes={
Array [
"xs",
]
}
<EuiFlexItem
grow={false}
>
<LocationMissingWarning />
<styled.div>
@ -203,8 +203,8 @@ exports[`LocationMap component renders named locations that have missing geo dat
upPoints={Array []}
/>
</styled.div>
</EuiHideFor>
</EuiFlexItem>
</EuiFlexItem>
</EuiHideFor>
</Styled(EuiFlexGroup)>
</EuiErrorBoundary>
`;
@ -247,15 +247,15 @@ exports[`LocationMap component shows warning if geo information is missing 1`] =
}
/>
</Styled(EuiFlexItem)>
<EuiFlexItem
grow={false}
<EuiHideFor
sizes={
Array [
"xs",
]
}
>
<EuiHideFor
sizes={
Array [
"xs",
]
}
<EuiFlexItem
grow={false}
>
<LocationMissingWarning />
<styled.div>
@ -271,8 +271,8 @@ exports[`LocationMap component shows warning if geo information is missing 1`] =
}
/>
</styled.div>
</EuiHideFor>
</EuiFlexItem>
</EuiFlexItem>
</EuiHideFor>
</Styled(EuiFlexGroup)>
</EuiErrorBoundary>
`;

View file

@ -32,7 +32,6 @@ const EuiFlexItemTags = styled(EuiFlexItem)`
padding-top: 5px;
@media (max-width: 850px) {
order: 1;
text-align: center;
}
`;
@ -80,14 +79,14 @@ export const LocationMap = ({ monitorLocations }: LocationMapProps) => {
<EuiFlexItemTags>
<LocationStatusTags locations={monitorLocations?.locations || []} />
</EuiFlexItemTags>
<EuiFlexItem grow={false}>
<EuiHideFor sizes={['xs']}>
<EuiHideFor sizes={['xs']}>
<EuiFlexItem grow={false}>
{isGeoInfoMissing && <LocationMissingWarning />}
<MapPanel>
<EmbeddedMap upPoints={upPoints} downPoints={downPoints} />
</MapPanel>
</EuiHideFor>
</EuiFlexItem>
</EuiFlexItem>
</EuiHideFor>
</FlexGroup>
</EuiErrorBoundary>
);

View file

@ -4,7 +4,7 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { renderWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import React from 'react';
import { MonitorSummaryResult } from '../../../../../common/graphql/types';
import { MonitorListComponent } from '../monitor_list';
@ -110,16 +110,14 @@ describe('MonitorList component', () => {
});
it('renders the monitor list', () => {
const component = renderWithIntl(
renderWithRouter(
<MonitorListComponent
dangerColor="danger"
data={{ monitorStates: result }}
hasActiveFilters={false}
loading={false}
successColor="primary"
/>
)
const component = renderWithRouter(
<MonitorListComponent
dangerColor="danger"
data={{ monitorStates: result }}
hasActiveFilters={false}
loading={false}
successColor="primary"
/>
);
expect(component).toMatchSnapshot();

View file

@ -5,11 +5,10 @@
*/
import 'jest';
import { MonitorSummary, Check } from '../../../../../../common/graphql/types';
import { shallowWithIntl } from 'test_utils/enzyme_helpers';
import React from 'react';
import { MonitorListDrawerComponent } from '../monitor_list_drawer';
import { MonitorDetails } from '../../../../../../common/runtime_types';
import { renderWithRouter } from '../../../../../lib';
import { shallowWithRouter } from '../../../../../lib';
describe('MonitorListDrawer component', () => {
let summary: MonitorSummary;
@ -52,41 +51,35 @@ describe('MonitorListDrawer component', () => {
});
it('renders nothing when no summary data is present', () => {
const component = shallowWithIntl(
renderWithRouter(
<MonitorListDrawerComponent
loadMonitorDetails={loadMonitorDetails}
summary={summary}
monitorDetails={monitorDetails}
/>
)
const component = shallowWithRouter(
<MonitorListDrawerComponent
loadMonitorDetails={loadMonitorDetails}
summary={summary}
monitorDetails={monitorDetails}
/>
);
expect(component).toEqual({});
});
it('renders nothing when no check data is present', () => {
delete summary.state.checks;
const component = shallowWithIntl(
renderWithRouter(
<MonitorListDrawerComponent
summary={summary}
loadMonitorDetails={loadMonitorDetails}
monitorDetails={monitorDetails}
/>
)
const component = shallowWithRouter(
<MonitorListDrawerComponent
summary={summary}
loadMonitorDetails={loadMonitorDetails}
monitorDetails={monitorDetails}
/>
);
expect(component).toEqual({});
});
it('renders a MonitorListDrawer when there is only one check', () => {
const component = shallowWithIntl(
renderWithRouter(
<MonitorListDrawerComponent
summary={summary}
loadMonitorDetails={loadMonitorDetails}
monitorDetails={monitorDetails}
/>
)
const component = shallowWithRouter(
<MonitorListDrawerComponent
summary={summary}
loadMonitorDetails={loadMonitorDetails}
monitorDetails={monitorDetails}
/>
);
expect(component).toMatchSnapshot();
});
@ -116,14 +109,12 @@ describe('MonitorListDrawer component', () => {
},
];
summary.state.checks = checks;
const component = shallowWithIntl(
renderWithRouter(
<MonitorListDrawerComponent
summary={summary}
loadMonitorDetails={loadMonitorDetails}
monitorDetails={monitorDetails}
/>
)
const component = shallowWithRouter(
<MonitorListDrawerComponent
summary={summary}
loadMonitorDetails={loadMonitorDetails}
monitorDetails={monitorDetails}
/>
);
expect(component).toMatchSnapshot();
});

View file

@ -11,7 +11,7 @@ exports[`useUrlParams deletes keys that do not have truthy values 1`] = `
"entries": Array [
Object {
"hash": "",
"key": "test",
"key": "TestKeyForTesting",
"pathname": "/",
"search": "?g=%22%22&dateRangeStart=now-12&dateRangeEnd=now&pagination=foo",
"state": undefined,
@ -25,7 +25,7 @@ exports[`useUrlParams deletes keys that do not have truthy values 1`] = `
"listen": [Function],
"location": Object {
"hash": "",
"key": "test",
"key": "TestKeyForTesting",
"pathname": "/",
"search": "?g=%22%22&dateRangeStart=now-12&dateRangeEnd=now&pagination=foo",
"state": undefined,

View file

@ -4,12 +4,11 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { mountWithIntl } from 'test_utils/enzyme_helpers';
import DateMath from '@elastic/datemath';
import React, { useState, Fragment } from 'react';
import { useUrlParams, UptimeUrlParamsHook } from '../use_url_params';
import { UptimeRefreshContext } from '../../contexts';
import { renderWithRouter } from '../../lib';
import { mountWithRouter } from '../../lib';
import { createMemoryHistory } from 'history';
interface MockUrlParamsComponentProps {
@ -51,13 +50,11 @@ describe('useUrlParams', () => {
const history = createMemoryHistory();
jest.spyOn(history, 'push');
const component = mountWithIntl(
renderWithRouter(
<UptimeRefreshContext.Provider value={{ lastRefresh: 123, refreshApp: jest.fn() }}>
<UseUrlParamsTestComponent hook={useUrlParams} />
</UptimeRefreshContext.Provider>,
history
)
const component = mountWithRouter(
<UptimeRefreshContext.Provider value={{ lastRefresh: 123, refreshApp: jest.fn() }}>
<UseUrlParamsTestComponent hook={useUrlParams} />
</UptimeRefreshContext.Provider>,
history
);
const setUrlParamsButton = component.find('#setUrlParams');
@ -69,17 +66,15 @@ describe('useUrlParams', () => {
});
it('gets the expected values using the context', () => {
const component = mountWithIntl(
renderWithRouter(
<UptimeRefreshContext.Provider
value={{
lastRefresh: 123,
refreshApp: jest.fn(),
}}
>
<UseUrlParamsTestComponent hook={useUrlParams} />
</UptimeRefreshContext.Provider>
)
const component = mountWithRouter(
<UptimeRefreshContext.Provider
value={{
lastRefresh: 123,
refreshApp: jest.fn(),
}}
>
<UseUrlParamsTestComponent hook={useUrlParams} />
</UptimeRefreshContext.Provider>
);
const getUrlParamsButton = component.find('#getUrlParams');
@ -95,18 +90,16 @@ describe('useUrlParams', () => {
history.location.key = 'test';
jest.spyOn(history, 'push');
const component = mountWithIntl(
renderWithRouter(
<UptimeRefreshContext.Provider
value={{
lastRefresh: 123,
refreshApp: jest.fn(),
}}
>
<UseUrlParamsTestComponent hook={useUrlParams} updateParams={{ pagination: '' }} />
</UptimeRefreshContext.Provider>,
history
)
const component = mountWithRouter(
<UptimeRefreshContext.Provider
value={{
lastRefresh: 123,
refreshApp: jest.fn(),
}}
>
<UseUrlParamsTestComponent hook={useUrlParams} updateParams={{ pagination: '' }} />
</UptimeRefreshContext.Provider>,
history
);
const getUrlParamsButton = component.find('#getUrlParams');

View file

@ -4,18 +4,36 @@
* you may not use this file except in compliance with the Elastic License.
*/
import React from 'react';
import React, { ReactElement } from 'react';
import { Router } from 'react-router-dom';
import { MemoryHistory } from 'history/createMemoryHistory';
import { createMemoryHistory } from 'history';
import { mountWithIntl, renderWithIntl, shallowWithIntl } from 'test_utils/enzyme_helpers';
export const renderWithRouter = (Component: any, customHistory?: MemoryHistory) => {
const helperWithRouter: <R>(
helper: (node: ReactElement) => R,
component: ReactElement,
customHistory?: MemoryHistory
) => R = (helper, component, customHistory) => {
if (customHistory) {
return <Router history={customHistory}>{Component}</Router>;
customHistory.location.key = 'TestKeyForTesting';
return helper(<Router history={customHistory}>{component}</Router>);
}
const history = createMemoryHistory();
history.location.key = 'TestKeyForTesting';
return <Router history={history}>{Component}</Router>;
return helper(<Router history={history}>{component}</Router>);
};
export const renderWithRouter = (component: ReactElement, customHistory?: MemoryHistory) => {
return helperWithRouter(renderWithIntl, component, customHistory);
};
export const shallowWithRouter = (component: ReactElement, customHistory?: MemoryHistory) => {
return helperWithRouter(shallowWithIntl, component, customHistory);
};
export const mountWithRouter = (component: ReactElement, customHistory?: MemoryHistory) => {
return helperWithRouter(mountWithIntl, component, customHistory);
};

View file

@ -4,4 +4,4 @@
* you may not use this file except in compliance with the Elastic License.
*/
export { renderWithRouter } from './helper/render_with_router';
export { renderWithRouter, shallowWithRouter, mountWithRouter } from './helper/render_with_router';

View file

@ -0,0 +1,56 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`MonitorPage shallow renders expected elements for valid props 1`] = `
<ContextProvider
value={
Object {
"history": Object {
"action": "POP",
"block": [Function],
"canGo": [Function],
"createHref": [Function],
"entries": Array [
Object {
"hash": "",
"key": "TestKeyForTesting",
"pathname": "/",
"search": "",
"state": undefined,
},
],
"go": [Function],
"goBack": [Function],
"goForward": [Function],
"index": 0,
"length": 1,
"listen": [Function],
"location": Object {
"hash": "",
"key": "TestKeyForTesting",
"pathname": "/",
"search": "",
"state": undefined,
},
"push": [Function],
"replace": [Function],
},
"location": Object {
"hash": "",
"key": "TestKeyForTesting",
"pathname": "/",
"search": "",
"state": undefined,
},
"match": Object {
"isExact": true,
"params": Object {},
"path": "/",
"url": "/",
},
"staticContext": undefined,
}
}
>
<MonitorPage />
</ContextProvider>
`;

View file

@ -0,0 +1,56 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`NotFoundPage render component for valid props 1`] = `
<ContextProvider
value={
Object {
"history": Object {
"action": "POP",
"block": [Function],
"canGo": [Function],
"createHref": [Function],
"entries": Array [
Object {
"hash": "",
"key": "TestKeyForTesting",
"pathname": "/",
"search": "",
"state": undefined,
},
],
"go": [Function],
"goBack": [Function],
"goForward": [Function],
"index": 0,
"length": 1,
"listen": [Function],
"location": Object {
"hash": "",
"key": "TestKeyForTesting",
"pathname": "/",
"search": "",
"state": undefined,
},
"push": [Function],
"replace": [Function],
},
"location": Object {
"hash": "",
"key": "TestKeyForTesting",
"pathname": "/",
"search": "",
"state": undefined,
},
"match": Object {
"isExact": true,
"params": Object {},
"path": "/",
"url": "/",
},
"staticContext": undefined,
}
}
>
<NotFoundPage />
</ContextProvider>
`;

View file

@ -0,0 +1,162 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`MonitorPage shallow renders expected elements for valid props 1`] = `
<ContextProvider
value={
Object {
"history": Object {
"action": "POP",
"block": [Function],
"canGo": [Function],
"createHref": [Function],
"entries": Array [
Object {
"hash": "",
"key": "TestKeyForTesting",
"pathname": "/",
"search": "",
"state": undefined,
},
],
"go": [Function],
"goBack": [Function],
"goForward": [Function],
"index": 0,
"length": 1,
"listen": [Function],
"location": Object {
"hash": "",
"key": "TestKeyForTesting",
"pathname": "/",
"search": "",
"state": undefined,
},
"push": [Function],
"replace": [Function],
},
"location": Object {
"hash": "",
"key": "TestKeyForTesting",
"pathname": "/",
"search": "",
"state": undefined,
},
"match": Object {
"isExact": true,
"params": Object {},
"path": "/",
"url": "/",
},
"staticContext": undefined,
}
}
>
<OverviewPageComponent
autocomplete={
Object {
"getQuerySuggestions": [MockFunction],
"getValueSuggestions": [MockFunction],
"hasQuerySuggestions": [Function],
}
}
indexPattern={
Object {
"fields": Array [
Object {
"aggregatable": true,
"esTypes": Array [
"date",
],
"name": "@timestamp",
"readFromDocValues": true,
"searchable": true,
"type": "date",
},
Object {
"aggregatable": true,
"esTypes": Array [
"keyword",
],
"name": "monitor.check_group",
"readFromDocValues": true,
"searchable": true,
"type": "string",
},
Object {
"aggregatable": true,
"esTypes": Array [
"long",
],
"name": "monitor.duration.us",
"readFromDocValues": true,
"searchable": true,
"type": "number",
},
Object {
"aggregatable": true,
"esTypes": Array [
"keyword",
],
"name": "monitor.id",
"readFromDocValues": true,
"searchable": true,
"type": "string",
},
Object {
"aggregatable": true,
"esTypes": Array [
"ip",
],
"name": "monitor.ip",
"readFromDocValues": true,
"searchable": true,
"type": "ip",
},
Object {
"aggregatable": true,
"esTypes": Array [
"keyword",
],
"name": "monitor.name",
"readFromDocValues": true,
"searchable": true,
"type": "string",
},
Object {
"aggregatable": true,
"esTypes": Array [
"keyword",
],
"name": "monitor.status",
"readFromDocValues": true,
"searchable": true,
"type": "string",
},
Object {
"aggregatable": true,
"esTypes": Array [
"date_range",
],
"name": "monitor.timespan",
"readFromDocValues": true,
"searchable": true,
"type": "unknown",
},
Object {
"aggregatable": true,
"esTypes": Array [
"keyword",
],
"name": "monitor.type",
"readFromDocValues": true,
"searchable": true,
"type": "string",
},
],
"title": "heartbeat-8*",
}
}
setEsKueryFilters={[MockFunction]}
/>
</ContextProvider>
`;

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,15 @@
/*
* 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 React from 'react';
import { MonitorPage } from '../monitor';
import { shallowWithRouter } from '../../lib';
describe('MonitorPage', () => {
it('shallow renders expected elements for valid props', () => {
expect(shallowWithRouter(<MonitorPage />)).toMatchSnapshot();
});
});

View file

@ -0,0 +1,16 @@
/*
* 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 React from 'react';
import { shallowWithRouter } from '../../lib';
import { NotFoundPage } from '../not_found';
describe('NotFoundPage', () => {
it('render component for valid props', () => {
const component = shallowWithRouter(<NotFoundPage />);
expect(component).toMatchSnapshot();
});
});

View file

@ -0,0 +1,108 @@
/*
* 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 React from 'react';
import { OverviewPageComponent } from '../overview';
import { shallowWithRouter } from '../../lib';
describe('MonitorPage', () => {
const indexPattern = {
fields: [
{
name: '@timestamp',
type: 'date',
esTypes: ['date'],
searchable: true,
aggregatable: true,
readFromDocValues: true,
},
{
name: 'monitor.check_group',
type: 'string',
esTypes: ['keyword'],
searchable: true,
aggregatable: true,
readFromDocValues: true,
},
{
name: 'monitor.duration.us',
type: 'number',
esTypes: ['long'],
searchable: true,
aggregatable: true,
readFromDocValues: true,
},
{
name: 'monitor.id',
type: 'string',
esTypes: ['keyword'],
searchable: true,
aggregatable: true,
readFromDocValues: true,
},
{
name: 'monitor.ip',
type: 'ip',
esTypes: ['ip'],
searchable: true,
aggregatable: true,
readFromDocValues: true,
},
{
name: 'monitor.name',
type: 'string',
esTypes: ['keyword'],
searchable: true,
aggregatable: true,
readFromDocValues: true,
},
{
name: 'monitor.status',
type: 'string',
esTypes: ['keyword'],
searchable: true,
aggregatable: true,
readFromDocValues: true,
},
{
name: 'monitor.timespan',
type: 'unknown',
esTypes: ['date_range'],
searchable: true,
aggregatable: true,
readFromDocValues: true,
},
{
name: 'monitor.type',
type: 'string',
esTypes: ['keyword'],
searchable: true,
aggregatable: true,
readFromDocValues: true,
},
],
title: 'heartbeat-8*',
};
const autocomplete = {
getQuerySuggestions: jest.fn(),
hasQuerySuggestions: () => true,
getValueSuggestions: jest.fn(),
};
it('shallow renders expected elements for valid props', () => {
expect(
shallowWithRouter(
<OverviewPageComponent
autocomplete={autocomplete}
indexPattern={indexPattern}
setEsKueryFilters={jest.fn()}
/>
)
).toMatchSnapshot();
});
});

View file

@ -0,0 +1,146 @@
/*
* 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 React from 'react';
import { Route } from 'react-router-dom';
import { PageHeaderComponent } from '../page_header';
import { mountWithRouter, renderWithRouter, shallowWithRouter } from '../../lib';
import { MONITOR_ROUTE, OVERVIEW_ROUTE } from '../../../common/constants';
import { Ping } from '../../../common/graphql/types';
import { createMemoryHistory } from 'history';
import { ChromeBreadcrumb } from 'kibana/public';
describe('PageHeaderComponent', () => {
const monitorStatus: Ping = {
id: 'elastic-co',
tcp: { rtt: { connect: { us: 174982 } } },
http: {
response: {
body: {
bytes: 2092041,
hash: '5d970606a6be810ae5d37115c4807fdd07ba4c3e407924ee5297e172d2efb3dc',
},
status_code: 200,
},
rtt: {
response_header: { us: 340175 },
write_request: { us: 38 },
validate: { us: 1797839 },
content: { us: 1457663 },
total: { us: 2030012 },
},
},
monitor: {
ip: '2a04:4e42:3::729',
status: 'up',
duration: { us: 2030035 },
type: 'http',
id: 'elastic-co',
name: 'elastic',
check_group: '2a017afa-4736-11ea-b3d0-acde48001122',
},
resolve: { ip: '2a04:4e42:3::729', rtt: { us: 2102 } },
url: { port: 443, full: 'https://www.elastic.co', scheme: 'https', domain: 'www.elastic.co' },
ecs: { version: '1.4.0' },
tls: {
certificate_not_valid_after: '2020-07-16T03:15:39.000Z',
rtt: { handshake: { us: 57115 } },
certificate_not_valid_before: '2019-08-16T01:40:25.000Z',
},
observer: {
geo: { name: 'US-West', location: '37.422994, -122.083666' },
},
timestamp: '2020-02-04T10:07:42.142Z',
};
it('shallow renders expected elements for valid props', () => {
const component = shallowWithRouter(<PageHeaderComponent setBreadcrumbs={jest.fn()} />);
expect(component).toMatchSnapshot();
});
it('renders expected elements for valid props', () => {
const component = renderWithRouter(<PageHeaderComponent setBreadcrumbs={jest.fn()} />);
expect(component).toMatchSnapshot();
});
it('renders expected title for valid overview route', () => {
const component = renderWithRouter(
<Route path={OVERVIEW_ROUTE}>
<PageHeaderComponent setBreadcrumbs={jest.fn()} />
</Route>
);
expect(component).toMatchSnapshot();
const titleComponent = component.find('.euiTitle');
expect(titleComponent.text()).toBe('Overview');
});
it('renders expected title for valid monitor route', () => {
const history = createMemoryHistory({ initialEntries: ['/monitor/ZWxhc3RpYy1jbw=='] });
const component = renderWithRouter(
<Route path={MONITOR_ROUTE}>
<PageHeaderComponent setBreadcrumbs={jest.fn()} monitorStatus={monitorStatus} />
</Route>,
history
);
expect(component).toMatchSnapshot();
const titleComponent = component.find('.euiTitle');
expect(titleComponent.text()).toBe('https://www.elastic.co');
});
it('mount expected page title for valid monitor route', () => {
const history = createMemoryHistory({ initialEntries: ['/monitor/ZWxhc3RpYy1jbw=='] });
const component = mountWithRouter(
<Route path={MONITOR_ROUTE}>
<PageHeaderComponent setBreadcrumbs={jest.fn()} monitorStatus={monitorStatus} />
</Route>,
history
);
expect(component).toMatchSnapshot();
const titleComponent = component.find('.euiTitle');
expect(titleComponent.text()).toBe('https://www.elastic.co');
expect(document.title).toBe('Uptime | elastic - Kibana');
});
it('mount and set expected breadcrumb for monitor route', () => {
const history = createMemoryHistory({ initialEntries: ['/monitor/ZWxhc3RpYy1jbw=='] });
let breadcrumbObj: ChromeBreadcrumb[] = [];
const setBreadcrumb = (breadcrumbs: ChromeBreadcrumb[]) => {
breadcrumbObj = breadcrumbs;
};
mountWithRouter(
<Route path={MONITOR_ROUTE}>
<PageHeaderComponent setBreadcrumbs={setBreadcrumb} monitorStatus={monitorStatus} />
</Route>,
history
);
expect(breadcrumbObj).toStrictEqual([
{ href: '#/?', text: 'Uptime' },
{ text: 'https://www.elastic.co' },
]);
});
it('mount and set expected breadcrumb for overview route', () => {
let breadcrumbObj: ChromeBreadcrumb[] = [];
const setBreadcrumb = (breadcrumbs: ChromeBreadcrumb[]) => {
breadcrumbObj = breadcrumbs;
};
mountWithRouter(
<Route path={OVERVIEW_ROUTE}>
<PageHeaderComponent setBreadcrumbs={setBreadcrumb} monitorStatus={monitorStatus} />
</Route>
);
expect(breadcrumbObj).toStrictEqual([{ href: '#/', text: 'Uptime' }]);
});
});

View file

@ -6,5 +6,3 @@
export { MonitorPage } from './monitor';
export { NotFoundPage } from './not_found';
export { PageHeader } from './page_header';
export { OverviewPage } from '../components/connected/';

View file

@ -5,21 +5,15 @@
*/
import { EuiSpacer } from '@elastic/eui';
import React, { Fragment, useContext, useState } from 'react';
import React, { useContext, useState } from 'react';
import { useParams } from 'react-router-dom';
import { MonitorCharts, PingList } from '../components/functional';
import { UMUpdateBreadcrumbs } from '../lib/lib';
import { UptimeRefreshContext, UptimeThemeContext } from '../contexts';
import { useUptimeTelemetry, useUrlParams, UptimePage } from '../hooks';
import { useTrackPageview } from '../../../infra/public';
import { PageHeader } from './page_header';
import { MonitorStatusDetails } from '../components/connected';
interface MonitorPageProps {
setBreadcrumbs: UMUpdateBreadcrumbs;
}
export const MonitorPage = ({ setBreadcrumbs }: MonitorPageProps) => {
export const MonitorPage = () => {
// decode 64 base string, it was decoded to make it a valid url, since monitor id can be a url
let { monitorId } = useParams();
monitorId = atob(monitorId || '');
@ -46,8 +40,7 @@ export const MonitorPage = ({ setBreadcrumbs }: MonitorPageProps) => {
useTrackPageview({ app: 'uptime', path: 'monitor', delay: 15000 });
return (
<Fragment>
<PageHeader setBreadcrumbs={setBreadcrumbs} />
<>
<EuiSpacer size="s" />
<MonitorStatusDetails monitorId={monitorId} />
<EuiSpacer size="s" />
@ -69,6 +62,6 @@ export const MonitorPage = ({ setBreadcrumbs }: MonitorPageProps) => {
status: selectedPingStatus,
}}
/>
</Fragment>
</>
);
};

View file

@ -13,11 +13,9 @@ import {
OverviewPageParsingErrorCallout,
StatusPanel,
} from '../components/functional';
import { UMUpdateBreadcrumbs } from '../lib/lib';
import { useUrlParams, useUptimeTelemetry, UptimePage } from '../hooks';
import { stringifyUrlParams } from '../lib/helper/stringify_url_params';
import { useTrackPageview } from '../../../infra/public';
import { PageHeader } from './page_header';
import { DataPublicPluginStart, IIndexPattern } from '../../../../../../src/plugins/data/public';
import { UptimeThemeContext } from '../contexts';
import { FilterGroup, KueryBar } from '../components/connected';
@ -25,7 +23,6 @@ import { useUpdateKueryString } from '../hooks';
interface OverviewPageProps {
autocomplete: DataPublicPluginStart['autocomplete'];
setBreadcrumbs: UMUpdateBreadcrumbs;
indexPattern: IIndexPattern;
setEsKueryFilters: (esFilters: string) => void;
}
@ -41,12 +38,7 @@ const EuiFlexItemStyled = styled(EuiFlexItem)`
}
`;
export const OverviewPageComponent = ({
autocomplete,
setBreadcrumbs,
indexPattern,
setEsKueryFilters,
}: Props) => {
export const OverviewPageComponent = ({ autocomplete, indexPattern, setEsKueryFilters }: Props) => {
const { colors } = useContext(UptimeThemeContext);
const [getUrlParams] = useUrlParams();
const { absoluteDateRangeStart, absoluteDateRangeEnd, ...params } = getUrlParams();
@ -81,7 +73,6 @@ export const OverviewPageComponent = ({
return (
<>
<PageHeader setBreadcrumbs={setBreadcrumbs} />
<EmptyState implementsCustomErrorState={true} variables={{}}>
<EuiFlexGroup gutterSize="xs" wrap responsive>
<EuiFlexItem grow={1} style={{ flexBasis: 500 }}>

View file

@ -4,23 +4,21 @@
* you may not use this file except in compliance with the Elastic License.
*/
import { EuiTitle, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
import React, { useEffect, useState } from 'react';
import { connect } from 'react-redux';
import { useRouteMatch } from 'react-router-dom';
import { i18n } from '@kbn/i18n';
import React, { useEffect, useState } from 'react';
import { useRouteMatch } from 'react-router-dom';
import { EuiTitle, EuiFlexGroup, EuiFlexItem, EuiSpacer } from '@elastic/eui';
import { UptimeDatePicker } from '../components/functional/uptime_date_picker';
import { AppState } from '../state';
import { selectSelectedMonitor } from '../state/selectors';
import { getMonitorPageBreadcrumb, getOverviewPageBreadcrumbs } from '../breadcrumbs';
import { stringifyUrlParams } from '../lib/helper/stringify_url_params';
import { getTitle } from '../lib/helper/get_title';
import { UMUpdateBreadcrumbs } from '../lib/lib';
import { MONITOR_ROUTE } from '../routes';
import { useUrlParams } from '../hooks';
import { MONITOR_ROUTE } from '../../common/constants';
import { Ping } from '../../common/graphql/types';
interface PageHeaderProps {
monitorStatus?: any;
monitorStatus?: Ping;
setBreadcrumbs: UMUpdateBreadcrumbs;
}
@ -32,24 +30,27 @@ export const PageHeaderComponent = ({ monitorStatus, setBreadcrumbs }: PageHeade
const [getUrlParams] = useUrlParams();
const { absoluteDateRangeStart, absoluteDateRangeEnd, ...params } = getUrlParams();
const headingText = i18n.translate('xpack.uptime.overviewPage.headerText', {
defaultMessage: 'Overview',
description: `The text that will be displayed in the app's heading when the Overview page loads.`,
});
const headingText = !monitorPage
? i18n.translate('xpack.uptime.overviewPage.headerText', {
defaultMessage: 'Overview',
description: `The text that will be displayed in the app's heading when the Overview page loads.`,
})
: monitorStatus?.url?.full;
const [headerText, setHeaderText] = useState(headingText);
useEffect(() => {
if (monitorPage) {
setHeaderText(monitorStatus?.url?.full);
setHeaderText(monitorStatus?.url?.full ?? '');
if (monitorStatus?.monitor) {
const { name, id } = monitorStatus.monitor;
document.title = getTitle(name || id);
document.title = getTitle((name || id) ?? '');
}
} else {
setHeaderText(headingText);
document.title = getTitle();
}
}, [monitorStatus, monitorPage, setHeaderText]);
}, [monitorStatus, monitorPage, setHeaderText, headingText]);
useEffect(() => {
if (monitorPage) {
@ -61,10 +62,6 @@ export const PageHeaderComponent = ({ monitorStatus, setBreadcrumbs }: PageHeade
}
}, [headerText, setBreadcrumbs, params, monitorPage]);
useEffect(() => {
document.title = getTitle();
}, []);
return (
<>
<EuiFlexGroup alignItems="center" justifyContent="spaceBetween" gutterSize="s" wrap={true}>
@ -81,9 +78,3 @@ export const PageHeaderComponent = ({ monitorStatus, setBreadcrumbs }: PageHeade
</>
);
};
const mapStateToProps = (state: AppState) => ({
monitorStatus: selectSelectedMonitor(state),
});
export const PageHeader = connect(mapStateToProps, null)(PageHeaderComponent);

View file

@ -6,26 +6,22 @@
import React, { FC } from 'react';
import { Route, Switch } from 'react-router-dom';
import { MonitorPage, NotFoundPage, OverviewPage } from './pages';
import { DataPublicPluginStart } from '../../../../../src/plugins/data/public';
import { UMUpdateBreadcrumbs } from './lib/lib';
export const MONITOR_ROUTE = '/monitor/:monitorId?';
export const OVERVIEW_ROUTE = '/';
import { OverviewPage } from './components/connected/pages/overview_container';
import { MONITOR_ROUTE, OVERVIEW_ROUTE } from '../common/constants';
import { MonitorPage, NotFoundPage } from './pages';
interface RouterProps {
autocomplete: DataPublicPluginStart['autocomplete'];
basePath: string;
setBreadcrumbs: UMUpdateBreadcrumbs;
}
export const PageRouter: FC<RouterProps> = ({ autocomplete, basePath, setBreadcrumbs }) => (
export const PageRouter: FC<RouterProps> = ({ autocomplete }) => (
<Switch>
<Route path={MONITOR_ROUTE}>
<MonitorPage setBreadcrumbs={setBreadcrumbs} />
<MonitorPage />
</Route>
<Route path={OVERVIEW_ROUTE}>
<OverviewPage autocomplete={autocomplete} setBreadcrumbs={setBreadcrumbs} />
<OverviewPage autocomplete={autocomplete} />
</Route>
<Route component={NotFoundPage} />
</Switch>

View file

@ -23,6 +23,7 @@ import { CommonlyUsedRange } from './components/functional/uptime_date_picker';
import { store } from './state';
import { setBasePath } from './state/actions';
import { PageRouter } from './routes';
import { PageHeader } from './components/connected/pages/page_header_container';
export interface UptimeAppColors {
danger: string;
@ -98,12 +99,9 @@ const Application = (props: UptimeAppProps) => {
<UptimeThemeContextProvider darkMode={darkMode}>
<EuiPage className="app-wrapper-panel " data-test-subj="uptimeApp">
<main>
<PageRouter
// @ts-ignore we need to update the type of this prop
autocomplete={plugins.data.autocomplete}
basePath={basePath}
setBreadcrumbs={setBreadcrumbs}
/>
<PageHeader setBreadcrumbs={setBreadcrumbs} />
// @ts-ignore we need to update the type of this prop
<PageRouter autocomplete={plugins.data.autocomplete} />
</main>
</EuiPage>
</UptimeThemeContextProvider>