explore.test.ts 5.0 KB

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