releaseActions.spec.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208
  1. import type {Location} from 'history';
  2. import {HealthFixture} from 'sentry-fixture/health';
  3. import {LocationFixture} from 'sentry-fixture/locationFixture';
  4. import {OrganizationFixture} from 'sentry-fixture/organization';
  5. import {ReleaseFixture} from 'sentry-fixture/release';
  6. import {ReleaseMetaFixture} from 'sentry-fixture/releaseMeta';
  7. import {ReleaseProjectFixture} from 'sentry-fixture/releaseProject';
  8. import {RouteComponentPropsFixture} from 'sentry-fixture/routeComponentPropsFixture';
  9. import {RouterFixture} from 'sentry-fixture/routerFixture';
  10. import {
  11. render,
  12. renderGlobalModal,
  13. screen,
  14. userEvent,
  15. waitFor,
  16. } from 'sentry-test/reactTestingLibrary';
  17. import type {ReleaseProject} from 'sentry/types/release';
  18. import {ReleaseStatus} from 'sentry/types/release';
  19. import ReleaseActions from 'sentry/views/releases/detail/header/releaseActions';
  20. describe('ReleaseActions', function () {
  21. const router = RouterFixture();
  22. const organization = OrganizationFixture();
  23. const project1 = ReleaseProjectFixture({
  24. slug: 'project1',
  25. hasHealthData: true,
  26. healthData: HealthFixture(),
  27. }) as Required<ReleaseProject>;
  28. const project2 = ReleaseProjectFixture({
  29. slug: 'project2',
  30. hasHealthData: true,
  31. healthData: HealthFixture(),
  32. }) as Required<ReleaseProject>;
  33. const release = ReleaseFixture({
  34. projects: [project1, project2],
  35. });
  36. const location: Location = {
  37. ...LocationFixture(),
  38. pathname: `/organizations/${organization.slug}/releases/${release.version}/`,
  39. query: {
  40. project: '1',
  41. statsPeriod: '24h',
  42. yAxis: 'events',
  43. },
  44. };
  45. let mockUpdate: ReturnType<typeof MockApiClient.addMockResponse>;
  46. beforeEach(function () {
  47. mockUpdate = MockApiClient.addMockResponse({
  48. url: `/organizations/${organization.slug}/releases/`,
  49. method: 'POST',
  50. });
  51. });
  52. afterEach(function () {
  53. MockApiClient.clearMockResponses();
  54. });
  55. it('archives a release', async function () {
  56. render(
  57. <ReleaseActions
  58. organization={organization}
  59. projectSlug={release.projects[0]!.slug}
  60. release={release}
  61. refetchData={jest.fn()}
  62. releaseMeta={{...ReleaseMetaFixture(), projects: release.projects}}
  63. location={location}
  64. />,
  65. {router}
  66. );
  67. renderGlobalModal({router});
  68. await userEvent.click(screen.getByLabelText('Actions'));
  69. const archiveAction = screen.getByTestId('archive');
  70. expect(archiveAction).toBeInTheDocument();
  71. expect(archiveAction).toHaveTextContent('Archive');
  72. await userEvent.click(archiveAction);
  73. expect(await screen.findByText('Archive Release 1.2.0')).toBeInTheDocument();
  74. const affectedProjects = screen.getAllByTestId('badge-display-name');
  75. expect(affectedProjects).toHaveLength(2);
  76. // confirm modal
  77. await userEvent.click(screen.getByTestId('confirm-button'));
  78. expect(mockUpdate).toHaveBeenCalledWith(
  79. expect.anything(),
  80. expect.objectContaining({
  81. data: {
  82. projects: [],
  83. status: 'archived',
  84. version: release.version,
  85. },
  86. })
  87. );
  88. await waitFor(() =>
  89. expect(router.push).toHaveBeenCalledWith(
  90. `/organizations/${organization.slug}/releases/`
  91. )
  92. );
  93. });
  94. it('restores a release', async function () {
  95. const refetchDataMock = jest.fn();
  96. render(
  97. <ReleaseActions
  98. {...RouteComponentPropsFixture()}
  99. organization={organization}
  100. projectSlug={release.projects[0]!.slug}
  101. release={{...release, status: ReleaseStatus.ARCHIVED}}
  102. refetchData={refetchDataMock}
  103. releaseMeta={{...ReleaseMetaFixture(), projects: release.projects}}
  104. location={location}
  105. />,
  106. {router}
  107. );
  108. renderGlobalModal({router});
  109. await userEvent.click(screen.getByLabelText('Actions'));
  110. const restoreAction = screen.getByTestId('restore');
  111. expect(restoreAction).toBeInTheDocument();
  112. expect(restoreAction).toHaveTextContent('Restore');
  113. await userEvent.click(restoreAction);
  114. expect(await screen.findByText('Restore Release 1.2.0')).toBeInTheDocument();
  115. const affectedProjects = screen.getAllByTestId('badge-display-name');
  116. expect(affectedProjects).toHaveLength(2);
  117. // confirm modal
  118. await userEvent.click(screen.getByTestId('confirm-button'));
  119. expect(mockUpdate).toHaveBeenCalledWith(
  120. expect.anything(),
  121. expect.objectContaining({
  122. data: {
  123. projects: [],
  124. status: 'open',
  125. version: release.version,
  126. },
  127. })
  128. );
  129. await waitFor(() => expect(refetchDataMock).toHaveBeenCalledTimes(1));
  130. });
  131. it('navigates to a next/prev release', function () {
  132. const {rerender} = render(
  133. <ReleaseActions
  134. organization={organization}
  135. projectSlug={release.projects[0]!.slug}
  136. release={release}
  137. refetchData={jest.fn()}
  138. releaseMeta={{...ReleaseMetaFixture(), projects: release.projects}}
  139. location={location}
  140. />,
  141. {router}
  142. );
  143. expect(screen.getByLabelText('Oldest')).toHaveAttribute(
  144. 'href',
  145. `/organizations/${organization.slug}/releases/0/?project=1&statsPeriod=24h&yAxis=events`
  146. );
  147. expect(screen.getByLabelText('Older')).toHaveAttribute(
  148. 'href',
  149. `/organizations/${organization.slug}/releases/123/?project=1&statsPeriod=24h&yAxis=events`
  150. );
  151. expect(screen.getByLabelText('Newer')).toHaveAttribute(
  152. 'href',
  153. `/organizations/${organization.slug}/releases/456/?project=1&statsPeriod=24h&yAxis=events`
  154. );
  155. expect(screen.getByLabelText('Newest')).toHaveAttribute(
  156. 'href',
  157. `/organizations/${organization.slug}/releases/999/?project=1&statsPeriod=24h&yAxis=events`
  158. );
  159. rerender(
  160. <ReleaseActions
  161. organization={organization}
  162. projectSlug={release.projects[0]!.slug}
  163. release={release}
  164. refetchData={jest.fn()}
  165. releaseMeta={{...ReleaseMetaFixture(), projects: release.projects}}
  166. location={{
  167. ...location,
  168. pathname: `/organizations/${organization.slug}/releases/${release.version}/files-changed/`,
  169. }}
  170. />
  171. );
  172. expect(screen.getByLabelText('Newer')).toHaveAttribute(
  173. 'href',
  174. `/organizations/${organization.slug}/releases/456/files-changed/?project=1&statsPeriod=24h&yAxis=events`
  175. );
  176. });
  177. });