index.spec.tsx 5.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import selectEvent from 'react-select-event';
  2. import pick from 'lodash/pick';
  3. import {OrganizationFixture} from 'sentry-fixture/organization';
  4. import {RouteComponentPropsFixture} from 'sentry-fixture/routeComponentPropsFixture';
  5. import {SentryAppFixture} from 'sentry-fixture/sentryApp';
  6. import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
  7. import {textWithMarkupMatcher} from 'sentry-test/utils';
  8. import type {Organization as TOrganization} from 'sentry/types';
  9. import SentryAppExternalInstallation from 'sentry/views/sentryAppExternalInstallation';
  10. describe('SentryAppExternalInstallation', () => {
  11. let sentryApp: ReturnType<typeof SentryAppFixture>,
  12. getOrgsMock: ReturnType<typeof MockApiClient.addMockResponse>,
  13. getOrgMock: ReturnType<typeof MockApiClient.addMockResponse>,
  14. getAppMock: ReturnType<typeof MockApiClient.addMockResponse>,
  15. getInstallationsMock: ReturnType<typeof MockApiClient.addMockResponse>,
  16. getFeaturesMock: ReturnType<typeof MockApiClient.addMockResponse>,
  17. org1: TOrganization,
  18. org1Lite: Pick<TOrganization, 'slug' | 'name' | 'id'>,
  19. org2: TOrganization,
  20. org2Lite: Pick<TOrganization, 'slug' | 'name' | 'id'>;
  21. beforeEach(() => {
  22. MockApiClient.clearMockResponses();
  23. org1 = OrganizationFixture({
  24. slug: 'org1',
  25. name: 'Organization 1',
  26. });
  27. org2 = OrganizationFixture({
  28. slug: 'org2',
  29. name: 'Organization 2',
  30. });
  31. org1Lite = pick(org1, ['slug', 'name', 'id']);
  32. org2Lite = pick(org2, ['slug', 'name', 'id']);
  33. sentryApp = SentryAppFixture({
  34. status: 'published',
  35. redirectUrl: 'https://google.com',
  36. });
  37. getAppMock = MockApiClient.addMockResponse({
  38. url: `/sentry-apps/${sentryApp.slug}/`,
  39. body: sentryApp,
  40. });
  41. getFeaturesMock = MockApiClient.addMockResponse({
  42. url: `/sentry-apps/${sentryApp.slug}/features/`,
  43. body: [],
  44. });
  45. MockApiClient.addMockResponse({
  46. url: `/sentry-apps/${sentryApp.slug}/interaction/`,
  47. method: 'POST',
  48. statusCode: 200,
  49. body: {},
  50. });
  51. });
  52. describe('single organization', () => {
  53. beforeEach(() => {
  54. getOrgsMock = MockApiClient.addMockResponse({
  55. url: '/organizations/',
  56. body: [org1Lite],
  57. });
  58. getOrgMock = MockApiClient.addMockResponse({
  59. url: `/organizations/${org1.slug}/`,
  60. body: org1,
  61. });
  62. getInstallationsMock = MockApiClient.addMockResponse({
  63. url: `/organizations/${org1.slug}/sentry-app-installations/`,
  64. body: [],
  65. });
  66. });
  67. it('sets the org automatically', () => {
  68. render(
  69. <SentryAppExternalInstallation
  70. {...RouteComponentPropsFixture()}
  71. params={{sentryAppSlug: sentryApp.slug}}
  72. />
  73. );
  74. expect(getAppMock).toHaveBeenCalled();
  75. expect(getOrgsMock).toHaveBeenCalled();
  76. expect(getOrgMock).toHaveBeenCalled();
  77. expect(getInstallationsMock).toHaveBeenCalled();
  78. expect(
  79. screen.getByText(
  80. textWithMarkupMatcher(
  81. 'You are installing Sample App for organization Organization 1'
  82. )
  83. )
  84. ).toBeInTheDocument();
  85. expect(screen.queryByText('Select an organization')).not.toBeInTheDocument();
  86. });
  87. it('installs and redirects', async () => {
  88. const installUrl = `/organizations/${org1.slug}/sentry-app-installations/`;
  89. const install = {
  90. uuid: 'fake-id',
  91. code: 'some-code',
  92. };
  93. const installMock = MockApiClient.addMockResponse({
  94. url: installUrl,
  95. method: 'POST',
  96. body: install,
  97. });
  98. render(
  99. <SentryAppExternalInstallation
  100. {...RouteComponentPropsFixture()}
  101. params={{sentryAppSlug: sentryApp.slug}}
  102. />
  103. );
  104. await userEvent.click(await screen.findByTestId('install'));
  105. expect(installMock).toHaveBeenCalledWith(
  106. installUrl,
  107. expect.objectContaining({
  108. data: {slug: sentryApp.slug},
  109. })
  110. );
  111. await waitFor(() => {
  112. expect(window.location.assign).toHaveBeenCalledWith(
  113. `https://google.com/?code=${install.code}&installationId=${install.uuid}&orgSlug=${org1.slug}`
  114. );
  115. });
  116. (window.location.assign as jest.Mock).mockClear();
  117. });
  118. });
  119. describe('multiple organizations', () => {
  120. beforeEach(() => {
  121. getOrgsMock = MockApiClient.addMockResponse({
  122. url: '/organizations/',
  123. body: [org1Lite, org2Lite],
  124. });
  125. });
  126. it('renders org dropdown', () => {
  127. render(
  128. <SentryAppExternalInstallation
  129. {...RouteComponentPropsFixture()}
  130. params={{sentryAppSlug: sentryApp.slug}}
  131. />
  132. );
  133. expect(getAppMock).toHaveBeenCalled();
  134. expect(getOrgsMock).toHaveBeenCalled();
  135. expect(screen.getByText('Select an organization')).toBeInTheDocument();
  136. });
  137. it('selecting org from dropdown loads the org through the API', async () => {
  138. getOrgMock = MockApiClient.addMockResponse({
  139. url: `/organizations/${org2.slug}/`,
  140. body: org2,
  141. });
  142. getInstallationsMock = MockApiClient.addMockResponse({
  143. url: `/organizations/${org2.slug}/sentry-app-installations/`,
  144. body: [],
  145. });
  146. render(
  147. <SentryAppExternalInstallation
  148. {...RouteComponentPropsFixture()}
  149. params={{sentryAppSlug: sentryApp.slug}}
  150. />
  151. );
  152. await selectEvent.select(screen.getByText('Select an organization'), 'org2');
  153. expect(getOrgMock).toHaveBeenCalledTimes(1);
  154. expect(getOrgMock).toHaveBeenLastCalledWith(
  155. '/organizations/org2/',
  156. expect.anything()
  157. );
  158. expect(getInstallationsMock).toHaveBeenCalled();
  159. expect(getFeaturesMock).toHaveBeenCalled();
  160. await waitFor(() => expect(screen.getByTestId('install')).toBeEnabled());
  161. });
  162. });
  163. });