sudoModal.spec.jsx 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158
  1. import React from 'react';
  2. import {mount} from 'enzyme';
  3. import {Client} from 'app/api';
  4. import App from 'app/views/app';
  5. import ConfigStore from 'app/stores/configStore';
  6. jest.mock('jquery');
  7. describe('Sudo Modal', function() {
  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. it('can delete an org with sudo flow', async function() {
  41. ConfigStore.set('user', {
  42. ...ConfigStore.get('user'),
  43. hasPasswordAuth: true,
  44. });
  45. let wrapper = mount(<App>{<div>placeholder content</div>}</App>);
  46. let api = new Client();
  47. let successCb = jest.fn();
  48. let errorCb = jest.fn();
  49. let orgDeleteMock;
  50. // No Modal
  51. expect(wrapper.find('ModalDialog')).toHaveLength(0);
  52. // Should return w/ `sudoRequired`
  53. api.request('/organizations/org-slug/', {
  54. method: 'DELETE',
  55. success: successCb,
  56. error: errorCb,
  57. });
  58. await tick();
  59. await tick();
  60. wrapper.update();
  61. // Should have Modal + input
  62. expect(wrapper.find('ModalDialog input')).toHaveLength(1);
  63. // Original callbacks should not have been called
  64. expect(successCb).not.toBeCalled();
  65. expect(errorCb).not.toBeCalled();
  66. // Clear mocks and allow DELETE
  67. Client.clearMockResponses();
  68. orgDeleteMock = Client.addMockResponse({
  69. url: '/organizations/org-slug/',
  70. method: 'DELETE',
  71. statusCode: 200,
  72. });
  73. let sudoMock = Client.addMockResponse({
  74. url: '/auth/',
  75. method: 'PUT',
  76. statusCode: 200,
  77. });
  78. expect(sudoMock).not.toHaveBeenCalled();
  79. // "Sudo" auth
  80. wrapper
  81. .find('ModalDialog input[name="password"]')
  82. .simulate('change', {target: {value: 'password'}});
  83. wrapper.find('ModalDialog form').simulate('submit');
  84. wrapper.find('ModalDialog Button[type="submit"]').simulate('click');
  85. await tick();
  86. wrapper.update();
  87. expect(sudoMock).toHaveBeenCalledWith(
  88. '/auth/',
  89. expect.objectContaining({
  90. method: 'PUT',
  91. data: {
  92. password: 'password',
  93. },
  94. })
  95. );
  96. // Retry API request
  97. expect(successCb).toHaveBeenCalled();
  98. expect(orgDeleteMock).toHaveBeenCalledWith(
  99. '/organizations/org-slug/',
  100. expect.objectContaining({
  101. method: 'DELETE',
  102. })
  103. );
  104. await tick();
  105. wrapper.update();
  106. // Sudo Modal should be closed
  107. expect(wrapper.find('ModalDialog')).toHaveLength(0);
  108. });
  109. it('shows button to redirect if user does not have password auth', async function() {
  110. ConfigStore.set('user', {
  111. ...ConfigStore.get('user'),
  112. hasPasswordAuth: false,
  113. });
  114. let wrapper = mount(<App>{<div>placeholder content</div>}</App>);
  115. let api = new Client();
  116. let successCb = jest.fn();
  117. let errorCb = jest.fn();
  118. // No Modal
  119. expect(wrapper.find('ModalDialog')).toHaveLength(0);
  120. // Should return w/ `sudoRequired`
  121. api.request('/organizations/org-slug/', {
  122. method: 'DELETE',
  123. success: successCb,
  124. error: errorCb,
  125. });
  126. await tick();
  127. await tick();
  128. wrapper.update();
  129. // Should have Modal + input
  130. expect(wrapper.find('ModalDialog input')).toHaveLength(0);
  131. expect(wrapper.find('Button').prop('href')).toMatch('/auth/login/?next=%2F');
  132. });
  133. });