operators.test.ts 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. import { of } from 'rxjs';
  2. import { FieldType, toDataFrame } from '@grafana/data';
  3. import { queryBuilder } from '../shared/testing/builders';
  4. import { toKeyedAction } from '../state/keyedVariablesReducer';
  5. import { areMetricFindValues, toMetricFindValues, updateOptionsState, validateVariableSelection } from './operators';
  6. import { updateVariableOptions } from './reducer';
  7. describe('operators', () => {
  8. beforeEach(() => {
  9. jest.clearAllMocks();
  10. });
  11. describe('validateVariableSelection', () => {
  12. describe('when called', () => {
  13. it('then the correct observable should be created', async () => {
  14. const variable = queryBuilder().withId('query').withRootStateKey('key').build();
  15. const dispatch = jest.fn().mockResolvedValue({});
  16. const observable = of(undefined).pipe(validateVariableSelection({ variable, dispatch }));
  17. await expect(observable).toEmitValuesWith((received) => {
  18. expect(received[0]).toEqual({});
  19. expect(dispatch).toHaveBeenCalledTimes(1);
  20. });
  21. });
  22. });
  23. });
  24. describe('updateOptionsState', () => {
  25. describe('when called', () => {
  26. it('then the correct observable should be created', async () => {
  27. const variable = queryBuilder().withId('query').withRootStateKey('key').build();
  28. const dispatch = jest.fn();
  29. const getTemplatedRegexFunc = jest.fn().mockReturnValue('getTemplatedRegexFunc result');
  30. const observable = of([{ text: 'A' }]).pipe(updateOptionsState({ variable, dispatch, getTemplatedRegexFunc }));
  31. await expect(observable).toEmitValuesWith((received) => {
  32. const value = received[0];
  33. expect(value).toEqual(undefined);
  34. expect(getTemplatedRegexFunc).toHaveBeenCalledTimes(1);
  35. expect(dispatch).toHaveBeenCalledTimes(1);
  36. expect(dispatch).toHaveBeenCalledWith(
  37. toKeyedAction(
  38. 'key',
  39. updateVariableOptions({
  40. id: 'query',
  41. type: 'query',
  42. data: { results: [{ text: 'A' }], templatedRegex: 'getTemplatedRegexFunc result' },
  43. })
  44. )
  45. );
  46. });
  47. });
  48. });
  49. });
  50. describe('toMetricFindValues', () => {
  51. const frameWithTextField = toDataFrame({
  52. fields: [{ name: 'text', type: FieldType.string, values: ['A', 'B', 'C'] }],
  53. });
  54. const frameWithValueField = toDataFrame({
  55. fields: [{ name: 'value', type: FieldType.string, values: ['A', 'B', 'C'] }],
  56. });
  57. const frameWithTextAndValueField = toDataFrame({
  58. fields: [
  59. { name: 'text', type: FieldType.string, values: ['TA', 'TB', 'TC'] },
  60. { name: 'value', type: FieldType.string, values: ['VA', 'VB', 'VC'] },
  61. ],
  62. });
  63. const frameWithAStringField = toDataFrame({
  64. fields: [{ name: 'label', type: FieldType.string, values: ['A', 'B', 'C'] }],
  65. });
  66. const frameWithExpandableField = toDataFrame({
  67. fields: [
  68. { name: 'label', type: FieldType.string, values: ['A', 'B', 'C'] },
  69. { name: 'expandable', type: FieldType.boolean, values: [true, false, true] },
  70. ],
  71. });
  72. // it.each wouldn't work here as we need the done callback
  73. [
  74. { series: null, expected: [] },
  75. { series: undefined, expected: [] },
  76. { series: [], expected: [] },
  77. { series: [{ text: '' }], expected: [{ text: '' }] },
  78. { series: [{ value: '' }], expected: [{ value: '' }] },
  79. {
  80. series: [frameWithTextField],
  81. expected: [
  82. { text: 'A', value: 'A' },
  83. { text: 'B', value: 'B' },
  84. { text: 'C', value: 'C' },
  85. ],
  86. },
  87. {
  88. series: [frameWithValueField],
  89. expected: [
  90. { text: 'A', value: 'A' },
  91. { text: 'B', value: 'B' },
  92. { text: 'C', value: 'C' },
  93. ],
  94. },
  95. {
  96. series: [frameWithTextAndValueField],
  97. expected: [
  98. { text: 'TA', value: 'VA' },
  99. { text: 'TB', value: 'VB' },
  100. { text: 'TC', value: 'VC' },
  101. ],
  102. },
  103. {
  104. series: [frameWithAStringField],
  105. expected: [
  106. { text: 'A', value: 'A' },
  107. { text: 'B', value: 'B' },
  108. { text: 'C', value: 'C' },
  109. ],
  110. },
  111. {
  112. series: [frameWithExpandableField],
  113. expected: [
  114. { text: 'A', value: 'A', expandable: true },
  115. { text: 'B', value: 'B', expandable: false },
  116. { text: 'C', value: 'C', expandable: true },
  117. ],
  118. },
  119. ].map((scenario) => {
  120. it(`when called with series:${JSON.stringify(scenario.series, null, 0)}`, async () => {
  121. const { series, expected } = scenario;
  122. const panelData: any = { series };
  123. const observable = of(panelData).pipe(toMetricFindValues());
  124. await expect(observable).toEmitValuesWith((received) => {
  125. const value = received[0];
  126. expect(value).toEqual(expected);
  127. });
  128. });
  129. });
  130. describe('when called without metric find values and string fields', () => {
  131. it('then the observable throws', async () => {
  132. const frameWithTimeField = toDataFrame({
  133. fields: [{ name: 'time', type: FieldType.time, values: [1, 2, 3] }],
  134. });
  135. const panelData: any = { series: [frameWithTimeField] };
  136. const observable = of(panelData).pipe(toMetricFindValues());
  137. await expect(observable).toEmitValuesWith((received) => {
  138. const value = received[0];
  139. expect(value).toEqual(new Error("Couldn't find any field of type string in the results."));
  140. });
  141. });
  142. });
  143. });
  144. });
  145. describe('areMetricFindValues', () => {
  146. const frame = toDataFrame({
  147. fields: [{ name: 'text', type: FieldType.number, values: [1] }],
  148. });
  149. it.each`
  150. values | expected
  151. ${null} | ${false}
  152. ${undefined} | ${false}
  153. ${[frame]} | ${false}
  154. ${[{ text: () => {} }]} | ${false}
  155. ${[{ text: { foo: 1 } }]} | ${false}
  156. ${[{ text: Symbol('foo') }]} | ${false}
  157. ${[{ text: true }]} | ${false}
  158. ${[{ text: null }]} | ${true}
  159. ${[{ value: null }]} | ${true}
  160. ${[]} | ${true}
  161. ${[{ text: '' }]} | ${true}
  162. ${[{ Text: '' }]} | ${true}
  163. ${[{ value: '' }]} | ${true}
  164. ${[{ Value: '' }]} | ${true}
  165. ${[{ text: '', value: '' }]} | ${true}
  166. ${[{ Text: '', Value: '' }]} | ${true}
  167. ${[{ text: 1 }]} | ${true}
  168. ${[{ Text: 1 }]} | ${true}
  169. ${[{ value: 1 }]} | ${true}
  170. ${[{ Value: 1 }]} | ${true}
  171. ${[{ text: 1, value: 1 }]} | ${true}
  172. ${[{ Text: 1, Value: 1 }]} | ${true}
  173. `('when called with values:$values', ({ values, expected }) => {
  174. expect(areMetricFindValues(values)).toBe(expected);
  175. });
  176. });