mirror of
https://github.com/grafana/grafana.git
synced 2025-02-13 00:55:47 -06:00
* Variables: Ensures all variable values are strings * Chore: remove redundant typings * Chore: fixes tests
202 lines
7.6 KiB
TypeScript
202 lines
7.6 KiB
TypeScript
import { dateTime, TimeRange } from '@grafana/data';
|
|
|
|
import { TemplateSrv } from '../../templating/template_srv';
|
|
import { onTimeRangeUpdated, OnTimeRangeUpdatedDependencies, setOptionAsCurrent } from './actions';
|
|
import { DashboardModel } from '../../dashboard/state';
|
|
import { DashboardState } from '../../../types';
|
|
import { createIntervalVariableAdapter } from '../interval/adapter';
|
|
import { variableAdapters } from '../adapters';
|
|
import { createConstantVariableAdapter } from '../constant/adapter';
|
|
import { VariableRefresh } from '../types';
|
|
import { constantBuilder, intervalBuilder } from '../shared/testing/builders';
|
|
import { reduxTester } from '../../../../test/core/redux/reduxTester';
|
|
import { getRootReducer, RootReducerType } from './helpers';
|
|
import { toVariableIdentifier, toVariablePayload } from './types';
|
|
import {
|
|
setCurrentVariableValue,
|
|
variableStateCompleted,
|
|
variableStateFailed,
|
|
variableStateFetching,
|
|
} from './sharedReducer';
|
|
import { createIntervalOptions } from '../interval/reducer';
|
|
import { silenceConsoleOutput } from '../../../../test/core/utils/silenceConsoleOutput';
|
|
import { notifyApp } from '../../../core/reducers/appNotification';
|
|
import { expect } from '../../../../test/lib/common';
|
|
import { TemplatingState } from './reducers';
|
|
|
|
variableAdapters.setInit(() => [createIntervalVariableAdapter(), createConstantVariableAdapter()]);
|
|
|
|
const getTestContext = () => {
|
|
const interval = intervalBuilder()
|
|
.withId('interval-0')
|
|
.withName('interval-0')
|
|
.withOptions('1m', '10m', '30m', '1h', '6h', '12h', '1d', '7d', '14d', '30d')
|
|
.withCurrent('1m')
|
|
.withRefresh(VariableRefresh.onTimeRangeChanged)
|
|
.build();
|
|
|
|
const constant = constantBuilder()
|
|
.withId('constant-1')
|
|
.withName('constant-1')
|
|
.withOptions('a constant')
|
|
.withCurrent('a constant')
|
|
.build();
|
|
|
|
const range: TimeRange = {
|
|
from: dateTime(new Date().getTime()).subtract(1, 'minutes'),
|
|
to: dateTime(new Date().getTime()),
|
|
raw: {
|
|
from: 'now-1m',
|
|
to: 'now',
|
|
},
|
|
};
|
|
const updateTimeRangeMock = jest.fn();
|
|
const templateSrvMock = ({ updateTimeRange: updateTimeRangeMock } as unknown) as TemplateSrv;
|
|
const dependencies: OnTimeRangeUpdatedDependencies = { templateSrv: templateSrvMock };
|
|
const templateVariableValueUpdatedMock = jest.fn();
|
|
const dashboard = ({
|
|
getModel: () =>
|
|
(({
|
|
templateVariableValueUpdated: templateVariableValueUpdatedMock,
|
|
startRefresh: startRefreshMock,
|
|
} as unknown) as DashboardModel),
|
|
} as unknown) as DashboardState;
|
|
const startRefreshMock = jest.fn();
|
|
const adapter = variableAdapters.get('interval');
|
|
const preloadedState = ({
|
|
dashboard,
|
|
templating: ({
|
|
variables: {
|
|
'interval-0': { ...interval },
|
|
'constant-1': { ...constant },
|
|
},
|
|
} as unknown) as TemplatingState,
|
|
} as unknown) as RootReducerType;
|
|
|
|
return {
|
|
interval,
|
|
range,
|
|
dependencies,
|
|
adapter,
|
|
preloadedState,
|
|
updateTimeRangeMock,
|
|
templateVariableValueUpdatedMock,
|
|
startRefreshMock,
|
|
};
|
|
};
|
|
|
|
describe('when onTimeRangeUpdated is dispatched', () => {
|
|
describe('and options are changed by update', () => {
|
|
it('then correct actions are dispatched and correct dependencies are called', async () => {
|
|
const {
|
|
preloadedState,
|
|
range,
|
|
dependencies,
|
|
updateTimeRangeMock,
|
|
templateVariableValueUpdatedMock,
|
|
startRefreshMock,
|
|
} = getTestContext();
|
|
|
|
const tester = await reduxTester<RootReducerType>({ preloadedState })
|
|
.givenRootReducer(getRootReducer())
|
|
.whenAsyncActionIsDispatched(onTimeRangeUpdated(range, dependencies));
|
|
|
|
tester.thenDispatchedActionsShouldEqual(
|
|
variableStateFetching(toVariablePayload({ type: 'interval', id: 'interval-0' })),
|
|
createIntervalOptions(toVariablePayload({ type: 'interval', id: 'interval-0' })),
|
|
setCurrentVariableValue(
|
|
toVariablePayload(
|
|
{ type: 'interval', id: 'interval-0' },
|
|
{ option: { text: '1m', value: '1m', selected: false } }
|
|
)
|
|
),
|
|
variableStateCompleted(toVariablePayload({ type: 'interval', id: 'interval-0' }))
|
|
);
|
|
|
|
expect(updateTimeRangeMock).toHaveBeenCalledTimes(1);
|
|
expect(updateTimeRangeMock).toHaveBeenCalledWith(range);
|
|
expect(templateVariableValueUpdatedMock).toHaveBeenCalledTimes(1);
|
|
expect(startRefreshMock).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|
|
|
|
describe('and options are not changed by update', () => {
|
|
it('then correct actions are dispatched and correct dependencies are called', async () => {
|
|
const {
|
|
interval,
|
|
preloadedState,
|
|
range,
|
|
dependencies,
|
|
updateTimeRangeMock,
|
|
templateVariableValueUpdatedMock,
|
|
startRefreshMock,
|
|
} = getTestContext();
|
|
|
|
const base = await reduxTester<RootReducerType>({ preloadedState })
|
|
.givenRootReducer(getRootReducer())
|
|
.whenAsyncActionIsDispatched(setOptionAsCurrent(toVariableIdentifier(interval), interval.options[0], false));
|
|
|
|
const tester = await base.whenAsyncActionIsDispatched(onTimeRangeUpdated(range, dependencies), true);
|
|
|
|
tester.thenDispatchedActionsShouldEqual(
|
|
variableStateFetching(toVariablePayload({ type: 'interval', id: 'interval-0' })),
|
|
createIntervalOptions(toVariablePayload({ type: 'interval', id: 'interval-0' })),
|
|
setCurrentVariableValue(
|
|
toVariablePayload(
|
|
{ type: 'interval', id: 'interval-0' },
|
|
{ option: { text: '1m', value: '1m', selected: false } }
|
|
)
|
|
),
|
|
variableStateCompleted(toVariablePayload({ type: 'interval', id: 'interval-0' }))
|
|
);
|
|
|
|
expect(updateTimeRangeMock).toHaveBeenCalledTimes(1);
|
|
expect(updateTimeRangeMock).toHaveBeenCalledWith(range);
|
|
expect(templateVariableValueUpdatedMock).toHaveBeenCalledTimes(0);
|
|
expect(startRefreshMock).toHaveBeenCalledTimes(1);
|
|
});
|
|
});
|
|
|
|
describe('and updateOptions throws', () => {
|
|
silenceConsoleOutput();
|
|
it('then correct actions are dispatched and correct dependencies are called', async () => {
|
|
const {
|
|
adapter,
|
|
preloadedState,
|
|
range,
|
|
dependencies,
|
|
updateTimeRangeMock,
|
|
templateVariableValueUpdatedMock,
|
|
startRefreshMock,
|
|
} = getTestContext();
|
|
|
|
adapter.updateOptions = jest.fn().mockRejectedValue(new Error('Something broke'));
|
|
|
|
const tester = await reduxTester<RootReducerType>({ preloadedState, debug: true })
|
|
.givenRootReducer(getRootReducer())
|
|
.whenAsyncActionIsDispatched(onTimeRangeUpdated(range, dependencies), true);
|
|
|
|
tester.thenDispatchedActionsPredicateShouldEqual((dispatchedActions) => {
|
|
expect(dispatchedActions[0]).toEqual(
|
|
variableStateFetching(toVariablePayload({ type: 'interval', id: 'interval-0' }))
|
|
);
|
|
expect(dispatchedActions[1]).toEqual(
|
|
variableStateFailed(
|
|
toVariablePayload({ type: 'interval', id: 'interval-0' }, { error: new Error('Something broke') })
|
|
)
|
|
);
|
|
expect(dispatchedActions[2].type).toEqual(notifyApp.type);
|
|
expect(dispatchedActions[2].payload.title).toEqual('Templating');
|
|
expect(dispatchedActions[2].payload.text).toEqual('Template variable service failed Something broke');
|
|
expect(dispatchedActions[2].payload.severity).toEqual('error');
|
|
return dispatchedActions.length === 3;
|
|
});
|
|
|
|
expect(updateTimeRangeMock).toHaveBeenCalledTimes(1);
|
|
expect(updateTimeRangeMock).toHaveBeenCalledWith(range);
|
|
expect(templateVariableValueUpdatedMock).toHaveBeenCalledTimes(0);
|
|
expect(startRefreshMock).toHaveBeenCalledTimes(0);
|
|
});
|
|
});
|
|
});
|