mirror of
https://github.com/elastic/kibana.git
synced 2025-04-24 09:48:58 -04:00
[Synthetics] Test useMonitorStatusData
hook (#195438)
## Summary Recently we had some issues related to module-level logic errors in a fairly complicated hook. This PR adds a new jest suite for the hook in question that covers some baseline usage. It could be improved in the future with additional test cases.
This commit is contained in:
parent
8bd567b73a
commit
4605cc0307
2 changed files with 387 additions and 12 deletions
|
@ -0,0 +1,356 @@
|
|||
/*
|
||||
* 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 { renderHook, act } from '@testing-library/react-hooks';
|
||||
import * as reactRedux from 'react-redux';
|
||||
import { useBins, useMonitorStatusData } from './use_monitor_status_data';
|
||||
import { WrappedHelper } from '../../../utils/testing';
|
||||
import * as selectedMonitorHook from '../hooks/use_selected_monitor';
|
||||
import * as selectedLocationHook from '../hooks/use_selected_location';
|
||||
import { omit } from 'lodash';
|
||||
|
||||
describe('useMonitorStatusData', () => {
|
||||
let dispatchMock: jest.Mock;
|
||||
beforeEach(() => {
|
||||
dispatchMock = jest.fn();
|
||||
jest.spyOn(reactRedux, 'useDispatch').mockReturnValue(dispatchMock);
|
||||
jest.spyOn(selectedLocationHook, 'useSelectedLocation').mockReturnValue({
|
||||
id: 'us-east-1',
|
||||
label: 'us-east-1',
|
||||
isServiceManaged: true,
|
||||
});
|
||||
jest.spyOn(selectedMonitorHook, 'useSelectedMonitor').mockReturnValue({
|
||||
monitor: {
|
||||
id: 'testMonitorId',
|
||||
type: 'browser',
|
||||
name: 'testMonitor',
|
||||
enabled: true,
|
||||
schedule: {
|
||||
number: 5,
|
||||
unit: 'm',
|
||||
},
|
||||
locations: ['us-east-1'],
|
||||
tags: [],
|
||||
apiKey: '1234',
|
||||
config: {
|
||||
synthetics: {
|
||||
type: 'simple',
|
||||
timeout: 10,
|
||||
frequency: 5,
|
||||
url: 'http://elastic.co',
|
||||
method: 'GET',
|
||||
request: {
|
||||
headers: {},
|
||||
},
|
||||
response: {
|
||||
status: 200,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
} as any);
|
||||
});
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('does not request status data when interval is invalid', async () => {
|
||||
const props = {
|
||||
from: 1728310613654,
|
||||
to: 1728311513654,
|
||||
initialSizeRef: { current: { clientWidth: 0 } as any },
|
||||
};
|
||||
const { result } = renderHook(() => useMonitorStatusData(props), {
|
||||
wrapper: WrappedHelper,
|
||||
});
|
||||
expect(result.current).toBeDefined();
|
||||
expect(result.current.minsPerBin).toBeNull();
|
||||
expect(
|
||||
dispatchMock.mock.calls.some((args) => args[0].type === 'QUIET GET MONITOR STATUS HEATMAP')
|
||||
).not.toBe(true);
|
||||
});
|
||||
|
||||
it('handles resize events and requests based on new data', async () => {
|
||||
const props = {
|
||||
from: 1728310613654,
|
||||
to: 1728317313654,
|
||||
initialSizeRef: { current: { clientWidth: 0 } as any },
|
||||
};
|
||||
const { result } = renderHook(() => useMonitorStatusData(props), {
|
||||
wrapper: WrappedHelper,
|
||||
});
|
||||
await act(async () => {
|
||||
result.current.handleResize({ width: 250, height: 800 });
|
||||
// this is necessary for debounce to complete
|
||||
await new Promise((r) => setTimeout(r, 510));
|
||||
});
|
||||
const fetchActions = dispatchMock.mock.calls.filter(
|
||||
(args) => args[0].type === 'QUIET GET MONITOR STATUS HEATMAP'
|
||||
);
|
||||
expect(fetchActions).toHaveLength(1);
|
||||
expect(omit(fetchActions[0][0], 'meta')).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"payload": Object {
|
||||
"from": 1728310613654,
|
||||
"interval": 7,
|
||||
"location": "us-east-1",
|
||||
"monitorId": "testMonitorId",
|
||||
"to": 1728317313654,
|
||||
},
|
||||
"type": "QUIET GET MONITOR STATUS HEATMAP",
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
||||
|
||||
describe('useBins', () => {
|
||||
it('generates bins and overlays histogram data', () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useBins({
|
||||
minsPerBin: 5,
|
||||
fromMillis: 1728310613654,
|
||||
toMillis: 1728313563654,
|
||||
dateHistogram: [
|
||||
{
|
||||
key: 1728310613654,
|
||||
key_as_string: '2023-06-06T00:56:53.654Z',
|
||||
doc_count: 1,
|
||||
down: {
|
||||
value: 0,
|
||||
},
|
||||
up: {
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 1728310613654 + 300000,
|
||||
key_as_string: '2023-06-06T00:56:53.654Z',
|
||||
doc_count: 1,
|
||||
down: {
|
||||
value: 0,
|
||||
},
|
||||
up: {
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 1728310613654 + 600000,
|
||||
key_as_string: '2023-06-06T00:56:53.654Z',
|
||||
doc_count: 1,
|
||||
down: {
|
||||
value: 1,
|
||||
},
|
||||
up: {
|
||||
value: 0,
|
||||
},
|
||||
},
|
||||
{
|
||||
key: 1728310613654 + 900000,
|
||||
key_as_string: '2023-06-06T00:56:53.654Z',
|
||||
doc_count: 1,
|
||||
down: {
|
||||
value: 2,
|
||||
},
|
||||
up: {
|
||||
value: 1,
|
||||
},
|
||||
},
|
||||
],
|
||||
}),
|
||||
{ wrapper: WrappedHelper }
|
||||
);
|
||||
expect(result.current).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"timeBinMap": Map {
|
||||
1728310800000 => Object {
|
||||
"downs": 0,
|
||||
"end": 1728310800000,
|
||||
"start": 1728310500000,
|
||||
"ups": 1,
|
||||
"value": 1,
|
||||
},
|
||||
1728311100000 => Object {
|
||||
"downs": 0,
|
||||
"end": 1728311100000,
|
||||
"start": 1728310800000,
|
||||
"ups": 1,
|
||||
"value": 1,
|
||||
},
|
||||
1728311400000 => Object {
|
||||
"downs": 1,
|
||||
"end": 1728311400000,
|
||||
"start": 1728311100000,
|
||||
"ups": 0,
|
||||
"value": -1,
|
||||
},
|
||||
1728311700000 => Object {
|
||||
"downs": 2,
|
||||
"end": 1728311700000,
|
||||
"start": 1728311400000,
|
||||
"ups": 1,
|
||||
"value": -0.3333333333333333,
|
||||
},
|
||||
1728312000000 => Object {
|
||||
"downs": 0,
|
||||
"end": 1728312000000,
|
||||
"start": 1728311700000,
|
||||
"ups": 0,
|
||||
"value": 0,
|
||||
},
|
||||
1728312300000 => Object {
|
||||
"downs": 0,
|
||||
"end": 1728312300000,
|
||||
"start": 1728312000000,
|
||||
"ups": 0,
|
||||
"value": 0,
|
||||
},
|
||||
1728312600000 => Object {
|
||||
"downs": 0,
|
||||
"end": 1728312600000,
|
||||
"start": 1728312300000,
|
||||
"ups": 0,
|
||||
"value": 0,
|
||||
},
|
||||
1728312900000 => Object {
|
||||
"downs": 0,
|
||||
"end": 1728312900000,
|
||||
"start": 1728312600000,
|
||||
"ups": 0,
|
||||
"value": 0,
|
||||
},
|
||||
1728313200000 => Object {
|
||||
"downs": 0,
|
||||
"end": 1728313200000,
|
||||
"start": 1728312900000,
|
||||
"ups": 0,
|
||||
"value": 0,
|
||||
},
|
||||
1728313500000 => Object {
|
||||
"downs": 0,
|
||||
"end": 1728313500000,
|
||||
"start": 1728313200000,
|
||||
"ups": 0,
|
||||
"value": 0,
|
||||
},
|
||||
1728313800000 => Object {
|
||||
"downs": 0,
|
||||
"end": 1728313800000,
|
||||
"start": 1728313500000,
|
||||
"ups": 0,
|
||||
"value": 0,
|
||||
},
|
||||
},
|
||||
"timeBins": Array [
|
||||
Object {
|
||||
"downs": 0,
|
||||
"end": 1728310800000,
|
||||
"start": 1728310500000,
|
||||
"ups": 1,
|
||||
"value": 1,
|
||||
},
|
||||
Object {
|
||||
"downs": 0,
|
||||
"end": 1728311100000,
|
||||
"start": 1728310800000,
|
||||
"ups": 1,
|
||||
"value": 1,
|
||||
},
|
||||
Object {
|
||||
"downs": 1,
|
||||
"end": 1728311400000,
|
||||
"start": 1728311100000,
|
||||
"ups": 0,
|
||||
"value": -1,
|
||||
},
|
||||
Object {
|
||||
"downs": 2,
|
||||
"end": 1728311700000,
|
||||
"start": 1728311400000,
|
||||
"ups": 1,
|
||||
"value": -0.3333333333333333,
|
||||
},
|
||||
Object {
|
||||
"downs": 0,
|
||||
"end": 1728312000000,
|
||||
"start": 1728311700000,
|
||||
"ups": 0,
|
||||
"value": 0,
|
||||
},
|
||||
Object {
|
||||
"downs": 0,
|
||||
"end": 1728312300000,
|
||||
"start": 1728312000000,
|
||||
"ups": 0,
|
||||
"value": 0,
|
||||
},
|
||||
Object {
|
||||
"downs": 0,
|
||||
"end": 1728312600000,
|
||||
"start": 1728312300000,
|
||||
"ups": 0,
|
||||
"value": 0,
|
||||
},
|
||||
Object {
|
||||
"downs": 0,
|
||||
"end": 1728312900000,
|
||||
"start": 1728312600000,
|
||||
"ups": 0,
|
||||
"value": 0,
|
||||
},
|
||||
Object {
|
||||
"downs": 0,
|
||||
"end": 1728313200000,
|
||||
"start": 1728312900000,
|
||||
"ups": 0,
|
||||
"value": 0,
|
||||
},
|
||||
Object {
|
||||
"downs": 0,
|
||||
"end": 1728313500000,
|
||||
"start": 1728313200000,
|
||||
"ups": 0,
|
||||
"value": 0,
|
||||
},
|
||||
Object {
|
||||
"downs": 0,
|
||||
"end": 1728313800000,
|
||||
"start": 1728313500000,
|
||||
"ups": 0,
|
||||
"value": 0,
|
||||
},
|
||||
],
|
||||
"xDomain": Object {
|
||||
"max": 1728313800000,
|
||||
"min": 1728310800000,
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
|
||||
it('returns a default value if interval is not valid', () => {
|
||||
const { result } = renderHook(
|
||||
() =>
|
||||
useBins({
|
||||
minsPerBin: null,
|
||||
fromMillis: 1728310613654,
|
||||
toMillis: 1728313563654,
|
||||
}),
|
||||
{ wrapper: WrappedHelper }
|
||||
);
|
||||
expect(result.current).toMatchInlineSnapshot(`
|
||||
Object {
|
||||
"timeBinMap": Map {},
|
||||
"timeBins": Array [],
|
||||
"xDomain": Object {
|
||||
"max": 1728313563654,
|
||||
"min": 1728310613654,
|
||||
},
|
||||
}
|
||||
`);
|
||||
});
|
||||
});
|
|
@ -28,6 +28,7 @@ import {
|
|||
quietGetMonitorStatusHeatmapAction,
|
||||
selectHeatmap,
|
||||
} from '../../../state/status_heatmap';
|
||||
import type { MonitorStatusHeatmapBucket } from '../../../../../../common/runtime_types';
|
||||
|
||||
type Props = Pick<MonitorStatusPanelProps, 'from' | 'to'> & {
|
||||
initialSizeRef?: React.MutableRefObject<HTMLDivElement | null>;
|
||||
|
@ -99,7 +100,36 @@ export const useMonitorStatusData = ({ from, to, initialSizeRef }: Props) => {
|
|||
[binsAvailableByWidth]
|
||||
);
|
||||
|
||||
const { timeBins, timeBinMap, xDomain } = useMemo((): {
|
||||
const { timeBins, timeBinMap, xDomain } = useBins({
|
||||
fromMillis,
|
||||
toMillis,
|
||||
dateHistogram,
|
||||
minsPerBin,
|
||||
});
|
||||
|
||||
return {
|
||||
loading,
|
||||
minsPerBin,
|
||||
timeBins,
|
||||
getTimeBinByXValue: (xValue: number | undefined) =>
|
||||
xValue === undefined ? undefined : timeBinMap.get(xValue),
|
||||
xDomain,
|
||||
handleResize,
|
||||
};
|
||||
};
|
||||
|
||||
export const useBins = ({
|
||||
minsPerBin,
|
||||
fromMillis,
|
||||
toMillis,
|
||||
dateHistogram,
|
||||
}: {
|
||||
minsPerBin: number | null;
|
||||
fromMillis: number;
|
||||
toMillis: number;
|
||||
dateHistogram?: MonitorStatusHeatmapBucket[];
|
||||
}) =>
|
||||
useMemo((): {
|
||||
timeBins: MonitorStatusTimeBin[];
|
||||
timeBinMap: Map<number, MonitorStatusTimeBin>;
|
||||
xDomain: { min: number; max: number };
|
||||
|
@ -125,14 +155,3 @@ export const useMonitorStatusData = ({ from, to, initialSizeRef }: Props) => {
|
|||
},
|
||||
};
|
||||
}, [minsPerBin, fromMillis, toMillis, dateHistogram]);
|
||||
|
||||
return {
|
||||
loading,
|
||||
minsPerBin,
|
||||
timeBins,
|
||||
getTimeBinByXValue: (xValue: number | undefined) =>
|
||||
xValue === undefined ? undefined : timeBinMap.get(xValue),
|
||||
xDomain,
|
||||
handleResize,
|
||||
};
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue