Skip to content

Commit

Permalink
Do not throw error on dashboards with undeclared query parameters or …
Browse files Browse the repository at this point in the history
…on widget creation. (#10536)

* Do not throw error on dashboards with undeclared query parameters.

We've recently implemented a time range info for dashboard widgets. This
PR is fixing a runtime error which occurred when no search types exist.
This is the case when a filter with an undeclared parameter   is being
applied.

* Do not throw error when widget id does not exist in search widget mapping.

* Fixing `TimrangeInfo.test` by using `mackReturnValueOnce` instead of `mockReturnValue`.`
  • Loading branch information
linuspahl committed May 4, 2021
1 parent 58eaedd commit 90d6743
Show file tree
Hide file tree
Showing 2 changed files with 60 additions and 25 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@
* <http://www.mongodb.com/licensing/server-side-public-license>.
*/
import React from 'react';
import Immutable from 'immutable';
import { render, screen } from 'wrappedTestingLibrary';
import { MockStore } from 'helpers/mocking';
import asMock from 'helpers/mocking/AsMock';

import Search from 'views/logic/search/Search';
import Widget from 'views/logic/widgets/Widget';
import TimeLocalizeContext from 'contexts/TimeLocalizeContext';
import { GlobalOverrideStore, GlobalOverrideStoreState } from 'views/stores/GlobalOverrideStore';
import GlobalOverride from 'views/logic/search/GlobalOverride';
import { SearchStore } from 'views/stores/SearchStore';

import TimerangeInfo from './TimerangeInfo';

Expand All @@ -34,30 +37,31 @@ jest.mock('views/stores/GlobalOverrideStore', () => ({
),
}));

jest.mock('views/stores/SearchStore', () => ({
SearchStore: MockStore(
['listen', () => jest.fn()],
'get',
['getInitialState', () => ({
result: {
results: {
'active-query-id': {
searchTypes: {
'search-type-id': {
effective_timerange: {
type: 'absolute', from: '2021-03-27T14:32:31.894Z', to: '2021-04-26T14:32:48.000Z',
},
},
const mockSearchStoreState = (storeState = {}) => ({
result: {
results: {
'active-query-id': {
searchTypes: {
'search-type-id': {
effective_timerange: {
type: 'absolute', from: '2021-03-27T14:32:31.894Z', to: '2021-04-26T14:32:48.000Z',
},
},
},
},
widgetMapping: {
get: jest.fn(() => ({
first: jest.fn(() => 'search-type-id'),
})),
},
})],
},
},
widgetMapping: Immutable.Map({ 'widget-id': Immutable.Set(['search-type-id']) }),
search: Search.create(),
widgetsToSearch: undefined,
...storeState,
});

jest.mock('views/stores/SearchStore', () => ({
SearchStore: MockStore(
['listen', () => jest.fn()],
'get',
['getInitialState', jest.fn(() => mockSearchStoreState())],
),
}));

Expand Down Expand Up @@ -118,7 +122,7 @@ describe('TimerangeInfo', () => {

it('should display global override', () => {
const state: GlobalOverrideStoreState = GlobalOverride.empty().toBuilder().timerange({ type: 'relative', range: 3000 }).build();
asMock(GlobalOverrideStore.getInitialState).mockReturnValue(state);
asMock(GlobalOverrideStore.getInitialState).mockReturnValueOnce(state);

const keywordWidget = widget.toBuilder()
.timerange({ type: 'keyword', keyword: '5 minutes ago' })
Expand All @@ -128,4 +132,32 @@ describe('TimerangeInfo', () => {

expect(screen.getByText('Global Override: an hour ago - Now')).toBeInTheDocument();
});

it('should not throw error when related search type is empty', () => {
const relativeWidget = widget.toBuilder().timerange({ type: 'relative', range: 3000 }).build();

asMock(SearchStore.getInitialState).mockReturnValueOnce(mockSearchStoreState({
result: {
results: {
'active-query-id': {
searchTypes: {},
},
},
},
}));

render(<SUT widget={relativeWidget} activeQuery="active-query-id" widgetId="widget-id" />);

expect(screen.getByText('an hour ago - Now')).toBeInTheDocument();
});

it('should not throw error and display default time range when widget id does not exist in search widget mapping', () => {
asMock(SearchStore.getInitialState).mockReturnValueOnce(mockSearchStoreState({
widgetMapping: Immutable.Map(),
}));

render(<SUT widget={widget} activeQuery="active-query-id" widgetId="widget-id" />);

expect(screen.getByText('5 minutes ago - Now')).toBeInTheDocument();
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@ const Wrapper = styled.div(({ theme }) => css`
width: max-content;
`);

const getEffectiveWidgetTimerange = (result, activeQuery, searchTypeId) => result?.results[activeQuery]
.searchTypes[searchTypeId]?.effective_timerange;

const TimerangeInfo = ({ className, widget, activeQuery, widgetId }: Props) => {
const { localizeTime } = useContext(TimeLocalizeContext);
const { result, widgetMapping } = useStore(SearchStore);
Expand All @@ -50,10 +53,10 @@ const TimerangeInfo = ({ className, widget, activeQuery, widgetId }: Props) => {

const configuredTimerange = timerangeToString(widget.timerange || DEFAULT_TIMERANGE, localizeTime);

const searchTypeId = widgetId ? widgetMapping.get(widgetId).first() : undefined;
const effectiveTimerange = activeQuery && searchTypeId ? result?.results[activeQuery]
.searchTypes[searchTypeId].effective_timerange : {};
const effectiveTimerangeString = timerangeToString(effectiveTimerange, localizeTime);
const searchTypeId = widgetId ? widgetMapping.get(widgetId)?.first() : undefined;

const effectiveTimerange = (activeQuery && searchTypeId) ? getEffectiveWidgetTimerange(result, activeQuery, searchTypeId) : undefined;
const effectiveTimerangeString = effectiveTimerange ? timerangeToString(effectiveTimerange, localizeTime) : 'Effective widget time range is currently not available.';

return (
<Wrapper className={className}>
Expand Down

0 comments on commit 90d6743

Please sign in to comment.