index.spec.jsx 8.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. import {mountWithTheme} from 'sentry-test/enzyme';
  2. import {Client} from 'sentry/api';
  3. import SentryApplicationDashboard from 'sentry/views/settings/organizationDeveloperSettings/sentryApplicationDashboard';
  4. describe('Sentry Application Dashboard', function () {
  5. const NUM_INSTALLS = 5;
  6. const NUM_UNINSTALLS = 2;
  7. let org;
  8. let orgId;
  9. let sentryApp;
  10. let request;
  11. let wrapper;
  12. beforeEach(() => {
  13. Client.clearMockResponses();
  14. org = TestStubs.Organization();
  15. orgId = org.slug;
  16. });
  17. describe('Viewing the Sentry App Dashboard for a published integration', () => {
  18. beforeEach(() => {
  19. sentryApp = TestStubs.SentryApp({
  20. status: 'published',
  21. schema: {
  22. elements: [
  23. {type: 'stacktrace-link', uri: '/test'},
  24. {
  25. type: 'issue-link',
  26. create: {uri: '/test', required_fields: []},
  27. link: {uri: '/test', required_fields: []},
  28. },
  29. ],
  30. },
  31. });
  32. request = TestStubs.SentryAppWebhookRequest();
  33. Client.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. Client.addMockResponse({
  43. url: `/sentry-apps/${sentryApp.slug}/requests/`,
  44. body: [request],
  45. });
  46. Client.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. Client.addMockResponse({
  57. url: `/sentry-apps/${sentryApp.slug}/`,
  58. body: sentryApp,
  59. });
  60. wrapper = mountWithTheme(
  61. <SentryApplicationDashboard params={{appSlug: sentryApp.slug, orgId}} />
  62. );
  63. });
  64. it('shows the total install/uninstall stats', () => {
  65. const installsStat = wrapper
  66. .find('StatsSection')
  67. .filterWhere(h => h.text().includes('Total installs'))
  68. .find('p');
  69. const uninstallsStat = wrapper
  70. .find('StatsSection')
  71. .filterWhere(h => h.text().includes('Total uninstalls'))
  72. .find('p');
  73. expect(installsStat.text()).toEqual(`${NUM_INSTALLS}`);
  74. expect(uninstallsStat.text()).toEqual(`${NUM_UNINSTALLS}`);
  75. });
  76. it('shows the installation stats in a graph', () => {
  77. const chart = wrapper.find('BarChart');
  78. const chartSeries = chart.props().series;
  79. expect(chart.exists()).toBeTruthy();
  80. expect(chartSeries).toHaveLength(2);
  81. expect(chartSeries).toContainEqual({
  82. data: [{name: 1569783600 * 1000, value: NUM_INSTALLS}],
  83. seriesName: 'installed',
  84. });
  85. expect(chartSeries).toContainEqual({
  86. data: [{name: 1569783600 * 1000, value: NUM_UNINSTALLS}],
  87. seriesName: 'uninstalled',
  88. });
  89. });
  90. it('shows the request log', () => {
  91. const requestLog = wrapper.find('PanelBody');
  92. const requestLogText = requestLog.find('PanelItem').text();
  93. // The mock response has 1 request
  94. expect(requestLog.find('PanelItem')).toHaveLength(1);
  95. // Make sure that all the info is displayed
  96. expect(requestLogText).toEqual(
  97. expect.stringContaining('https://example.com/webhook')
  98. );
  99. expect(requestLogText).toEqual(expect.stringContaining('400'));
  100. expect(requestLogText).toEqual(expect.stringContaining('issue.assigned'));
  101. expect(requestLogText).toEqual(expect.stringContaining('Test Org'));
  102. });
  103. it('shows an empty message if there are no requests', () => {
  104. Client.addMockResponse({
  105. url: `/sentry-apps/${sentryApp.slug}/requests/`,
  106. body: [],
  107. });
  108. wrapper = mountWithTheme(
  109. <SentryApplicationDashboard params={{appSlug: sentryApp.slug, orgId}} />
  110. );
  111. expect(wrapper.find('PanelBody').exists('PanelItem')).toBeFalsy();
  112. expect(wrapper.find('EmptyMessage').text()).toEqual(
  113. expect.stringContaining('No requests found in the last 30 days.')
  114. );
  115. });
  116. it('shows the integration views in a line chart', () => {
  117. const chart = wrapper
  118. .find('Panel')
  119. .filterWhere(h => h.text().includes('Integration Views'))
  120. .find('LineChart');
  121. const chartData = chart.props().series[0].data;
  122. expect(chart.exists()).toBeTruthy();
  123. expect(chartData).toHaveLength(1);
  124. expect(chartData).toContainEqual({name: 1569783600 * 1000, value: 1});
  125. });
  126. it('shows the component interactions in a line chart', () => {
  127. const chart = wrapper
  128. .find('Panel')
  129. .filterWhere(h => h.text().includes('Component Interactions'))
  130. .find('LineChart');
  131. const chartSeries = chart.props().series;
  132. expect(chart.exists()).toBeTruthy();
  133. expect(chartSeries).toHaveLength(2);
  134. expect(chartSeries).toContainEqual({
  135. data: [{name: 1569783600 * 1000, value: 1}],
  136. seriesName: 'stacktrace-link',
  137. });
  138. expect(chartSeries).toContainEqual({
  139. data: [{name: 1569783600 * 1000, value: 1}],
  140. seriesName: 'issue-link',
  141. });
  142. });
  143. });
  144. describe('Viewing the Sentry App Dashboard for an internal integration', () => {
  145. beforeEach(() => {
  146. sentryApp = TestStubs.SentryApp({
  147. status: 'internal',
  148. schema: {
  149. elements: [{type: 'stacktrace-link', uri: '/test'}],
  150. },
  151. });
  152. request = TestStubs.SentryAppWebhookRequest();
  153. Client.addMockResponse({
  154. url: `/sentry-apps/${sentryApp.slug}/stats/`,
  155. body: {
  156. totalInstalls: 1,
  157. totalUninstalls: 0,
  158. installStats: [[1569783600, 1]],
  159. uninstallStats: [[1569783600, 0]],
  160. },
  161. });
  162. Client.addMockResponse({
  163. url: `/sentry-apps/${sentryApp.slug}/requests/`,
  164. body: [request],
  165. });
  166. Client.addMockResponse({
  167. url: `/sentry-apps/${sentryApp.slug}/interaction/`,
  168. body: {
  169. componentInteractions: {
  170. 'stacktrace-link': [[1569783600, 1]],
  171. },
  172. views: [[1569783600, 1]],
  173. },
  174. });
  175. Client.addMockResponse({
  176. url: `/sentry-apps/${sentryApp.slug}/`,
  177. body: sentryApp,
  178. });
  179. wrapper = mountWithTheme(
  180. <SentryApplicationDashboard params={{appSlug: sentryApp.slug, orgId}} />
  181. );
  182. });
  183. it('does not show the installation stats or graph', () => {
  184. expect(wrapper.exists('StatsSection')).toBeFalsy();
  185. expect(wrapper.exists('BarChart')).toBeFalsy();
  186. });
  187. it('shows the request log', () => {
  188. const requestLog = wrapper.find('PanelBody');
  189. const requestLogText = requestLog.find('PanelItem').text();
  190. // The mock response has 1 request
  191. expect(requestLog.find('PanelItem')).toHaveLength(1);
  192. // Make sure that all the info is displayed
  193. expect(requestLogText).toEqual(
  194. expect.stringContaining('https://example.com/webhook')
  195. );
  196. expect(requestLogText).toEqual(expect.stringContaining('400'));
  197. expect(requestLogText).toEqual(expect.stringContaining('issue.assigned'));
  198. });
  199. it('shows an empty message if there are no requests', () => {
  200. Client.addMockResponse({
  201. url: `/sentry-apps/${sentryApp.slug}/requests/`,
  202. body: [],
  203. });
  204. wrapper = mountWithTheme(
  205. <SentryApplicationDashboard params={{appSlug: sentryApp.slug, orgId}} />
  206. );
  207. expect(wrapper.find('PanelBody').exists('PanelItem')).toBeFalsy();
  208. expect(wrapper.find('EmptyMessage').text()).toEqual(
  209. expect.stringContaining('No requests found in the last 30 days.')
  210. );
  211. });
  212. it('does not show the integration views', () => {
  213. const chart = wrapper.findWhere(h => h.text().includes('Integration Views'));
  214. expect(chart.exists()).toBeFalsy();
  215. });
  216. it('shows the component interactions in a line chart', () => {
  217. const chart = wrapper
  218. .find('Panel')
  219. .filterWhere(h => h.text().includes('Component Interactions'))
  220. .find('LineChart');
  221. const chartSeries = chart.props().series;
  222. expect(chart.exists()).toBeTruthy();
  223. expect(chartSeries).toHaveLength(1);
  224. expect(chartSeries).toContainEqual({
  225. data: [{name: 1569783600 * 1000, value: 1}],
  226. seriesName: 'stacktrace-link',
  227. });
  228. });
  229. });
  230. });