grafana/public/app/features/variables/state/templateVarsChangedInUrl.test.ts
Josh Hunt 1a683e53c5
Typed variables pt2: Use type-accurate mock variables in tests (#52987)
* wip

* make diff easier to read

* Update template_srv getVariables to return new TypedVariableModel

* update VariableType to use the type from TypedVariableModel

* tidy things up

* Chore: Use type-accurate mock variables in tests

* make createBaseVariableModel take the variable type
2022-08-02 14:47:41 +01:00

223 lines
8.3 KiB
TypeScript

import { TypedVariableModel } from '@grafana/data';
import { DashboardState, StoreState } from '../../../types';
import { DashboardModel, PanelModel } from '../../dashboard/state';
import { initialState } from '../../dashboard/state/reducers';
import { variableAdapters } from '../adapters';
import { createConstantVariableAdapter } from '../constant/adapter';
import { createCustomVariableAdapter } from '../custom/adapter';
import { constantBuilder, customBuilder } from '../shared/testing/builders';
import { ExtendedUrlQueryMap } from '../utils';
import { templateVarsChangedInUrl } from './actions';
import { getPreloadedState } from './helpers';
import { VariablesState } from './types';
const dashboardModel = new DashboardModel({});
variableAdapters.setInit(() => [createCustomVariableAdapter(), createConstantVariableAdapter()]);
async function getTestContext(
urlQueryMap: ExtendedUrlQueryMap = {},
variable: TypedVariableModel | undefined = undefined
) {
jest.clearAllMocks();
const key = 'key';
if (!variable) {
variable = customBuilder()
.withId('variable')
.withRootStateKey(key)
.withName('variable')
.withCurrent(['A', 'C'])
.withOptions('A', 'B', 'C')
.build();
}
const variableB = customBuilder()
.withId('variableB')
.withRootStateKey(key)
.withName('variableB')
.withCurrent(['B'])
.withOptions('A', 'B', 'C')
.build();
const setValueFromUrlMock = jest.fn();
variableAdapters.get(variable.type).setValueFromUrl = setValueFromUrlMock;
const modelJson = {
id: 1,
type: 'table',
maxDataPoints: 100,
interval: '5m',
showColumns: true,
targets: [{ refId: 'A', queryType: '${variable}' }, { noRefId: true }],
options: null,
fieldConfig: {
defaults: {
unit: 'mpg',
thresholds: {
mode: 'absolute',
steps: [
{ color: 'green', value: null },
{ color: 'red', value: 80 },
],
},
},
overrides: [
{
matcher: {
id: '1',
options: {},
},
properties: [
{
id: 'thresholds',
value: {
mode: 'absolute',
steps: [
{ color: 'green', value: null },
{ color: 'red', value: 80 },
],
},
},
],
},
],
},
};
const panelModelA = new PanelModel(modelJson);
const panelModelB = new PanelModel({ ...modelJson, id: 2, targets: [{ refId: 'B', queryType: '${variableB}' }] });
const templateVariableValueUpdatedMock = jest.fn();
const startRefreshMock = jest.fn();
const dashboard: DashboardState = {
...initialState,
getModel: () => {
dashboardModel.templateVariableValueUpdated = templateVariableValueUpdatedMock;
dashboardModel.startRefresh = startRefreshMock;
dashboardModel.templating = { list: [variable] };
dashboardModel.panels = [panelModelA, panelModelB];
return dashboardModel;
},
};
const variables: VariablesState = { variable, variableB };
const state: Partial<StoreState> = {
dashboard,
...getPreloadedState(key, { variables }),
};
const getState = () => state as unknown as StoreState;
const dispatch = jest.fn();
const thunk = templateVarsChangedInUrl(key, urlQueryMap);
await thunk(dispatch, getState, undefined);
return { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock, variable, variableB };
}
describe('templateVarsChangedInUrl', () => {
describe('when called with no variables in url query map', () => {
it('then no value should change and dashboard should not be refreshed', async () => {
const { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock } = await getTestContext();
expect(setValueFromUrlMock).not.toHaveBeenCalled();
expect(templateVariableValueUpdatedMock).not.toHaveBeenCalled();
expect(startRefreshMock).not.toHaveBeenCalled();
});
});
describe('when called with no variables in url query map matching variables in state', () => {
it('then no value should change and dashboard should not be refreshed', async () => {
const { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock } = await getTestContext({
'var-query': { value: 'A' },
});
expect(setValueFromUrlMock).not.toHaveBeenCalled();
expect(templateVariableValueUpdatedMock).not.toHaveBeenCalled();
expect(startRefreshMock).not.toHaveBeenCalled();
});
});
describe('when called with variables in url query map matching variables in state', () => {
describe('and the values in url query map are the same as current in state', () => {
it('then no value should change and dashboard should not be refreshed', async () => {
const { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock } = await getTestContext({
'var-variable': { value: ['A', 'C'] },
});
expect(setValueFromUrlMock).not.toHaveBeenCalled();
expect(templateVariableValueUpdatedMock).not.toHaveBeenCalled();
expect(startRefreshMock).not.toHaveBeenCalled();
});
});
describe('and the values in url query map are the not the same as current in state', () => {
it('then the value should change to the value in url query map and dashboard should be refreshed', async () => {
const { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock, variable } =
await getTestContext({
'var-variable': { value: 'B' },
});
expect(setValueFromUrlMock).toHaveBeenCalledTimes(1);
expect(setValueFromUrlMock).toHaveBeenCalledWith(variable, 'B');
expect(templateVariableValueUpdatedMock).toHaveBeenCalledTimes(1);
expect(startRefreshMock).toHaveBeenCalledTimes(1);
expect(startRefreshMock).toHaveBeenCalledWith({ refreshAll: false, panelIds: [1] });
});
it('should update URL value and only refresh panels with variableB dependency', async () => {
const { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock, variableB } =
await getTestContext({
'var-variableB': { value: 'A' },
});
expect(setValueFromUrlMock).toHaveBeenCalledTimes(1);
expect(setValueFromUrlMock).toHaveBeenCalledWith(variableB, 'A');
expect(templateVariableValueUpdatedMock).toHaveBeenCalledTimes(1);
expect(startRefreshMock).toHaveBeenCalledTimes(1);
expect(startRefreshMock).toHaveBeenCalledWith({ refreshAll: false, panelIds: [2] });
});
describe('but the values in url query map were removed', () => {
it('then the value should change to the value in dashboard json and dashboard should be refreshed', async () => {
const { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock, variable } =
await getTestContext({
'var-variable': { value: '', removed: true },
});
expect(setValueFromUrlMock).toHaveBeenCalledTimes(1);
expect(setValueFromUrlMock).toHaveBeenCalledWith(variable, ['A', 'C']);
expect(templateVariableValueUpdatedMock).toHaveBeenCalledTimes(1);
expect(startRefreshMock).toHaveBeenCalledTimes(1);
});
});
describe('and the variable is a constant', () => {
it('then the value should change to the value in dashboard json and dashboard should be refreshed', async () => {
const constant = constantBuilder()
.withId('variable')
.withRootStateKey('key')
.withName('variable')
.withQuery('default value in dash.json')
.build();
const { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock, variable } =
await getTestContext(
{
'var-variable': { value: '', removed: true },
},
constant
);
expect(setValueFromUrlMock).toHaveBeenCalledTimes(1);
expect(setValueFromUrlMock).toHaveBeenCalledWith(variable, 'default value in dash.json');
expect(templateVariableValueUpdatedMock).toHaveBeenCalledTimes(1);
expect(startRefreshMock).toHaveBeenCalledTimes(1);
});
});
});
});
});