widgetQueryFields.spec.tsx 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285
  1. import {mountWithTheme} from 'sentry-test/enzyme';
  2. import {initializeOrg} from 'sentry-test/initializeOrg';
  3. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  4. import WidgetQueryFields from 'sentry/components/dashboards/widgetQueryFields';
  5. import {QueryFieldValue} from 'sentry/utils/discover/fields';
  6. import {DisplayType, WidgetType} from 'sentry/views/dashboardsV2/types';
  7. import {FieldValueKind} from 'sentry/views/eventsV2/table/types';
  8. describe('WidgetQueryFields', function () {
  9. describe('Discover Fields', function () {
  10. const {routerContext} = initializeOrg();
  11. const organization = TestStubs.Organization();
  12. let wrapper;
  13. beforeEach(() => {
  14. // TODO change this to react testing library
  15. wrapper = mountWithTheme(
  16. <WidgetQueryFields
  17. widgetType={WidgetType.DISCOVER}
  18. displayType={DisplayType.TOP_N}
  19. fieldOptions={{
  20. 'function:count': {
  21. label: 'count()',
  22. value: {
  23. kind: FieldValueKind.FUNCTION,
  24. meta: {
  25. name: 'count',
  26. parameters: [],
  27. },
  28. },
  29. },
  30. 'field:title': {
  31. label: 'title',
  32. value: {
  33. kind: FieldValueKind.FIELD,
  34. meta: {
  35. name: 'title',
  36. dataType: 'string',
  37. },
  38. },
  39. },
  40. 'function:p95': {
  41. label: 'p95(…)',
  42. value: {
  43. kind: FieldValueKind.FUNCTION,
  44. meta: {
  45. name: 'p95',
  46. parameters: [],
  47. },
  48. },
  49. },
  50. }}
  51. fields={[
  52. {
  53. kind: 'field',
  54. field: 'title',
  55. },
  56. {
  57. kind: 'function',
  58. function: ['count', '', undefined, undefined],
  59. },
  60. {
  61. kind: 'function',
  62. function: ['p95', 'transaction.duration', undefined, undefined],
  63. },
  64. ]}
  65. organization={organization}
  66. onChange={() => undefined}
  67. />,
  68. routerContext
  69. );
  70. });
  71. it('renders with grey dotted previous period when using only a single series', function () {
  72. const columns = wrapper.find('StyledColumnEditCollection').find('QueryField');
  73. expect(columns.length).toEqual(2);
  74. expect(columns.at(0).props().fieldValue).toEqual({
  75. kind: 'field',
  76. field: 'title',
  77. });
  78. expect(columns.at(1).props().fieldValue).toEqual({
  79. kind: 'function',
  80. function: ['count', '', undefined, undefined],
  81. });
  82. expect(
  83. wrapper.find('QueryFieldWrapper').find('QueryField').props().fieldValue
  84. ).toEqual({
  85. function: ['p95', 'transaction.duration', undefined, undefined],
  86. kind: 'function',
  87. });
  88. });
  89. });
  90. describe('Issue Fields', function () {
  91. const organization = TestStubs.Organization();
  92. let fields: QueryFieldValue[];
  93. const mountComponent = () =>
  94. render(
  95. <WidgetQueryFields
  96. widgetType={WidgetType.ISSUE}
  97. displayType={DisplayType.TABLE}
  98. fieldOptions={{
  99. 'field:issue': {
  100. label: 'issue',
  101. value: {
  102. kind: FieldValueKind.FIELD,
  103. meta: {
  104. name: 'issue',
  105. dataType: 'string',
  106. },
  107. },
  108. },
  109. 'field:assignee': {
  110. label: 'assignee',
  111. value: {
  112. kind: FieldValueKind.FIELD,
  113. meta: {
  114. name: 'assignee',
  115. dataType: 'string',
  116. },
  117. },
  118. },
  119. }}
  120. fields={fields}
  121. organization={organization}
  122. onChange={newFields => {
  123. fields.splice(0, fields.length, ...newFields);
  124. }}
  125. />
  126. );
  127. beforeEach(() => {
  128. fields = [
  129. {
  130. kind: 'field',
  131. field: 'issue',
  132. },
  133. {
  134. kind: 'field',
  135. field: 'assignee',
  136. },
  137. ];
  138. });
  139. it('renders issue and assignee columns', function () {
  140. mountComponent();
  141. expect(screen.getByText('issue')).toBeInTheDocument();
  142. expect(screen.getByText('assignee')).toBeInTheDocument();
  143. });
  144. it('renders only issue column', function () {
  145. mountComponent();
  146. expect(screen.getByText('issue')).toBeInTheDocument();
  147. userEvent.click(screen.getByTestId('remove-column-1'));
  148. expect(screen.queryByText('assignee')).not.toBeInTheDocument();
  149. });
  150. it('renders issue column and then assignee column after adding', function () {
  151. mountComponent();
  152. userEvent.click(screen.getByTestId('remove-column-1'));
  153. expect(screen.queryByText('assignee')).not.toBeInTheDocument();
  154. expect(screen.getByText('Add a Column')).toBeInTheDocument();
  155. userEvent.click(screen.getByText('Add a Column'));
  156. mountComponent();
  157. expect(screen.getByText('(Required)')).toBeInTheDocument();
  158. userEvent.keyboard('a');
  159. userEvent.click(screen.getByText('assignee'));
  160. mountComponent();
  161. expect(screen.getByText('assignee')).toBeInTheDocument();
  162. });
  163. });
  164. describe('Metrics Fields', function () {
  165. const organization = TestStubs.Organization();
  166. it('top N shows the right options for y-axis and columns', function () {
  167. render(
  168. <WidgetQueryFields
  169. widgetType={WidgetType.RELEASE}
  170. displayType={DisplayType.TOP_N}
  171. fieldOptions={{
  172. 'field:sentry.sessions.session': {
  173. label: 'sentry.sessions.session',
  174. value: {
  175. kind: FieldValueKind.METRICS,
  176. meta: {name: 'sentry.sessions.session', dataType: 'integer'},
  177. },
  178. },
  179. 'field:sentry.sessions.session.error': {
  180. label: 'sentry.sessions.session.error',
  181. value: {
  182. kind: FieldValueKind.METRICS,
  183. meta: {name: 'sentry.sessions.session.error', dataType: 'integer'},
  184. },
  185. },
  186. 'field:sentry.sessions.user': {
  187. label: 'sentry.sessions.user',
  188. value: {
  189. kind: FieldValueKind.METRICS,
  190. meta: {name: 'sentry.sessions.user', dataType: 'string'},
  191. },
  192. },
  193. 'function:count_unique': {
  194. label: 'count_unique(…)',
  195. value: {
  196. kind: FieldValueKind.FUNCTION,
  197. meta: {
  198. name: 'count_unique',
  199. parameters: [
  200. {
  201. kind: 'column',
  202. columnTypes: ['string'],
  203. required: true,
  204. defaultValue: 'sentry.sessions.user',
  205. },
  206. ],
  207. },
  208. },
  209. },
  210. 'function:sum': {
  211. label: 'sum(…)',
  212. value: {
  213. kind: FieldValueKind.FUNCTION,
  214. meta: {
  215. name: 'sum',
  216. parameters: [
  217. {
  218. kind: 'column',
  219. columnTypes: ['integer'],
  220. required: true,
  221. defaultValue: 'sentry.sessions.session',
  222. },
  223. ],
  224. },
  225. },
  226. },
  227. 'tag:environment': {
  228. label: 'environment',
  229. value: {
  230. kind: FieldValueKind.TAG,
  231. meta: {name: 'environment', dataType: 'string'},
  232. },
  233. },
  234. 'tag:release': {
  235. label: 'release',
  236. value: {
  237. kind: FieldValueKind.TAG,
  238. meta: {name: 'release', dataType: 'string'},
  239. },
  240. },
  241. 'tag:session.status': {
  242. label: 'session.status',
  243. value: {
  244. kind: FieldValueKind.TAG,
  245. meta: {name: 'session.status', dataType: 'string'},
  246. },
  247. },
  248. }}
  249. fields={[
  250. {kind: 'field', field: 'release'},
  251. {
  252. kind: 'function',
  253. function: ['sum', 'sentry.sessions.session', undefined, undefined],
  254. },
  255. ]}
  256. organization={organization}
  257. onChange={() => undefined}
  258. />
  259. );
  260. // ensure that columns section shows only tags
  261. userEvent.click(screen.getByText('release'));
  262. expect(screen.getByText('environment')).toBeInTheDocument();
  263. expect(screen.getByText('session.status')).toBeInTheDocument();
  264. expect(screen.queryByText('count_unique(…)')).not.toBeInTheDocument();
  265. // ensure that y-axis section shows only functions/fields
  266. userEvent.click(screen.getByText('sum(…)'));
  267. expect(screen.getByText('count_unique(…)')).toBeInTheDocument();
  268. expect(screen.queryByText('environment')).not.toBeInTheDocument();
  269. });
  270. });
  271. });