grafana/public/app/features/variables/interval/actions.test.ts

245 lines
9.3 KiB
TypeScript

import { dateTime } from '@grafana/data';
import { reduxTester } from '../../../../test/core/redux/reduxTester';
import { silenceConsoleOutput } from '../../../../test/core/utils/silenceConsoleOutput';
import { notifyApp } from '../../../core/actions';
import { getTimeSrv, setTimeSrv, TimeSrv } from '../../dashboard/services/TimeSrv';
import { TemplateSrv } from '../../templating/template_srv';
import { variableAdapters } from '../adapters';
import { intervalBuilder } from '../shared/testing/builders';
import { updateOptions } from '../state/actions';
import { getRootReducer, RootReducerType } from '../state/helpers';
import { toKeyedAction } from '../state/keyedVariablesReducer';
import {
addVariable,
setCurrentVariableValue,
variableStateFailed,
variableStateFetching,
} from '../state/sharedReducer';
import { variablesInitTransaction } from '../state/transactionReducer';
import { toKeyedVariableIdentifier, toVariablePayload } from '../utils';
import { updateAutoValue, UpdateAutoValueDependencies, updateIntervalVariableOptions } from './actions';
import { createIntervalVariableAdapter } from './adapter';
import { createIntervalOptions } from './reducer';
describe('interval actions', () => {
variableAdapters.setInit(() => [createIntervalVariableAdapter()]);
describe('when updateIntervalVariableOptions is dispatched', () => {
it('then correct actions are dispatched', async () => {
const interval = intervalBuilder()
.withId('0')
.withRootStateKey('key')
.withQuery('1s,1m,1h,1d')
.withAuto(false)
.build();
const tester = await reduxTester<RootReducerType>()
.givenRootReducer(getRootReducer())
.whenActionIsDispatched(
toKeyedAction('key', addVariable(toVariablePayload(interval, { global: false, index: 0, model: interval })))
)
.whenAsyncActionIsDispatched(updateIntervalVariableOptions(toKeyedVariableIdentifier(interval)), true);
tester.thenDispatchedActionsShouldEqual(
toKeyedAction('key', createIntervalOptions({ type: 'interval', id: '0', data: undefined })),
toKeyedAction(
'key',
setCurrentVariableValue({
type: 'interval',
id: '0',
data: { option: { text: '1s', value: '1s', selected: false } },
})
)
);
});
});
describe('when updateOptions is dispatched but something throws', () => {
silenceConsoleOutput();
const originalTimeSrv = getTimeSrv();
beforeEach(() => {
const timeSrvMock = {
timeRange: jest.fn().mockReturnValue({
from: dateTime(new Date()).subtract(1, 'days').toDate(),
to: new Date(),
raw: {
from: 'now-1d',
to: 'now',
},
}),
} as unknown as TimeSrv;
setTimeSrv(timeSrvMock);
});
afterEach(() => {
setTimeSrv(originalTimeSrv);
});
it('then an notifyApp action should be dispatched', async () => {
const interval = intervalBuilder()
.withId('0')
.withRootStateKey('key')
.withQuery('1s,1m,1h,1d')
.withAuto(true)
.withAutoMin('1xyz') // illegal interval string
.build();
const tester = await reduxTester<RootReducerType>()
.givenRootReducer(getRootReducer())
.whenActionIsDispatched(
toKeyedAction('key', addVariable(toVariablePayload(interval, { global: false, index: 0, model: interval })))
)
.whenActionIsDispatched(toKeyedAction('key', variablesInitTransaction({ uid: 'key' })))
.whenAsyncActionIsDispatched(updateOptions(toKeyedVariableIdentifier(interval)), true);
tester.thenDispatchedActionsPredicateShouldEqual((dispatchedActions) => {
const expectedNumberOfActions = 4;
expect(dispatchedActions[0]).toEqual(toKeyedAction('key', variableStateFetching(toVariablePayload(interval))));
expect(dispatchedActions[1]).toEqual(toKeyedAction('key', createIntervalOptions(toVariablePayload(interval))));
expect(dispatchedActions[2]).toEqual(
toKeyedAction(
'key',
variableStateFailed(
toVariablePayload(interval, {
error: new Error(
'Invalid interval string, has to be either unit-less or end with one of the following units: "y, M, w, d, h, m, s, ms"'
),
})
)
)
);
expect(dispatchedActions[3].type).toEqual(notifyApp.type);
expect(dispatchedActions[3].payload.title).toEqual('Templating [0]');
expect(dispatchedActions[3].payload.text).toEqual(
'Error updating options: Invalid interval string, has to be either unit-less or end with one of the following units: "y, M, w, d, h, m, s, ms"'
);
expect(dispatchedActions[3].payload.severity).toEqual('error');
return dispatchedActions.length === expectedNumberOfActions;
});
});
describe('but there is no ongoing transaction', () => {
it('then no actions are dispatched', async () => {
const interval = intervalBuilder()
.withId('0')
.withRootStateKey('key')
.withQuery('1s,1m,1h,1d')
.withAuto(true)
.withAutoMin('1xyz') // illegal interval string
.build();
const tester = await reduxTester<RootReducerType>()
.givenRootReducer(getRootReducer())
.whenActionIsDispatched(
toKeyedAction('key', addVariable(toVariablePayload(interval, { global: false, index: 0, model: interval })))
)
.whenAsyncActionIsDispatched(updateOptions(toKeyedVariableIdentifier(interval)), true);
tester.thenNoActionsWhereDispatched();
});
});
});
describe('when updateAutoValue is dispatched', () => {
describe('and auto is false', () => {
it('then no dependencies are called', async () => {
const interval = intervalBuilder().withId('0').withRootStateKey('key').withAuto(false).build();
const dependencies: UpdateAutoValueDependencies = {
calculateInterval: jest.fn(),
getTimeSrv: () => {
return {
timeRange: jest.fn().mockReturnValue({
from: '2001-01-01',
to: '2001-01-02',
raw: {
from: '2001-01-01',
to: '2001-01-02',
},
}),
} as unknown as TimeSrv;
},
templateSrv: {
setGrafanaVariable: jest.fn(),
} as unknown as TemplateSrv,
};
await reduxTester<RootReducerType>()
.givenRootReducer(getRootReducer())
.whenActionIsDispatched(
toKeyedAction('key', addVariable(toVariablePayload(interval, { global: false, index: 0, model: interval })))
)
.whenAsyncActionIsDispatched(updateAutoValue(toKeyedVariableIdentifier(interval), dependencies), true);
expect(dependencies.calculateInterval).toHaveBeenCalledTimes(0);
expect(dependencies.getTimeSrv().timeRange).toHaveBeenCalledTimes(0);
expect(dependencies.templateSrv.setGrafanaVariable).toHaveBeenCalledTimes(0);
});
});
describe('and auto is true', () => {
it('then correct dependencies are called', async () => {
const interval = intervalBuilder()
.withId('0')
.withRootStateKey('key')
.withName('intervalName')
.withAuto(true)
.withAutoCount(33)
.withAutoMin('13s')
.build();
const timeRangeMock = jest.fn().mockReturnValue({
from: '2001-01-01',
to: '2001-01-02',
raw: {
from: '2001-01-01',
to: '2001-01-02',
},
});
const setGrafanaVariableMock = jest.fn();
const dependencies: UpdateAutoValueDependencies = {
calculateInterval: jest.fn().mockReturnValue({ interval: '10s' }),
getTimeSrv: () => {
return {
timeRange: timeRangeMock,
} as unknown as TimeSrv;
},
templateSrv: {
setGrafanaVariable: setGrafanaVariableMock,
} as unknown as TemplateSrv,
};
await reduxTester<RootReducerType>()
.givenRootReducer(getRootReducer())
.whenActionIsDispatched(
toKeyedAction('key', addVariable(toVariablePayload(interval, { global: false, index: 0, model: interval })))
)
.whenAsyncActionIsDispatched(updateAutoValue(toKeyedVariableIdentifier(interval), dependencies), true);
expect(dependencies.calculateInterval).toHaveBeenCalledTimes(1);
expect(dependencies.calculateInterval).toHaveBeenCalledWith(
{
from: '2001-01-01',
to: '2001-01-02',
raw: {
from: '2001-01-01',
to: '2001-01-02',
},
},
33,
'13s'
);
expect(timeRangeMock).toHaveBeenCalledTimes(1);
expect(setGrafanaVariableMock).toHaveBeenCalledTimes(2);
expect(setGrafanaVariableMock.mock.calls[0][0]).toBe('$__auto_interval_intervalName');
expect(setGrafanaVariableMock.mock.calls[0][1]).toBe('10s');
expect(setGrafanaVariableMock.mock.calls[1][0]).toBe('$__auto_interval');
expect(setGrafanaVariableMock.mock.calls[1][1]).toBe('10s');
});
});
});
});