index.spec.tsx 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. import {RouterFixture} from 'sentry-fixture/routerFixture';
  2. import {SentryAppFixture} from 'sentry-fixture/sentryApp';
  3. import {SentryAppWebhookRequestFixture} from 'sentry-fixture/sentryAppWebhookRequest';
  4. import {render, screen, within} from 'sentry-test/reactTestingLibrary';
  5. import SentryApplicationDashboard from './index';
  6. jest.mock('sentry/components/charts/baseChart', () => {
  7. return jest.fn().mockImplementation(() => <div data-test-id="chart" />);
  8. });
  9. describe('Sentry Application Dashboard', function () {
  10. const NUM_INSTALLS = 5;
  11. const NUM_UNINSTALLS = 2;
  12. let sentryApp: ReturnType<typeof SentryAppFixture>;
  13. let webhookRequest: ReturnType<typeof SentryAppWebhookRequestFixture>;
  14. afterEach(() => {
  15. MockApiClient.clearMockResponses();
  16. });
  17. describe('Viewing the Sentry App Dashboard for a published integration', () => {
  18. beforeEach(() => {
  19. sentryApp = SentryAppFixture({
  20. status: 'published',
  21. schema: {
  22. elements: [
  23. {type: 'stacktrace-link', uri: '/test', url: '/test'},
  24. {
  25. type: 'issue-link',
  26. create: {uri: '/test', required_fields: []},
  27. link: {uri: '/test', required_fields: []},
  28. },
  29. ],
  30. },
  31. });
  32. webhookRequest = SentryAppWebhookRequestFixture();
  33. MockApiClient.addMockResponse({
  34. url: `/sentry-apps/${sentryApp.slug}/stats/`,
  35. body: {
  36. totalInstalls: NUM_INSTALLS,
  37. totalUninstalls: NUM_UNINSTALLS,
  38. installStats: [[1569783600, NUM_INSTALLS]],
  39. uninstallStats: [[1569783600, NUM_UNINSTALLS]],
  40. },
  41. });
  42. MockApiClient.addMockResponse({
  43. url: `/sentry-apps/${sentryApp.slug}/requests/`,
  44. body: [webhookRequest],
  45. });
  46. MockApiClient.addMockResponse({
  47. url: `/sentry-apps/${sentryApp.slug}/interaction/`,
  48. body: {
  49. componentInteractions: {
  50. 'stacktrace-link': [[1569783600, 1]],
  51. 'issue-link': [[1569783600, 1]],
  52. },
  53. views: [[1569783600, 1]],
  54. },
  55. });
  56. MockApiClient.addMockResponse({
  57. url: `/sentry-apps/${sentryApp.slug}/`,
  58. body: sentryApp,
  59. });
  60. });
  61. it('shows the total install/uninstall stats', async () => {
  62. const router = RouterFixture({params: {appSlug: sentryApp.slug}});
  63. render(<SentryApplicationDashboard />, {router});
  64. expect(await screen.findByTestId('installs')).toHaveTextContent('Total installs5');
  65. expect(screen.getByTestId('uninstalls')).toHaveTextContent('Total uninstalls2');
  66. });
  67. it('shows the request log', async () => {
  68. const router = RouterFixture({params: {appSlug: sentryApp.slug}});
  69. render(<SentryApplicationDashboard />, {router});
  70. // The mock response has 1 request
  71. expect(await screen.findByTestId('request-item')).toBeInTheDocument();
  72. const requestLog = within(screen.getByTestId('request-item'));
  73. // Make sure that all the info is displayed
  74. expect(requestLog.getByText('https://example.com/webhook')).toBeInTheDocument();
  75. expect(requestLog.getByText('400')).toBeInTheDocument();
  76. expect(requestLog.getByText('issue.assigned')).toBeInTheDocument();
  77. expect(requestLog.getByText('Test Org')).toBeInTheDocument();
  78. });
  79. it('shows an empty message if there are no requests', async () => {
  80. MockApiClient.addMockResponse({
  81. url: `/sentry-apps/${sentryApp.slug}/requests/`,
  82. body: [],
  83. });
  84. const router = RouterFixture({params: {appSlug: sentryApp.slug}});
  85. render(<SentryApplicationDashboard />, {router});
  86. expect(
  87. await screen.findByText('No requests found in the last 30 days.')
  88. ).toBeInTheDocument();
  89. });
  90. it('shows integration and interactions chart', async () => {
  91. const router = RouterFixture({params: {appSlug: sentryApp.slug}});
  92. render(<SentryApplicationDashboard />, {router});
  93. expect(await screen.findAllByTestId('chart')).toHaveLength(3);
  94. });
  95. });
  96. describe('Viewing the Sentry App Dashboard for an internal integration', () => {
  97. beforeEach(() => {
  98. sentryApp = SentryAppFixture({
  99. status: 'internal',
  100. schema: {
  101. elements: [{type: 'stacktrace-link', uri: '/test', url: '/test'}],
  102. },
  103. });
  104. webhookRequest = SentryAppWebhookRequestFixture();
  105. MockApiClient.addMockResponse({
  106. url: `/sentry-apps/${sentryApp.slug}/stats/`,
  107. body: {
  108. totalInstalls: 1,
  109. totalUninstalls: 0,
  110. installStats: [[1569783600, 1]],
  111. uninstallStats: [[1569783600, 0]],
  112. },
  113. });
  114. MockApiClient.addMockResponse({
  115. url: `/sentry-apps/${sentryApp.slug}/requests/`,
  116. body: [webhookRequest],
  117. });
  118. MockApiClient.addMockResponse({
  119. url: `/sentry-apps/${sentryApp.slug}/interaction/`,
  120. body: {
  121. componentInteractions: {
  122. 'stacktrace-link': [[1569783600, 1]],
  123. },
  124. views: [[1569783600, 1]],
  125. },
  126. });
  127. MockApiClient.addMockResponse({
  128. url: `/sentry-apps/${sentryApp.slug}/`,
  129. body: sentryApp,
  130. });
  131. });
  132. it('shows the request log', async () => {
  133. const router = RouterFixture({params: {appSlug: sentryApp.slug}});
  134. render(<SentryApplicationDashboard />, {router});
  135. expect(await screen.findByTestId('loading-indicator')).not.toBeInTheDocument();
  136. // The mock response has 1 request
  137. expect(await screen.findByTestId('request-item')).toBeInTheDocument();
  138. const requestLog = within(screen.getByTestId('request-item'));
  139. // Make sure that all the info is displayed
  140. expect(requestLog.getByText('https://example.com/webhook')).toBeInTheDocument();
  141. expect(requestLog.getByText('400')).toBeInTheDocument();
  142. expect(requestLog.getByText('issue.assigned')).toBeInTheDocument();
  143. // Does not show the integration views
  144. expect(screen.queryByText('Integration Views')).not.toBeInTheDocument();
  145. });
  146. it('shows an empty message if there are no requests', async () => {
  147. MockApiClient.addMockResponse({
  148. url: `/sentry-apps/${sentryApp.slug}/requests/`,
  149. body: [],
  150. });
  151. const router = RouterFixture({params: {appSlug: sentryApp.slug}});
  152. render(<SentryApplicationDashboard />, {router});
  153. expect(
  154. await screen.findByText('No requests found in the last 30 days.')
  155. ).toBeInTheDocument();
  156. });
  157. it('shows the component interactions in a line chart', async () => {
  158. const router = RouterFixture({params: {appSlug: sentryApp.slug}});
  159. render(<SentryApplicationDashboard />, {router});
  160. expect(await screen.findByTestId('chart')).toBeInTheDocument();
  161. });
  162. });
  163. });