databaseSystemSelector.spec.tsx 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234
  1. import {OrganizationFixture} from 'sentry-fixture/organization';
  2. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  3. import {useLocalStorageState} from 'sentry/utils/useLocalStorageState';
  4. import {useLocation} from 'sentry/utils/useLocation';
  5. import {useNavigate} from 'sentry/utils/useNavigate';
  6. import {useSpanMetrics} from 'sentry/views/insights/common/queries/useDiscover';
  7. import {DatabaseSystemSelector} from 'sentry/views/insights/database/components/databaseSystemSelector';
  8. import {SpanMetricsField} from 'sentry/views/insights/types';
  9. jest.mock('sentry/views/insights/common/queries/useDiscover', () => ({
  10. useSpanMetrics: jest.fn(),
  11. }));
  12. jest.mock('sentry/utils/useLocalStorageState', () => ({
  13. useLocalStorageState: jest.fn(),
  14. }));
  15. jest.mock('sentry/utils/useLocation', () => ({
  16. useLocation: jest.fn(),
  17. }));
  18. jest.mock('sentry/utils/useNavigate', () => ({
  19. useNavigate: jest.fn(),
  20. }));
  21. const mockUseLocalStorageState = jest.mocked(useLocalStorageState);
  22. const mockUseSpanMetrics = jest.mocked(useSpanMetrics);
  23. const mockUseLocation = jest.mocked(useLocation);
  24. const mockUseNavigate = jest.mocked(useNavigate);
  25. describe('DatabaseSystemSelector', function () {
  26. const organization = OrganizationFixture();
  27. afterAll(() => {
  28. jest.clearAllMocks();
  29. });
  30. beforeEach(() => {
  31. mockUseLocation.mockReturnValue({
  32. query: {project: ['1']},
  33. pathname: '',
  34. search: '',
  35. hash: '',
  36. state: undefined,
  37. action: 'POP',
  38. key: '',
  39. });
  40. });
  41. it('is disabled and does not select a system if there are none available', async function () {
  42. const mockSetState = jest.fn();
  43. mockUseLocalStorageState.mockReturnValue(['', mockSetState]);
  44. mockUseSpanMetrics.mockReturnValue({
  45. data: [],
  46. isLoading: false,
  47. isError: false,
  48. } as any);
  49. render(<DatabaseSystemSelector />, {organization});
  50. expect(mockSetState).not.toHaveBeenCalled();
  51. const dropdownButton = await screen.findByRole('button');
  52. expect(dropdownButton).toBeInTheDocument();
  53. expect(dropdownButton).toHaveTextContent('DB SystemNone');
  54. });
  55. it('is disabled when only one database system is present and shows that system as selected', async function () {
  56. const mockSetState = jest.fn();
  57. mockUseLocalStorageState.mockReturnValue(['', mockSetState]);
  58. mockUseSpanMetrics.mockReturnValue({
  59. data: [
  60. {
  61. 'span.system': 'postgresql',
  62. 'count()': 1000,
  63. },
  64. ],
  65. isLoading: false,
  66. isError: false,
  67. } as any);
  68. render(<DatabaseSystemSelector />, {organization});
  69. const dropdownSelector = await screen.findByRole('button');
  70. expect(dropdownSelector).toBeDisabled();
  71. expect(mockSetState).toHaveBeenCalledWith('postgresql');
  72. });
  73. it('renders all database system options correctly', async function () {
  74. mockUseSpanMetrics.mockReturnValue({
  75. data: [
  76. {
  77. 'span.system': 'postgresql',
  78. 'count()': 1000,
  79. },
  80. {
  81. 'span.system': 'mongodb',
  82. 'count()': 500,
  83. },
  84. {
  85. 'span.system': 'chungusdb',
  86. 'count()': 200,
  87. },
  88. ],
  89. isLoading: false,
  90. isError: false,
  91. } as any);
  92. render(<DatabaseSystemSelector />, {organization});
  93. const dropdownSelector = await screen.findByRole('button');
  94. expect(dropdownSelector).toBeEnabled();
  95. expect(mockUseSpanMetrics).toHaveBeenCalled();
  96. const dropdownButton = await screen.findByRole('button');
  97. expect(dropdownButton).toBeInTheDocument();
  98. await userEvent.click(dropdownButton);
  99. const dropdownOptionLabels = await screen.findAllByTestId('menu-list-item-label');
  100. expect(dropdownOptionLabels[0]).toHaveTextContent('PostgreSQL');
  101. expect(dropdownOptionLabels[1]).toHaveTextContent('MongoDB');
  102. // chungusdb does not exist, so we do not expect this option to have casing
  103. expect(dropdownOptionLabels[2]).toHaveTextContent('chungusdb');
  104. });
  105. it('chooses the currently selected system from localStorage', async function () {
  106. mockUseLocalStorageState.mockReturnValue(['mongodb', () => {}]);
  107. mockUseSpanMetrics.mockReturnValue({
  108. data: [
  109. {
  110. 'span.system': 'postgresql',
  111. 'count()': 1000,
  112. },
  113. {
  114. 'span.system': 'mongodb',
  115. 'count()': 500,
  116. },
  117. {
  118. 'span.system': 'chungusdb',
  119. 'count()': 200,
  120. },
  121. ],
  122. isLoading: false,
  123. isError: false,
  124. } as any);
  125. render(<DatabaseSystemSelector />, {organization});
  126. expect(await screen.findByText('MongoDB')).toBeInTheDocument();
  127. });
  128. it('does not set the value from localStorage if the value is invalid', async function () {
  129. const mockSetState = jest.fn();
  130. mockUseLocalStorageState.mockReturnValue(['chungusdb', mockSetState]);
  131. mockUseSpanMetrics.mockReturnValue({
  132. data: [
  133. {
  134. 'span.system': 'postgresql',
  135. 'count()': 1000,
  136. },
  137. ],
  138. isLoading: false,
  139. isError: false,
  140. } as any);
  141. render(<DatabaseSystemSelector />, {organization});
  142. const dropdownSelector = await screen.findByRole('button');
  143. expect(dropdownSelector).toBeInTheDocument();
  144. expect(mockSetState).not.toHaveBeenCalledWith('chungusdb');
  145. });
  146. it('prioritizes the system set in query parameters but does not replace localStorage value until an option is clicked', async function () {
  147. const {SPAN_SYSTEM} = SpanMetricsField;
  148. const mockNavigate = jest.fn();
  149. mockUseNavigate.mockReturnValue(mockNavigate);
  150. mockUseLocation.mockReturnValue({
  151. query: {project: ['1'], [SPAN_SYSTEM]: 'mongodb'},
  152. pathname: '',
  153. search: '',
  154. hash: '',
  155. state: undefined,
  156. action: 'POP',
  157. key: '',
  158. });
  159. mockUseSpanMetrics.mockReturnValue({
  160. data: [
  161. {
  162. 'span.system': 'postgresql',
  163. 'count()': 1000,
  164. },
  165. {
  166. 'span.system': 'mongodb',
  167. 'count()': 500,
  168. },
  169. ],
  170. isLoading: false,
  171. isError: false,
  172. } as any);
  173. const mockSetState = jest.fn();
  174. mockUseLocalStorageState.mockReturnValue(['postgresql', mockSetState]);
  175. render(<DatabaseSystemSelector />, {organization});
  176. const dropdownSelector = await screen.findByRole('button');
  177. expect(dropdownSelector).toHaveTextContent('DB SystemMongoDB');
  178. expect(mockSetState).not.toHaveBeenCalledWith('mongodb');
  179. // Now that it has been confirmed that following a URL does not reset localStorage state, confirm that
  180. // clicking a different option will update both the state and the URL
  181. await userEvent.click(dropdownSelector);
  182. const dropdownOptionLabels = await screen.findAllByTestId('menu-list-item-label');
  183. expect(dropdownOptionLabels[0]).toHaveTextContent('PostgreSQL');
  184. expect(dropdownOptionLabels[1]).toHaveTextContent('MongoDB');
  185. await userEvent.click(dropdownOptionLabels[0]);
  186. expect(dropdownSelector).toHaveTextContent('DB SystemPostgreSQL');
  187. expect(mockSetState).toHaveBeenCalledWith('postgresql');
  188. expect(mockNavigate).toHaveBeenCalledWith({
  189. action: 'POP',
  190. hash: '',
  191. key: '',
  192. pathname: '',
  193. query: {project: ['1'], 'span.system': 'postgresql'},
  194. search: '',
  195. state: undefined,
  196. });
  197. });
  198. });