templateVarsChangedInUrl.test.ts 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. import { DashboardState, StoreState } from '../../../types';
  2. import { DashboardModel, PanelModel } from '../../dashboard/state';
  3. import { initialState } from '../../dashboard/state/reducers';
  4. import { variableAdapters } from '../adapters';
  5. import { createConstantVariableAdapter } from '../constant/adapter';
  6. import { createCustomVariableAdapter } from '../custom/adapter';
  7. import { constantBuilder, customBuilder } from '../shared/testing/builders';
  8. import { VariableModel } from '../types';
  9. import { ExtendedUrlQueryMap } from '../utils';
  10. import { templateVarsChangedInUrl } from './actions';
  11. import { getPreloadedState } from './helpers';
  12. import { VariablesState } from './types';
  13. const dashboardModel = new DashboardModel({});
  14. variableAdapters.setInit(() => [createCustomVariableAdapter(), createConstantVariableAdapter()]);
  15. async function getTestContext(urlQueryMap: ExtendedUrlQueryMap = {}, variable: VariableModel | undefined = undefined) {
  16. jest.clearAllMocks();
  17. const key = 'key';
  18. if (!variable) {
  19. variable = customBuilder()
  20. .withId('variable')
  21. .withRootStateKey(key)
  22. .withName('variable')
  23. .withCurrent(['A', 'C'])
  24. .withOptions('A', 'B', 'C')
  25. .build();
  26. }
  27. const variableB = customBuilder()
  28. .withId('variableB')
  29. .withRootStateKey(key)
  30. .withName('variableB')
  31. .withCurrent(['B'])
  32. .withOptions('A', 'B', 'C')
  33. .build();
  34. const setValueFromUrlMock = jest.fn();
  35. variableAdapters.get(variable.type).setValueFromUrl = setValueFromUrlMock;
  36. const modelJson = {
  37. id: 1,
  38. type: 'table',
  39. maxDataPoints: 100,
  40. interval: '5m',
  41. showColumns: true,
  42. targets: [{ refId: 'A', queryType: '${variable}' }, { noRefId: true }],
  43. options: null,
  44. fieldConfig: {
  45. defaults: {
  46. unit: 'mpg',
  47. thresholds: {
  48. mode: 'absolute',
  49. steps: [
  50. { color: 'green', value: null },
  51. { color: 'red', value: 80 },
  52. ],
  53. },
  54. },
  55. overrides: [
  56. {
  57. matcher: {
  58. id: '1',
  59. options: {},
  60. },
  61. properties: [
  62. {
  63. id: 'thresholds',
  64. value: {
  65. mode: 'absolute',
  66. steps: [
  67. { color: 'green', value: null },
  68. { color: 'red', value: 80 },
  69. ],
  70. },
  71. },
  72. ],
  73. },
  74. ],
  75. },
  76. };
  77. const panelModelA = new PanelModel(modelJson);
  78. const panelModelB = new PanelModel({ ...modelJson, id: 2, targets: [{ refId: 'B', queryType: '${variableB}' }] });
  79. const templateVariableValueUpdatedMock = jest.fn();
  80. const startRefreshMock = jest.fn();
  81. const dashboard: DashboardState = {
  82. ...initialState,
  83. getModel: () => {
  84. dashboardModel.templateVariableValueUpdated = templateVariableValueUpdatedMock;
  85. dashboardModel.startRefresh = startRefreshMock;
  86. dashboardModel.templating = { list: [variable] };
  87. dashboardModel.panels = [panelModelA, panelModelB];
  88. return dashboardModel;
  89. },
  90. };
  91. const variables: VariablesState = { variable, variableB };
  92. const state: Partial<StoreState> = {
  93. dashboard,
  94. ...getPreloadedState(key, { variables }),
  95. };
  96. const getState = () => state as unknown as StoreState;
  97. const dispatch = jest.fn();
  98. const thunk = templateVarsChangedInUrl(key, urlQueryMap);
  99. await thunk(dispatch, getState, undefined);
  100. return { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock, variable, variableB };
  101. }
  102. describe('templateVarsChangedInUrl', () => {
  103. describe('when called with no variables in url query map', () => {
  104. it('then no value should change and dashboard should not be refreshed', async () => {
  105. const { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock } = await getTestContext();
  106. expect(setValueFromUrlMock).not.toHaveBeenCalled();
  107. expect(templateVariableValueUpdatedMock).not.toHaveBeenCalled();
  108. expect(startRefreshMock).not.toHaveBeenCalled();
  109. });
  110. });
  111. describe('when called with no variables in url query map matching variables in state', () => {
  112. it('then no value should change and dashboard should not be refreshed', async () => {
  113. const { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock } = await getTestContext({
  114. 'var-query': { value: 'A' },
  115. });
  116. expect(setValueFromUrlMock).not.toHaveBeenCalled();
  117. expect(templateVariableValueUpdatedMock).not.toHaveBeenCalled();
  118. expect(startRefreshMock).not.toHaveBeenCalled();
  119. });
  120. });
  121. describe('when called with variables in url query map matching variables in state', () => {
  122. describe('and the values in url query map are the same as current in state', () => {
  123. it('then no value should change and dashboard should not be refreshed', async () => {
  124. const { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock } = await getTestContext({
  125. 'var-variable': { value: ['A', 'C'] },
  126. });
  127. expect(setValueFromUrlMock).not.toHaveBeenCalled();
  128. expect(templateVariableValueUpdatedMock).not.toHaveBeenCalled();
  129. expect(startRefreshMock).not.toHaveBeenCalled();
  130. });
  131. });
  132. describe('and the values in url query map are the not the same as current in state', () => {
  133. it('then the value should change to the value in url query map and dashboard should be refreshed', async () => {
  134. const { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock, variable } =
  135. await getTestContext({
  136. 'var-variable': { value: 'B' },
  137. });
  138. expect(setValueFromUrlMock).toHaveBeenCalledTimes(1);
  139. expect(setValueFromUrlMock).toHaveBeenCalledWith(variable, 'B');
  140. expect(templateVariableValueUpdatedMock).toHaveBeenCalledTimes(1);
  141. expect(startRefreshMock).toHaveBeenCalledTimes(1);
  142. expect(startRefreshMock).toHaveBeenCalledWith({ refreshAll: false, panelIds: [1] });
  143. });
  144. it('should update URL value and only refresh panels with variableB dependency', async () => {
  145. const { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock, variableB } =
  146. await getTestContext({
  147. 'var-variableB': { value: 'A' },
  148. });
  149. expect(setValueFromUrlMock).toHaveBeenCalledTimes(1);
  150. expect(setValueFromUrlMock).toHaveBeenCalledWith(variableB, 'A');
  151. expect(templateVariableValueUpdatedMock).toHaveBeenCalledTimes(1);
  152. expect(startRefreshMock).toHaveBeenCalledTimes(1);
  153. expect(startRefreshMock).toHaveBeenCalledWith({ refreshAll: false, panelIds: [2] });
  154. });
  155. describe('but the values in url query map were removed', () => {
  156. it('then the value should change to the value in dashboard json and dashboard should be refreshed', async () => {
  157. const { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock, variable } =
  158. await getTestContext({
  159. 'var-variable': { value: '', removed: true },
  160. });
  161. expect(setValueFromUrlMock).toHaveBeenCalledTimes(1);
  162. expect(setValueFromUrlMock).toHaveBeenCalledWith(variable, ['A', 'C']);
  163. expect(templateVariableValueUpdatedMock).toHaveBeenCalledTimes(1);
  164. expect(startRefreshMock).toHaveBeenCalledTimes(1);
  165. });
  166. });
  167. describe('and the variable is a constant', () => {
  168. it('then the value should change to the value in dashboard json and dashboard should be refreshed', async () => {
  169. const constant = constantBuilder()
  170. .withId('variable')
  171. .withRootStateKey('key')
  172. .withName('variable')
  173. .withQuery('default value in dash.json')
  174. .build();
  175. const { setValueFromUrlMock, templateVariableValueUpdatedMock, startRefreshMock, variable } =
  176. await getTestContext(
  177. {
  178. 'var-variable': { value: '', removed: true },
  179. },
  180. constant
  181. );
  182. expect(setValueFromUrlMock).toHaveBeenCalledTimes(1);
  183. expect(setValueFromUrlMock).toHaveBeenCalledWith(variable, 'default value in dash.json');
  184. expect(templateVariableValueUpdatedMock).toHaveBeenCalledTimes(1);
  185. expect(startRefreshMock).toHaveBeenCalledTimes(1);
  186. });
  187. });
  188. });
  189. });
  190. });