resolve.spec.jsx 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. import {Fragment} from 'react';
  2. import {mountWithTheme} from 'sentry-test/enzyme';
  3. import {selectByValue} from 'sentry-test/select-new';
  4. import ResolveActions from 'app/components/actions/resolve';
  5. import GlobalModal from 'app/components/globalModal';
  6. describe('ResolveActions', function () {
  7. describe('disabled', function () {
  8. let component, button;
  9. const spy = jest.fn();
  10. beforeEach(function () {
  11. component = mountWithTheme(
  12. <ResolveActions
  13. onUpdate={spy}
  14. disabled
  15. hasRelease={false}
  16. orgSlug="org-1"
  17. projectSlug="proj-1"
  18. />,
  19. TestStubs.routerContext()
  20. );
  21. button = component.find('button[aria-label="Resolve"]').first();
  22. });
  23. it('has disabled prop', function () {
  24. expect(button.props()['aria-disabled']).toBe(true);
  25. });
  26. it('does not call onUpdate when clicked', function () {
  27. button.simulate('click');
  28. expect(spy).not.toHaveBeenCalled();
  29. });
  30. });
  31. describe('disableDropdown', function () {
  32. let component, button;
  33. const spy = jest.fn();
  34. beforeEach(function () {
  35. component = mountWithTheme(
  36. <ResolveActions
  37. onUpdate={spy}
  38. disableDropdown
  39. hasRelease={false}
  40. orgSlug="org-1"
  41. projectSlug="proj-1"
  42. />,
  43. TestStubs.routerContext()
  44. );
  45. });
  46. it('main button is enabled', function () {
  47. button = component.find('button[aria-label="Resolve"]');
  48. expect(button.prop('disabled')).toBeFalsy();
  49. });
  50. it('main button calls onUpdate when clicked', function () {
  51. button = component.find('button[aria-label="Resolve"]');
  52. button.simulate('click');
  53. expect(spy).toHaveBeenCalled();
  54. });
  55. it('dropdown menu is disabled', function () {
  56. button = component.find('button[aria-label="More resolve options"]');
  57. expect(button.props()['aria-disabled']).toBe(true);
  58. });
  59. });
  60. describe('resolved', function () {
  61. let component;
  62. const spy = jest.fn();
  63. beforeEach(function () {
  64. component = mountWithTheme(
  65. <ResolveActions
  66. onUpdate={spy}
  67. disabled
  68. hasRelease={false}
  69. orgSlug="org-1"
  70. projectSlug="proj-1"
  71. isResolved
  72. />,
  73. TestStubs.routerContext()
  74. );
  75. });
  76. it('displays resolved view', function () {
  77. const button = component.find('button[aria-label="Unresolve"]').first();
  78. expect(button).toHaveLength(1);
  79. expect(button.text()).toBe('');
  80. });
  81. it('calls onUpdate with unresolved status when clicked', function () {
  82. component.find('button[aria-label="Unresolve"]').last().simulate('click');
  83. expect(spy).toHaveBeenCalledWith({status: 'unresolved'});
  84. });
  85. });
  86. describe('auto resolved', function () {
  87. it('cannot be unresolved manually', function () {
  88. const spy = jest.fn();
  89. const component = mountWithTheme(
  90. <ResolveActions
  91. onUpdate={spy}
  92. disabled
  93. hasRelease={false}
  94. orgSlug="org-1"
  95. projectSlug="proj-1"
  96. isResolved
  97. isAutoResolved
  98. />,
  99. TestStubs.routerContext()
  100. );
  101. component.find('button[aria-label="Unresolve"]').simulate('click');
  102. expect(spy).not.toHaveBeenCalled();
  103. });
  104. });
  105. describe('without confirmation', function () {
  106. let component;
  107. const spy = jest.fn();
  108. beforeEach(function () {
  109. component = mountWithTheme(
  110. <ResolveActions
  111. onUpdate={spy}
  112. hasRelease={false}
  113. orgSlug="org-1"
  114. projectSlug="proj-1"
  115. />,
  116. TestStubs.routerContext()
  117. );
  118. });
  119. it('renders', function () {
  120. expect(component).toSnapshot();
  121. });
  122. it('calls spy with resolved status when clicked', function () {
  123. const button = component.find('button[aria-label="Resolve"]');
  124. button.simulate('click');
  125. expect(spy).toHaveBeenCalledTimes(1);
  126. expect(spy).toHaveBeenCalledWith({status: 'resolved'});
  127. });
  128. });
  129. describe('with confirmation step', function () {
  130. let component, button;
  131. const spy = jest.fn();
  132. beforeEach(function () {
  133. component = mountWithTheme(
  134. <Fragment>
  135. <GlobalModal />
  136. <ResolveActions
  137. onUpdate={spy}
  138. hasRelease={false}
  139. orgSlug="org-1"
  140. projectSlug="proj-1"
  141. shouldConfirm
  142. confirmMessage="Are you sure???"
  143. />
  144. </Fragment>,
  145. TestStubs.routerContext()
  146. );
  147. });
  148. it('renders', function () {
  149. expect(component).toSnapshot();
  150. });
  151. it('displays confirmation modal with message provided', async function () {
  152. button = component.find('button[aria-label="Resolve"]').first();
  153. button.simulate('click');
  154. await tick();
  155. component.update();
  156. const modal = component.find('Modal');
  157. expect(modal.text()).toContain('Are you sure???');
  158. expect(spy).not.toHaveBeenCalled();
  159. modal.find('button[aria-label="Resolve"]').simulate('click');
  160. expect(spy).toHaveBeenCalled();
  161. });
  162. });
  163. it('can resolve in "another version"', async function () {
  164. const onUpdate = jest.fn();
  165. MockApiClient.addMockResponse({
  166. url: '/projects/org-slug/project-slug/releases/',
  167. body: [TestStubs.Release()],
  168. });
  169. const wrapper = mountWithTheme(
  170. <Fragment>
  171. <GlobalModal />
  172. <ResolveActions
  173. hasRelease
  174. orgSlug="org-slug"
  175. projectSlug="project-slug"
  176. onUpdate={onUpdate}
  177. />
  178. </Fragment>,
  179. TestStubs.routerContext()
  180. );
  181. wrapper.find('ActionLink').last().simulate('click');
  182. await tick();
  183. wrapper.update();
  184. expect(wrapper.find('CustomResolutionModal Select').prop('options')).toEqual([
  185. expect.objectContaining({
  186. value: 'sentry-android-shop@1.2.0',
  187. label: expect.anything(),
  188. }),
  189. ]);
  190. selectByValue(wrapper, 'sentry-android-shop@1.2.0', {
  191. selector: 'SelectAsyncControl[name="version"]',
  192. });
  193. wrapper.find('CustomResolutionModal form').simulate('submit');
  194. expect(onUpdate).toHaveBeenCalledWith({
  195. status: 'resolved',
  196. statusDetails: {
  197. inRelease: 'sentry-android-shop@1.2.0',
  198. },
  199. });
  200. });
  201. });