sudoModal.spec.jsx 3.7 KB

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