explore.test.ts 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189
  1. import {
  2. DEFAULT_RANGE,
  3. serializeStateToUrlParam,
  4. parseUrlState,
  5. updateHistory,
  6. clearHistory,
  7. hasNonEmptyQuery,
  8. } from './explore';
  9. import { ExploreState } from 'app/types/explore';
  10. import store from 'app/core/store';
  11. const DEFAULT_EXPLORE_STATE: ExploreState = {
  12. datasource: null,
  13. datasourceError: null,
  14. datasourceLoading: null,
  15. datasourceMissing: false,
  16. datasourceName: '',
  17. exploreDatasources: [],
  18. graphInterval: 1000,
  19. history: [],
  20. initialQueries: [],
  21. queryTransactions: [],
  22. range: DEFAULT_RANGE,
  23. showingGraph: true,
  24. showingLogs: true,
  25. showingTable: true,
  26. supportsGraph: null,
  27. supportsLogs: null,
  28. supportsTable: null,
  29. };
  30. describe('state functions', () => {
  31. describe('parseUrlState', () => {
  32. it('returns default state on empty string', () => {
  33. expect(parseUrlState('')).toMatchObject({
  34. datasource: null,
  35. queries: [],
  36. range: DEFAULT_RANGE,
  37. });
  38. });
  39. it('returns a valid Explore state from URL parameter', () => {
  40. const paramValue =
  41. '%7B"datasource":"Local","queries":%5B%7B"expr":"metric"%7D%5D,"range":%7B"from":"now-1h","to":"now"%7D%7D';
  42. expect(parseUrlState(paramValue)).toMatchObject({
  43. datasource: 'Local',
  44. queries: [{ expr: 'metric' }],
  45. range: {
  46. from: 'now-1h',
  47. to: 'now',
  48. },
  49. });
  50. });
  51. it('returns a valid Explore state from a compact URL parameter', () => {
  52. const paramValue = '%5B"now-1h","now","Local",%7B"expr":"metric"%7D%5D';
  53. expect(parseUrlState(paramValue)).toMatchObject({
  54. datasource: 'Local',
  55. queries: [{ expr: 'metric' }],
  56. range: {
  57. from: 'now-1h',
  58. to: 'now',
  59. },
  60. });
  61. });
  62. });
  63. describe('serializeStateToUrlParam', () => {
  64. it('returns url parameter value for a state object', () => {
  65. const state = {
  66. ...DEFAULT_EXPLORE_STATE,
  67. datasourceName: 'foo',
  68. range: {
  69. from: 'now-5h',
  70. to: 'now',
  71. },
  72. initialQueries: [
  73. {
  74. refId: '1',
  75. expr: 'metric{test="a/b"}',
  76. },
  77. {
  78. refId: '2',
  79. expr: 'super{foo="x/z"}',
  80. },
  81. ],
  82. };
  83. expect(serializeStateToUrlParam(state)).toBe(
  84. '{"datasource":"foo","queries":[{"expr":"metric{test=\\"a/b\\"}"},' +
  85. '{"expr":"super{foo=\\"x/z\\"}"}],"range":{"from":"now-5h","to":"now"}}'
  86. );
  87. });
  88. it('returns url parameter value for a state object', () => {
  89. const state = {
  90. ...DEFAULT_EXPLORE_STATE,
  91. datasourceName: 'foo',
  92. range: {
  93. from: 'now-5h',
  94. to: 'now',
  95. },
  96. initialQueries: [
  97. {
  98. refId: '1',
  99. expr: 'metric{test="a/b"}',
  100. },
  101. {
  102. refId: '2',
  103. expr: 'super{foo="x/z"}',
  104. },
  105. ],
  106. };
  107. expect(serializeStateToUrlParam(state, true)).toBe(
  108. '["now-5h","now","foo",{"expr":"metric{test=\\"a/b\\"}"},{"expr":"super{foo=\\"x/z\\"}"}]'
  109. );
  110. });
  111. });
  112. describe('interplay', () => {
  113. it('can parse the serialized state into the original state', () => {
  114. const state = {
  115. ...DEFAULT_EXPLORE_STATE,
  116. datasourceName: 'foo',
  117. range: {
  118. from: 'now - 5h',
  119. to: 'now',
  120. },
  121. initialQueries: [
  122. {
  123. refId: '1',
  124. expr: 'metric{test="a/b"}',
  125. },
  126. {
  127. refId: '2',
  128. expr: 'super{foo="x/z"}',
  129. },
  130. ],
  131. };
  132. const serialized = serializeStateToUrlParam(state);
  133. const parsed = parseUrlState(serialized);
  134. // Account for datasource vs datasourceName
  135. const { datasource, queries, ...rest } = parsed;
  136. const resultState = {
  137. ...rest,
  138. datasource: DEFAULT_EXPLORE_STATE.datasource,
  139. datasourceName: datasource,
  140. initialQueries: queries,
  141. };
  142. expect(state).toMatchObject(resultState);
  143. });
  144. });
  145. });
  146. describe('updateHistory()', () => {
  147. const datasourceId = 'myDatasource';
  148. const key = `grafana.explore.history.${datasourceId}`;
  149. beforeEach(() => {
  150. clearHistory(datasourceId);
  151. expect(store.exists(key)).toBeFalsy();
  152. });
  153. test('should save history item to localStorage', () => {
  154. const expected = [
  155. {
  156. query: { refId: '1', expr: 'metric' },
  157. },
  158. ];
  159. expect(updateHistory([], datasourceId, [{ refId: '1', expr: 'metric' }])).toMatchObject(expected);
  160. expect(store.exists(key)).toBeTruthy();
  161. expect(store.getObject(key)).toMatchObject(expected);
  162. });
  163. });
  164. describe('hasNonEmptyQuery', () => {
  165. test('should return true if one query is non-empty', () => {
  166. expect(hasNonEmptyQuery([{ refId: '1', key: '2', expr: 'foo' }])).toBeTruthy();
  167. });
  168. test('should return false if query is empty', () => {
  169. expect(hasNonEmptyQuery([{ refId: '1', key: '2' }])).toBeFalsy();
  170. });
  171. test('should return false if no queries exist', () => {
  172. expect(hasNonEmptyQuery([])).toBeFalsy();
  173. });
  174. });