utils.spec.tsx 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. import {initializeOrg} from 'sentry-test/initializeOrg';
  2. import {
  3. Dataset,
  4. Datasource,
  5. SessionsAggregate,
  6. } from 'sentry/views/alerts/rules/metric/types';
  7. import {Incident, IncidentStats} from 'sentry/views/alerts/types';
  8. import {
  9. alertAxisFormatter,
  10. alertTooltipValueFormatter,
  11. getQueryDatasource,
  12. getTeamParams,
  13. isSessionAggregate,
  14. } from 'sentry/views/alerts/utils';
  15. import {getIncidentDiscoverUrl} from 'sentry/views/alerts/utils/getIncidentDiscoverUrl';
  16. describe('Alert utils', function () {
  17. const {org, projects} = initializeOrg();
  18. const mockStats: IncidentStats = {
  19. eventStats: {
  20. data: [
  21. [0, [{count: 10}]],
  22. [120, [{count: 10}]],
  23. ],
  24. },
  25. totalEvents: 0,
  26. uniqueUsers: 0,
  27. };
  28. describe('getIncidentDiscoverUrl', function () {
  29. it('creates a discover query url for errors', function () {
  30. // TODO(ts): Add a TestStub for Incident
  31. const incident: Incident = {
  32. title: 'Test error alert',
  33. discoverQuery: 'id:test',
  34. projects,
  35. alertRule: TestStubs.MetricRule({
  36. timeWindow: 1,
  37. dataset: Dataset.ERRORS,
  38. aggregate: 'count()',
  39. }),
  40. } as Incident;
  41. const to = getIncidentDiscoverUrl({
  42. orgSlug: org.slug,
  43. projects,
  44. incident,
  45. stats: mockStats,
  46. });
  47. expect(to).toEqual({
  48. query: expect.objectContaining({
  49. name: 'Test error alert',
  50. field: ['issue', 'count()', 'count_unique(user)'],
  51. sort: ['-count'],
  52. query: 'id:test',
  53. yAxis: 'count()',
  54. start: '1970-01-01T00:00:00.000',
  55. end: '1970-01-01T00:02:00.000',
  56. interval: '1m',
  57. }),
  58. pathname: '/organizations/org-slug/discover/results/',
  59. });
  60. });
  61. it('creates a discover query url for transactions', function () {
  62. // TODO(ts): Add a TestStub for Incident
  63. const incident = {
  64. title: 'Test transaction alert',
  65. discoverQuery: 'id:test',
  66. projects,
  67. alertRule: TestStubs.MetricRule({
  68. timeWindow: 1,
  69. dataset: Dataset.TRANSACTIONS,
  70. aggregate: 'p90()',
  71. }),
  72. } as Incident;
  73. const to = getIncidentDiscoverUrl({
  74. orgSlug: org.slug,
  75. projects,
  76. incident,
  77. stats: mockStats,
  78. });
  79. expect(to).toEqual({
  80. query: expect.objectContaining({
  81. name: 'Test transaction alert',
  82. field: ['transaction', 'p90()'],
  83. sort: ['-p90'],
  84. query: 'id:test',
  85. yAxis: 'p90()',
  86. }),
  87. pathname: '/organizations/org-slug/discover/results/',
  88. });
  89. });
  90. });
  91. describe('getQuerySource', () => {
  92. it('should parse event type error or default', () => {
  93. expect(getQueryDatasource('event.type:default OR event.type:error')).toEqual({
  94. source: Datasource.ERROR_DEFAULT,
  95. query: '',
  96. });
  97. expect(
  98. getQueryDatasource(
  99. 'event.type:error OR event.type:default transaction.duration:<30s'
  100. )
  101. ).toEqual({
  102. source: Datasource.ERROR_DEFAULT,
  103. query: 'transaction.duration:<30s',
  104. });
  105. expect(
  106. getQueryDatasource('event.type:error OR (event.type:default event.level:fatal)')
  107. ).toEqual({
  108. source: Datasource.ERROR_DEFAULT,
  109. query: 'event.level:fatal)',
  110. });
  111. expect(
  112. getQueryDatasource('(event.type:error OR event.type:default) event.level:fatal')
  113. ).toEqual({
  114. source: Datasource.ERROR_DEFAULT,
  115. query: 'event.level:fatal',
  116. });
  117. });
  118. it('should not allow event type transaction with anything else', () => {
  119. expect(getQueryDatasource('event.type:error OR event.type:transaction')).toBeNull();
  120. expect(
  121. getQueryDatasource('event.type:transaction OR event.type:default')
  122. ).toBeNull();
  123. });
  124. it('should not allow boolean event types', () => {
  125. expect(getQueryDatasource('!event.type:error')).toBeNull();
  126. expect(getQueryDatasource('!event.type:transaction something')).toBeNull();
  127. expect(getQueryDatasource('!event.type:default')).toBeNull();
  128. });
  129. it('should allow error, transaction, default alone', () => {
  130. expect(getQueryDatasource('event.type:error test')).toEqual({
  131. source: Datasource.ERROR,
  132. query: 'test',
  133. });
  134. expect(getQueryDatasource('event.type:default test')).toEqual({
  135. source: Datasource.DEFAULT,
  136. query: 'test',
  137. });
  138. expect(getQueryDatasource('event.type:transaction test')).toEqual({
  139. source: Datasource.TRANSACTION,
  140. query: 'test',
  141. });
  142. expect(
  143. getQueryDatasource(
  144. 'event.type:error explode OR (event.type:default event.level:fatal)'
  145. )
  146. ).toEqual({
  147. source: Datasource.ERROR,
  148. query: 'explode OR (event.type:default event.level:fatal)',
  149. });
  150. });
  151. });
  152. describe('isSessionAggregate', () => {
  153. it('accepts session aggregate', () => {
  154. Object.values(SessionsAggregate).forEach(aggregate => {
  155. expect(isSessionAggregate(aggregate)).toBeTruthy();
  156. });
  157. });
  158. it('rejects other aggregates', () => {
  159. expect(isSessionAggregate('p95(transaction.duration)')).toBeFalsy();
  160. });
  161. });
  162. describe('alertAxisFormatter', () => {
  163. it('formatts', () => {
  164. expect(
  165. alertAxisFormatter(
  166. 98.312,
  167. 'Crash Free Rate',
  168. SessionsAggregate.CRASH_FREE_SESSIONS
  169. )
  170. ).toBe('98.31%');
  171. expect(alertAxisFormatter(0.1234, 'failure_rate()', 'failure_rate()')).toBe('12%');
  172. });
  173. });
  174. describe('alertTooltipValueFormatter', () => {
  175. it('formatts', () => {
  176. expect(
  177. alertTooltipValueFormatter(
  178. 98.312,
  179. 'Crash Free Rate',
  180. SessionsAggregate.CRASH_FREE_SESSIONS
  181. )
  182. ).toBe('98.312%');
  183. expect(alertTooltipValueFormatter(0.1234, 'failure_rate()', 'failure_rate()')).toBe(
  184. '12.34%'
  185. );
  186. });
  187. });
  188. describe('getTeamParams', () => {
  189. it('should use default teams', () => {
  190. expect(getTeamParams()).toEqual(['myteams', 'unassigned']);
  191. });
  192. it('should allow no teams with an empty string param', () => {
  193. expect(getTeamParams('')).toEqual([]);
  194. });
  195. it('should allow one or more teams', () => {
  196. expect(getTeamParams('team-sentry')).toEqual(['team-sentry']);
  197. expect(getTeamParams(['team-sentry', 'team-two'])).toEqual([
  198. 'team-sentry',
  199. 'team-two',
  200. ]);
  201. });
  202. });
  203. });