sudoModal.spec.jsx 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152
  1. import {mountWithTheme} from 'sentry-test/enzyme';
  2. import {act} from 'sentry-test/reactTestingLibrary';
  3. import {Client} from 'sentry/api';
  4. import ConfigStore from 'sentry/stores/configStore';
  5. import App from 'sentry/views/app';
  6. describe('Sudo Modal', function () {
  7. const setHasPasswordAuth = hasPasswordAuth =>
  8. act(() => ConfigStore.set('user', {...ConfigStore.get('user'), hasPasswordAuth}));
  9. beforeEach(function () {
  10. Client.clearMockResponses();
  11. Client.addMockResponse({
  12. url: '/internal/health/',
  13. body: {
  14. problems: [],
  15. },
  16. });
  17. Client.addMockResponse({
  18. url: '/assistant/',
  19. body: [],
  20. });
  21. Client.addMockResponse({
  22. url: '/organizations/',
  23. body: [TestStubs.Organization()],
  24. });
  25. Client.addMockResponse({
  26. url: '/organizations/org-slug/',
  27. method: 'DELETE',
  28. statusCode: 401,
  29. body: {
  30. detail: {
  31. code: 'sudo-required',
  32. username: 'test@test.com',
  33. },
  34. },
  35. });
  36. Client.addMockResponse({
  37. url: '/authenticators/',
  38. body: [],
  39. });
  40. });
  41. it('can delete an org with sudo flow', async function () {
  42. setHasPasswordAuth(true);
  43. const wrapper = mountWithTheme(<App>{<div>placeholder content</div>}</App>);
  44. const api = new Client();
  45. const successCb = jest.fn();
  46. const errorCb = jest.fn();
  47. // No Modal
  48. expect(wrapper.find('GlobalModal[visible=true]').exists()).toBe(false);
  49. // Should return w/ `sudoRequired`
  50. api.request('/organizations/org-slug/', {
  51. method: 'DELETE',
  52. success: successCb,
  53. error: errorCb,
  54. });
  55. await tick();
  56. await tick();
  57. wrapper.update();
  58. // Should have Modal + input
  59. expect(wrapper.find('Modal input')).toHaveLength(1);
  60. // Original callbacks should not have been called
  61. expect(successCb).not.toHaveBeenCalled();
  62. expect(errorCb).not.toHaveBeenCalled();
  63. // Clear mocks and allow DELETE
  64. Client.clearMockResponses();
  65. const orgDeleteMock = Client.addMockResponse({
  66. url: '/organizations/org-slug/',
  67. method: 'DELETE',
  68. statusCode: 200,
  69. });
  70. const sudoMock = Client.addMockResponse({
  71. url: '/auth/',
  72. method: 'PUT',
  73. statusCode: 200,
  74. });
  75. expect(sudoMock).not.toHaveBeenCalled();
  76. // "Sudo" auth
  77. wrapper
  78. .find('Modal input[name="password"]')
  79. .simulate('change', {target: {value: 'password'}});
  80. wrapper.find('Modal form').simulate('submit');
  81. wrapper.find('Modal Button[type="submit"]').simulate('click');
  82. await tick();
  83. wrapper.update();
  84. expect(sudoMock).toHaveBeenCalledWith(
  85. '/auth/',
  86. expect.objectContaining({
  87. method: 'PUT',
  88. data: {isSuperuserModal: false, password: 'password'},
  89. })
  90. );
  91. // Retry API request
  92. expect(successCb).toHaveBeenCalled();
  93. expect(orgDeleteMock).toHaveBeenCalledWith(
  94. '/organizations/org-slug/',
  95. expect.objectContaining({
  96. method: 'DELETE',
  97. })
  98. );
  99. await tick();
  100. wrapper.update();
  101. // Sudo Modal should be closed
  102. expect(wrapper.find('GlobalModal[visible=true]').exists()).toBe(false);
  103. });
  104. it('shows button to redirect if user does not have password auth', async function () {
  105. setHasPasswordAuth(false);
  106. const wrapper = mountWithTheme(<App>{<div>placeholder content</div>}</App>);
  107. const api = new Client();
  108. const successCb = jest.fn();
  109. const errorCb = jest.fn();
  110. // No Modal
  111. expect(wrapper.find('GlobalModal[visible=true]').exists()).toBe(false);
  112. // Should return w/ `sudoRequired`
  113. api.request('/organizations/org-slug/', {
  114. method: 'DELETE',
  115. success: successCb,
  116. error: errorCb,
  117. });
  118. await tick();
  119. await tick();
  120. wrapper.update();
  121. // Should have Modal + input
  122. expect(wrapper.find('Modal input')).toHaveLength(0);
  123. expect(wrapper.find('Button[href]').prop('href')).toMatch('/auth/login/?next=%2F');
  124. });
  125. });