initVariableTransaction.test.ts 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205
  1. import { DataSourceRef, LoadingState } from '@grafana/data/src';
  2. import { setDataSourceSrv } from '@grafana/runtime/src';
  3. import { reduxTester } from '../../../../test/core/redux/reduxTester';
  4. import { toAsyncOfResult } from '../../query/state/DashboardQueryRunner/testHelpers';
  5. import { variableAdapters } from '../adapters';
  6. import { createAdHocVariableAdapter } from '../adhoc/adapter';
  7. import { createConstantVariableAdapter } from '../constant/adapter';
  8. import { createDataSourceVariableAdapter } from '../datasource/adapter';
  9. import { createDataSourceOptions } from '../datasource/reducer';
  10. import { cleanEditorState } from '../editor/reducer';
  11. import { cleanPickerState } from '../pickers/OptionsPicker/reducer';
  12. import { setVariableQueryRunner } from '../query/VariableQueryRunner';
  13. import { createQueryVariableAdapter } from '../query/adapter';
  14. import { adHocBuilder, constantBuilder, datasourceBuilder, queryBuilder } from '../shared/testing/builders';
  15. import { TransactionStatus, VariableModel } from '../types';
  16. import { toVariablePayload } from '../utils';
  17. import { initVariablesTransaction } from './actions';
  18. import { getPreloadedState, getRootReducer, RootReducerType } from './helpers';
  19. import { toKeyedAction } from './keyedVariablesReducer';
  20. import {
  21. addVariable,
  22. changeVariableProp,
  23. setCurrentVariableValue,
  24. variableStateCompleted,
  25. variableStateFetching,
  26. variableStateNotStarted,
  27. } from './sharedReducer';
  28. import {
  29. initialTransactionState,
  30. variablesClearTransaction,
  31. variablesCompleteTransaction,
  32. variablesInitTransaction,
  33. } from './transactionReducer';
  34. import { cleanVariables } from './variablesReducer';
  35. variableAdapters.setInit(() => [
  36. createQueryVariableAdapter(),
  37. createConstantVariableAdapter(),
  38. createAdHocVariableAdapter(),
  39. createDataSourceVariableAdapter(),
  40. ]);
  41. function getTestContext(variables?: VariableModel[]) {
  42. const key = 'key';
  43. const constant = constantBuilder().withId('constant').withName('constant').build();
  44. const templating = { list: variables ?? [constant] };
  45. const getInstanceSettingsMock = jest.fn().mockReturnValue(undefined);
  46. setDataSourceSrv({
  47. get: jest.fn().mockResolvedValue({}),
  48. getList: jest.fn().mockReturnValue([]),
  49. getInstanceSettings: getInstanceSettingsMock,
  50. reload: jest.fn(),
  51. });
  52. const variableQueryRunner: any = {
  53. cancelRequest: jest.fn(),
  54. queueRequest: jest.fn(),
  55. getResponse: () => toAsyncOfResult({ state: LoadingState.Done, identifier: { type: 'query', id: 'query' } }),
  56. destroy: jest.fn(),
  57. };
  58. setVariableQueryRunner(variableQueryRunner);
  59. const dashboard: any = { title: 'Some dash', uid: key, templating };
  60. return { constant, getInstanceSettingsMock, templating, key, dashboard };
  61. }
  62. describe('initVariablesTransaction', () => {
  63. describe('when called and the previous dashboard has completed', () => {
  64. it('then correct actions are dispatched', async () => {
  65. const { constant, key, dashboard } = getTestContext();
  66. const tester = await reduxTester<RootReducerType>()
  67. .givenRootReducer(getRootReducer())
  68. .whenAsyncActionIsDispatched(initVariablesTransaction(key, dashboard));
  69. tester.thenDispatchedActionsPredicateShouldEqual((dispatchedActions) => {
  70. expect(dispatchedActions[0]).toEqual(toKeyedAction(key, variablesInitTransaction({ uid: key })));
  71. expect(dispatchedActions[1].payload.action.type).toEqual(addVariable.type);
  72. expect(dispatchedActions[1].payload.action.payload.id).toEqual('__dashboard');
  73. expect(dispatchedActions[2].payload.action.type).toEqual(addVariable.type);
  74. expect(dispatchedActions[2].payload.action.payload.id).toEqual('__org');
  75. expect(dispatchedActions[3].payload.action.type).toEqual(addVariable.type);
  76. expect(dispatchedActions[3].payload.action.payload.id).toEqual('__user');
  77. expect(dispatchedActions[4]).toEqual(
  78. toKeyedAction(key, addVariable(toVariablePayload(constant, { global: false, index: 0, model: constant })))
  79. );
  80. expect(dispatchedActions[5]).toEqual(toKeyedAction(key, variableStateNotStarted(toVariablePayload(constant))));
  81. expect(dispatchedActions[6]).toEqual(toKeyedAction(key, variableStateCompleted(toVariablePayload(constant))));
  82. expect(dispatchedActions[7]).toEqual(toKeyedAction(key, variablesCompleteTransaction({ uid: key })));
  83. return dispatchedActions.length === 8;
  84. });
  85. });
  86. describe('and there are variables that have data source that need to be migrated', () => {
  87. it('then correct actions are dispatched', async () => {
  88. const legacyDs = '${ds}' as unknown as DataSourceRef;
  89. const ds = datasourceBuilder().withId('ds').withRootStateKey('key').withName('ds').withQuery('prom').build();
  90. const query = queryBuilder()
  91. .withId('query')
  92. .withRootStateKey('key')
  93. .withName('query')
  94. .withDatasource(legacyDs)
  95. .build();
  96. const adhoc = adHocBuilder()
  97. .withId('adhoc')
  98. .withRootStateKey('key')
  99. .withName('adhoc')
  100. .withDatasource(legacyDs)
  101. .build();
  102. const { key, dashboard } = getTestContext([ds, query, adhoc]);
  103. const tester = await reduxTester<RootReducerType>()
  104. .givenRootReducer(getRootReducer())
  105. .whenAsyncActionIsDispatched(initVariablesTransaction(key, dashboard));
  106. tester.thenDispatchedActionsPredicateShouldEqual((dispatchedActions) => {
  107. expect(dispatchedActions[0]).toEqual(toKeyedAction(key, variablesInitTransaction({ uid: key })));
  108. expect(dispatchedActions[1].payload.action.type).toEqual(addVariable.type);
  109. expect(dispatchedActions[1].payload.action.payload.id).toEqual('__dashboard');
  110. expect(dispatchedActions[2].payload.action.type).toEqual(addVariable.type);
  111. expect(dispatchedActions[2].payload.action.payload.id).toEqual('__org');
  112. expect(dispatchedActions[3].payload.action.type).toEqual(addVariable.type);
  113. expect(dispatchedActions[3].payload.action.payload.id).toEqual('__user');
  114. expect(dispatchedActions[4]).toEqual(
  115. toKeyedAction(key, addVariable(toVariablePayload(ds, { global: false, index: 0, model: ds })))
  116. );
  117. expect(dispatchedActions[5]).toEqual(
  118. toKeyedAction(key, addVariable(toVariablePayload(query, { global: false, index: 1, model: query })))
  119. );
  120. expect(dispatchedActions[6]).toEqual(
  121. toKeyedAction(key, addVariable(toVariablePayload(adhoc, { global: false, index: 2, model: adhoc })))
  122. );
  123. expect(dispatchedActions[7]).toEqual(toKeyedAction(key, variableStateNotStarted(toVariablePayload(ds))));
  124. expect(dispatchedActions[8]).toEqual(toKeyedAction(key, variableStateNotStarted(toVariablePayload(query))));
  125. expect(dispatchedActions[9]).toEqual(toKeyedAction(key, variableStateNotStarted(toVariablePayload(adhoc))));
  126. expect(dispatchedActions[10]).toEqual(
  127. toKeyedAction(
  128. key,
  129. changeVariableProp(toVariablePayload(query, { propName: 'datasource', propValue: { uid: '${ds}' } }))
  130. )
  131. );
  132. expect(dispatchedActions[11]).toEqual(
  133. toKeyedAction(
  134. key,
  135. changeVariableProp(toVariablePayload(adhoc, { propName: 'datasource', propValue: { uid: '${ds}' } }))
  136. )
  137. );
  138. expect(dispatchedActions[12]).toEqual(toKeyedAction(key, variableStateFetching(toVariablePayload(ds))));
  139. expect(dispatchedActions[13]).toEqual(toKeyedAction(key, variableStateCompleted(toVariablePayload(adhoc))));
  140. expect(dispatchedActions[14]).toEqual(
  141. toKeyedAction(key, createDataSourceOptions(toVariablePayload(ds, { sources: [], regex: undefined })))
  142. );
  143. expect(dispatchedActions[15]).toEqual(
  144. toKeyedAction(
  145. key,
  146. setCurrentVariableValue(
  147. toVariablePayload(ds, { option: { selected: false, text: 'No data sources found', value: '' } })
  148. )
  149. )
  150. );
  151. expect(dispatchedActions[16]).toEqual(toKeyedAction(key, variableStateCompleted(toVariablePayload(ds))));
  152. expect(dispatchedActions[17]).toEqual(toKeyedAction(key, variableStateFetching(toVariablePayload(query))));
  153. expect(dispatchedActions[18]).toEqual(toKeyedAction(key, variableStateCompleted(toVariablePayload(query))));
  154. expect(dispatchedActions[19]).toEqual(toKeyedAction(key, variablesCompleteTransaction({ uid: key })));
  155. return dispatchedActions.length === 20;
  156. });
  157. });
  158. });
  159. });
  160. describe('when called and the previous dashboard is still processing variables', () => {
  161. it('then correct actions are dispatched', async () => {
  162. const { constant, key, dashboard } = getTestContext();
  163. const transactionState = { ...initialTransactionState, uid: 'previous-uid', status: TransactionStatus.Fetching };
  164. const preloadedState = getPreloadedState(key, { transaction: transactionState });
  165. const tester = await reduxTester<RootReducerType>({ preloadedState })
  166. .givenRootReducer(getRootReducer())
  167. .whenAsyncActionIsDispatched(initVariablesTransaction(key, dashboard));
  168. tester.thenDispatchedActionsPredicateShouldEqual((dispatchedActions) => {
  169. expect(dispatchedActions[0]).toEqual(toKeyedAction(key, cleanVariables()));
  170. expect(dispatchedActions[1]).toEqual(toKeyedAction(key, cleanEditorState()));
  171. expect(dispatchedActions[2]).toEqual(toKeyedAction(key, cleanPickerState()));
  172. expect(dispatchedActions[3]).toEqual(toKeyedAction(key, variablesClearTransaction()));
  173. expect(dispatchedActions[4]).toEqual(toKeyedAction(key, variablesInitTransaction({ uid: key })));
  174. expect(dispatchedActions[5].payload.action.type).toEqual(addVariable.type);
  175. expect(dispatchedActions[5].payload.action.payload.id).toEqual('__dashboard');
  176. expect(dispatchedActions[6].payload.action.type).toEqual(addVariable.type);
  177. expect(dispatchedActions[6].payload.action.payload.id).toEqual('__org');
  178. expect(dispatchedActions[7].payload.action.type).toEqual(addVariable.type);
  179. expect(dispatchedActions[7].payload.action.payload.id).toEqual('__user');
  180. expect(dispatchedActions[8]).toEqual(
  181. toKeyedAction(key, addVariable(toVariablePayload(constant, { global: false, index: 0, model: constant })))
  182. );
  183. expect(dispatchedActions[9]).toEqual(toKeyedAction(key, variableStateNotStarted(toVariablePayload(constant))));
  184. expect(dispatchedActions[10]).toEqual(toKeyedAction(key, variableStateCompleted(toVariablePayload(constant))));
  185. expect(dispatchedActions[11]).toEqual(toKeyedAction(key, variablesCompleteTransaction({ uid: key })));
  186. return dispatchedActions.length === 12;
  187. });
  188. });
  189. });
  190. });