PromQueryField.test.tsx 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219
  1. import React from 'react';
  2. import Enzyme, { shallow } from 'enzyme';
  3. import Adapter from 'enzyme-adapter-react-16';
  4. import Plain from 'slate-plain-serializer';
  5. import PromQueryField, { groupMetricsByPrefix, RECORDING_RULES_GROUP } from './PromQueryField';
  6. Enzyme.configure({ adapter: new Adapter() });
  7. describe('PromQueryField typeahead handling', () => {
  8. const defaultProps = {
  9. request: () => ({ data: { data: [] } }),
  10. };
  11. it('returns default suggestions on emtpty context', () => {
  12. const instance = shallow(<PromQueryField {...defaultProps} />).instance() as PromQueryField;
  13. const result = instance.getTypeahead({ text: '', prefix: '', wrapperClasses: [] });
  14. expect(result.context).toBeUndefined();
  15. expect(result.refresher).toBeUndefined();
  16. expect(result.suggestions.length).toEqual(2);
  17. });
  18. describe('range suggestions', () => {
  19. it('returns range suggestions in range context', () => {
  20. const instance = shallow(<PromQueryField {...defaultProps} />).instance() as PromQueryField;
  21. const result = instance.getTypeahead({ text: '1', prefix: '1', wrapperClasses: ['context-range'] });
  22. expect(result.context).toBe('context-range');
  23. expect(result.refresher).toBeUndefined();
  24. expect(result.suggestions).toEqual([
  25. {
  26. items: [{ label: '1m' }, { label: '5m' }, { label: '10m' }, { label: '30m' }, { label: '1h' }],
  27. label: 'Range vector',
  28. },
  29. ]);
  30. });
  31. });
  32. describe('metric suggestions', () => {
  33. it('returns metrics suggestions by default', () => {
  34. const instance = shallow(
  35. <PromQueryField {...defaultProps} metrics={['foo', 'bar']} />
  36. ).instance() as PromQueryField;
  37. const result = instance.getTypeahead({ text: 'a', prefix: 'a', wrapperClasses: [] });
  38. expect(result.context).toBeUndefined();
  39. expect(result.refresher).toBeUndefined();
  40. expect(result.suggestions.length).toEqual(2);
  41. });
  42. it('returns default suggestions after a binary operator', () => {
  43. const instance = shallow(
  44. <PromQueryField {...defaultProps} metrics={['foo', 'bar']} />
  45. ).instance() as PromQueryField;
  46. const result = instance.getTypeahead({ text: '*', prefix: '', wrapperClasses: [] });
  47. expect(result.context).toBeUndefined();
  48. expect(result.refresher).toBeUndefined();
  49. expect(result.suggestions.length).toEqual(2);
  50. });
  51. });
  52. describe('label suggestions', () => {
  53. it('returns default label suggestions on label context and no metric', () => {
  54. const instance = shallow(<PromQueryField {...defaultProps} />).instance() as PromQueryField;
  55. const value = Plain.deserialize('{}');
  56. const range = value.selection.merge({
  57. anchorOffset: 1,
  58. });
  59. const valueWithSelection = value.change().select(range).value;
  60. const result = instance.getTypeahead({
  61. text: '',
  62. prefix: '',
  63. wrapperClasses: ['context-labels'],
  64. value: valueWithSelection,
  65. });
  66. expect(result.context).toBe('context-labels');
  67. expect(result.suggestions).toEqual([{ items: [{ label: 'job' }, { label: 'instance' }], label: 'Labels' }]);
  68. });
  69. it('returns label suggestions on label context and metric', () => {
  70. const instance = shallow(
  71. <PromQueryField {...defaultProps} labelKeys={{ '{__name__="metric"}': ['bar'] }} />
  72. ).instance() as PromQueryField;
  73. const value = Plain.deserialize('metric{}');
  74. const range = value.selection.merge({
  75. anchorOffset: 7,
  76. });
  77. const valueWithSelection = value.change().select(range).value;
  78. const result = instance.getTypeahead({
  79. text: '',
  80. prefix: '',
  81. wrapperClasses: ['context-labels'],
  82. value: valueWithSelection,
  83. });
  84. expect(result.context).toBe('context-labels');
  85. expect(result.suggestions).toEqual([{ items: [{ label: 'bar' }], label: 'Labels' }]);
  86. });
  87. it('returns a refresher on label context and unavailable metric', () => {
  88. const instance = shallow(
  89. <PromQueryField {...defaultProps} labelKeys={{ '{__name__="foo"}': ['bar'] }} />
  90. ).instance() as PromQueryField;
  91. const value = Plain.deserialize('metric{}');
  92. const range = value.selection.merge({
  93. anchorOffset: 7,
  94. });
  95. const valueWithSelection = value.change().select(range).value;
  96. const result = instance.getTypeahead({
  97. text: '',
  98. prefix: '',
  99. wrapperClasses: ['context-labels'],
  100. value: valueWithSelection,
  101. });
  102. expect(result.context).toBeUndefined();
  103. expect(result.refresher).toBeInstanceOf(Promise);
  104. expect(result.suggestions).toEqual([]);
  105. });
  106. it('returns label values on label context when given a metric and a label key', () => {
  107. const instance = shallow(
  108. <PromQueryField
  109. {...defaultProps}
  110. labelKeys={{ '{__name__="metric"}': ['bar'] }}
  111. labelValues={{ '{__name__="metric"}': { bar: ['baz'] } }}
  112. />
  113. ).instance() as PromQueryField;
  114. const value = Plain.deserialize('metric{bar=ba}');
  115. const range = value.selection.merge({
  116. anchorOffset: 13,
  117. });
  118. const valueWithSelection = value.change().select(range).value;
  119. const result = instance.getTypeahead({
  120. text: '=ba',
  121. prefix: 'ba',
  122. wrapperClasses: ['context-labels'],
  123. labelKey: 'bar',
  124. value: valueWithSelection,
  125. });
  126. expect(result.context).toBe('context-label-values');
  127. expect(result.suggestions).toEqual([{ items: [{ label: 'baz' }], label: 'Label values for "bar"' }]);
  128. });
  129. it('returns label suggestions on aggregation context and metric w/ selector', () => {
  130. const instance = shallow(
  131. <PromQueryField {...defaultProps} labelKeys={{ '{__name__="metric",foo="xx"}': ['bar'] }} />
  132. ).instance() as PromQueryField;
  133. const value = Plain.deserialize('sum(metric{foo="xx"}) by ()');
  134. const range = value.selection.merge({
  135. anchorOffset: 26,
  136. });
  137. const valueWithSelection = value.change().select(range).value;
  138. const result = instance.getTypeahead({
  139. text: '',
  140. prefix: '',
  141. wrapperClasses: ['context-aggregation'],
  142. value: valueWithSelection,
  143. });
  144. expect(result.context).toBe('context-aggregation');
  145. expect(result.suggestions).toEqual([{ items: [{ label: 'bar' }], label: 'Labels' }]);
  146. });
  147. it('returns label suggestions on aggregation context and metric w/o selector', () => {
  148. const instance = shallow(
  149. <PromQueryField {...defaultProps} labelKeys={{ '{__name__="metric"}': ['bar'] }} />
  150. ).instance() as PromQueryField;
  151. const value = Plain.deserialize('sum(metric) by ()');
  152. const range = value.selection.merge({
  153. anchorOffset: 16,
  154. });
  155. const valueWithSelection = value.change().select(range).value;
  156. const result = instance.getTypeahead({
  157. text: '',
  158. prefix: '',
  159. wrapperClasses: ['context-aggregation'],
  160. value: valueWithSelection,
  161. });
  162. expect(result.context).toBe('context-aggregation');
  163. expect(result.suggestions).toEqual([{ items: [{ label: 'bar' }], label: 'Labels' }]);
  164. });
  165. });
  166. });
  167. describe('groupMetricsByPrefix()', () => {
  168. it('returns an empty group for no metrics', () => {
  169. expect(groupMetricsByPrefix([])).toEqual([]);
  170. });
  171. it('returns options grouped by prefix', () => {
  172. expect(groupMetricsByPrefix(['foo_metric'])).toMatchObject([
  173. {
  174. value: 'foo',
  175. children: [
  176. {
  177. value: 'foo_metric',
  178. },
  179. ],
  180. },
  181. ]);
  182. });
  183. it('returns options without prefix as toplevel option', () => {
  184. expect(groupMetricsByPrefix(['metric'])).toMatchObject([
  185. {
  186. value: 'metric',
  187. },
  188. ]);
  189. });
  190. it('returns recording rules grouped separately', () => {
  191. expect(groupMetricsByPrefix([':foo_metric:'])).toMatchObject([
  192. {
  193. value: RECORDING_RULES_GROUP,
  194. children: [
  195. {
  196. value: ':foo_metric:',
  197. },
  198. ],
  199. },
  200. ]);
  201. });
  202. });