releaseActions.spec.tsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207
  1. import {browserHistory} from 'react-router';
  2. import type {Location} from 'history';
  3. import {HealthFixture} from 'sentry-fixture/health';
  4. import {LocationFixture} from 'sentry-fixture/locationFixture';
  5. import {OrganizationFixture} from 'sentry-fixture/organization';
  6. import {ReleaseFixture} from 'sentry-fixture/release';
  7. import {ReleaseMetaFixture} from 'sentry-fixture/releaseMeta';
  8. import {ReleaseProjectFixture} from 'sentry-fixture/releaseProject';
  9. import {RouteComponentPropsFixture} from 'sentry-fixture/routeComponentPropsFixture';
  10. import {RouterContextFixture} from 'sentry-fixture/routerContextFixture';
  11. import {
  12. render,
  13. renderGlobalModal,
  14. screen,
  15. userEvent,
  16. waitFor,
  17. } from 'sentry-test/reactTestingLibrary';
  18. import type {ReleaseProject} from 'sentry/types';
  19. import {ReleaseStatus} from 'sentry/types';
  20. import ReleaseActions from 'sentry/views/releases/detail/header/releaseActions';
  21. describe('ReleaseActions', function () {
  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/sentry/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. );
  66. renderGlobalModal();
  67. await userEvent.click(screen.getByLabelText('Actions'));
  68. const archiveAction = screen.getByTestId('archive');
  69. expect(archiveAction).toBeInTheDocument();
  70. expect(archiveAction).toHaveTextContent('Archive');
  71. await userEvent.click(archiveAction);
  72. expect(await screen.findByText('Archive Release 1.2.0')).toBeInTheDocument();
  73. const affectedProjects = screen.getAllByTestId('badge-display-name');
  74. expect(affectedProjects.length).toBe(2);
  75. // confirm modal
  76. await userEvent.click(screen.getByTestId('confirm-button'));
  77. expect(mockUpdate).toHaveBeenCalledWith(
  78. expect.anything(),
  79. expect.objectContaining({
  80. data: {
  81. projects: [],
  82. status: 'archived',
  83. version: release.version,
  84. },
  85. })
  86. );
  87. await waitFor(() =>
  88. expect(browserHistory.push).toHaveBeenCalledWith(
  89. `/organizations/${organization.slug}/releases/`
  90. )
  91. );
  92. });
  93. it('restores a release', async function () {
  94. const refetchDataMock = jest.fn();
  95. render(
  96. <ReleaseActions
  97. {...RouteComponentPropsFixture()}
  98. organization={organization}
  99. projectSlug={release.projects[0].slug}
  100. release={{...release, status: ReleaseStatus.ARCHIVED}}
  101. refetchData={refetchDataMock}
  102. releaseMeta={{...ReleaseMetaFixture(), projects: release.projects}}
  103. location={location}
  104. />
  105. );
  106. renderGlobalModal();
  107. await userEvent.click(screen.getByLabelText('Actions'));
  108. const restoreAction = screen.getByTestId('restore');
  109. expect(restoreAction).toBeInTheDocument();
  110. expect(restoreAction).toHaveTextContent('Restore');
  111. await userEvent.click(restoreAction);
  112. expect(await screen.findByText('Restore Release 1.2.0')).toBeInTheDocument();
  113. const affectedProjects = screen.getAllByTestId('badge-display-name');
  114. expect(affectedProjects.length).toBe(2);
  115. // confirm modal
  116. await userEvent.click(screen.getByTestId('confirm-button'));
  117. expect(mockUpdate).toHaveBeenCalledWith(
  118. expect.anything(),
  119. expect.objectContaining({
  120. data: {
  121. projects: [],
  122. status: 'open',
  123. version: release.version,
  124. },
  125. })
  126. );
  127. await waitFor(() => expect(refetchDataMock).toHaveBeenCalledTimes(1));
  128. });
  129. it('navigates to a next/prev release', function () {
  130. const routerContext = RouterContextFixture();
  131. const {rerender} = render(
  132. <ReleaseActions
  133. organization={organization}
  134. projectSlug={release.projects[0].slug}
  135. release={release}
  136. refetchData={jest.fn()}
  137. releaseMeta={{...ReleaseMetaFixture(), projects: release.projects}}
  138. location={location}
  139. />,
  140. {context: routerContext}
  141. );
  142. expect(screen.getByLabelText('Oldest')).toHaveAttribute(
  143. 'href',
  144. '/organizations/sentry/releases/0/?project=1&statsPeriod=24h&yAxis=events'
  145. );
  146. expect(screen.getByLabelText('Older')).toHaveAttribute(
  147. 'href',
  148. '/organizations/sentry/releases/123/?project=1&statsPeriod=24h&yAxis=events'
  149. );
  150. expect(screen.getByLabelText('Newer')).toHaveAttribute(
  151. 'href',
  152. '/organizations/sentry/releases/456/?project=1&statsPeriod=24h&yAxis=events'
  153. );
  154. expect(screen.getByLabelText('Newest')).toHaveAttribute(
  155. 'href',
  156. '/organizations/sentry/releases/999/?project=1&statsPeriod=24h&yAxis=events'
  157. );
  158. rerender(
  159. <ReleaseActions
  160. organization={organization}
  161. projectSlug={release.projects[0].slug}
  162. release={release}
  163. refetchData={jest.fn()}
  164. releaseMeta={{...ReleaseMetaFixture(), projects: release.projects}}
  165. location={{
  166. ...location,
  167. pathname: `/organizations/sentry/releases/${release.version}/files-changed/`,
  168. }}
  169. />
  170. );
  171. expect(screen.getByLabelText('Newer')).toHaveAttribute(
  172. 'href',
  173. '/organizations/sentry/releases/456/files-changed/?project=1&statsPeriod=24h&yAxis=events'
  174. );
  175. });
  176. });