dashboardWidgetLibraryModal.spec.jsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175
  1. import {initializeOrg} from 'sentry-test/initializeOrg';
  2. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  3. import {openAddDashboardWidgetModal} from 'sentry/actionCreators/modal';
  4. import DashboardWidgetLibraryModal from 'sentry/components/modals/dashboardWidgetLibraryModal';
  5. import * as types from 'sentry/views/dashboardsV2/types';
  6. const stubEl = props => <div>{props.children}</div>;
  7. const alertText =
  8. 'Please select at least one Widget from our Library. Alternatively, you can build a custom widget from scratch.';
  9. jest.mock('sentry/actionCreators/modal', () => ({
  10. openAddDashboardWidgetModal: jest.fn(),
  11. }));
  12. function mountModal({initialData}, onApply, closeModal, widgets = []) {
  13. return render(
  14. <DashboardWidgetLibraryModal
  15. Header={stubEl}
  16. Footer={stubEl}
  17. Body={stubEl}
  18. organization={initialData.organization}
  19. dashboard={TestStubs.Dashboard(widgets, {
  20. id: '1',
  21. title: 'Dashboard 1',
  22. dateCreated: '2021-04-19T13:13:23.962105Z',
  23. createdBy: {id: '1'},
  24. widgetDisplay: [],
  25. })}
  26. onAddWidget={onApply}
  27. closeModal={closeModal}
  28. />
  29. );
  30. }
  31. describe('Modals -> DashboardWidgetLibraryModal', function () {
  32. const initialData = initializeOrg({
  33. organization: {
  34. apdexThreshold: 400,
  35. },
  36. });
  37. let container;
  38. afterEach(() => {
  39. MockApiClient.clearMockResponses();
  40. if (container) {
  41. container.unmount();
  42. }
  43. });
  44. it('opens modal and renders correctly', function () {
  45. // Checking initial modal states
  46. container = mountModal({initialData});
  47. expect(screen.getByText('Duration Distribution')).toBeInTheDocument();
  48. expect(screen.getByText('High Throughput Transactions')).toBeInTheDocument();
  49. expect(screen.getByText('LCP by Country')).toBeInTheDocument();
  50. expect(screen.getByText('Miserable Users')).toBeInTheDocument();
  51. expect(screen.getByText('Slow vs. Fast Transactions')).toBeInTheDocument();
  52. expect(screen.getByText('Issues For Review')).toBeInTheDocument();
  53. expect(screen.getByText('Top Unhandled Error Types')).toBeInTheDocument();
  54. expect(screen.getByText('Users Affected by Errors')).toBeInTheDocument();
  55. expect(screen.getByRole('button', {name: 'Widget Library new'})).toBeInTheDocument();
  56. expect(screen.getByRole('button', {name: 'Custom Widget'})).toBeInTheDocument();
  57. const button = screen.getByRole('button', {name: 'Custom Widget'});
  58. userEvent.click(button);
  59. expect(openAddDashboardWidgetModal).toHaveBeenCalledTimes(1);
  60. });
  61. it('submits selected widgets', function () {
  62. // Checking initial modal states
  63. const mockApply = jest.fn();
  64. const closeModal = jest.fn();
  65. container = mountModal({initialData}, mockApply, closeModal, [
  66. TestStubs.Widget(
  67. [
  68. {
  69. name: '',
  70. orderby: '',
  71. conditions: 'event.type:error',
  72. fields: ['count()'],
  73. aggregates: ['count()'],
  74. columns: [],
  75. },
  76. ],
  77. {
  78. title: 'Errors',
  79. interval: '1d',
  80. id: '1',
  81. displayType: 'line',
  82. }
  83. ),
  84. ]);
  85. // Select some widgets
  86. const allEvents = screen.queryByText('High Throughput Transactions');
  87. userEvent.click(allEvents);
  88. expect(screen.getByTestId('confirm-widgets')).toBeEnabled();
  89. userEvent.click(screen.getByTestId('confirm-widgets'));
  90. expect(mockApply).toHaveBeenCalledTimes(1);
  91. expect(mockApply).toHaveBeenCalledWith([
  92. expect.objectContaining({
  93. displayType: 'line',
  94. id: '1',
  95. interval: '1d',
  96. queries: [
  97. {
  98. conditions: 'event.type:error',
  99. fields: ['count()'],
  100. aggregates: ['count()'],
  101. columns: [],
  102. name: '',
  103. orderby: '',
  104. },
  105. ],
  106. title: 'Errors',
  107. }),
  108. expect.objectContaining({
  109. displayType: 'top_n',
  110. id: 'high-throughput-transactions',
  111. interval: '5m',
  112. description: 'Top 5 transactions with the largest volume.',
  113. queries: [
  114. {
  115. conditions: 'event.type:transaction',
  116. fields: ['transaction', 'count()'],
  117. aggregates: ['count()'],
  118. columns: ['transaction'],
  119. name: '',
  120. orderby: '-count()',
  121. },
  122. ],
  123. title: 'High Throughput Transactions',
  124. widgetType: 'discover',
  125. }),
  126. ]);
  127. expect(closeModal).toHaveBeenCalledTimes(1);
  128. });
  129. it('raises warning if widget not selected', function () {
  130. // Checking initial modal states
  131. const mockApply = jest.fn();
  132. const closeModal = jest.fn();
  133. container = mountModal({initialData}, mockApply, closeModal);
  134. expect(screen.queryByText(alertText)).not.toBeInTheDocument();
  135. userEvent.click(screen.getByTestId('confirm-widgets'));
  136. expect(mockApply).toHaveBeenCalledTimes(0);
  137. expect(closeModal).toHaveBeenCalledTimes(0);
  138. expect(screen.getByText(alertText)).toBeInTheDocument();
  139. });
  140. it('disables save button if widget limit is exceeded', function () {
  141. // Checking initial modal states
  142. const mockApply = jest.fn();
  143. const closeModal = jest.fn();
  144. types.MAX_WIDGETS = 1;
  145. container = mountModal({initialData}, mockApply, closeModal);
  146. // Select some widgets
  147. const allEvents = screen.queryByText('High Throughput Transactions');
  148. userEvent.click(allEvents);
  149. const totalErrors = screen.queryByText('Users Affected by Errors');
  150. userEvent.click(totalErrors);
  151. expect(screen.getByTestId('confirm-widgets')).toBeDisabled();
  152. });
  153. });