accountSecurityDetails.spec.jsx 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. import {mountWithTheme} from 'sentry-test/enzyme';
  2. import {initializeOrg} from 'sentry-test/initializeOrg';
  3. import {mountGlobalModal} from 'sentry-test/modal';
  4. import {Client} from 'sentry/api';
  5. import AccountSecurityDetails from 'sentry/views/settings/account/accountSecurity/accountSecurityDetails';
  6. import AccountSecurityWrapper from 'sentry/views/settings/account/accountSecurity/accountSecurityWrapper';
  7. const ENDPOINT = '/users/me/authenticators/';
  8. const ACCOUNT_EMAILS_ENDPOINT = '/users/me/emails/';
  9. const ORG_ENDPOINT = '/organizations/';
  10. describe('AccountSecurityDetails', function () {
  11. let wrapper;
  12. let routerContext;
  13. let router;
  14. let params;
  15. describe('Totp', function () {
  16. beforeAll(function () {
  17. Client.clearMockResponses();
  18. params = {
  19. authId: 15,
  20. };
  21. ({router, routerContext} = initializeOrg({
  22. router: {
  23. params,
  24. },
  25. }));
  26. Client.addMockResponse({
  27. url: ENDPOINT,
  28. body: TestStubs.AllAuthenticators(),
  29. });
  30. Client.addMockResponse({
  31. url: ORG_ENDPOINT,
  32. body: TestStubs.Organizations(),
  33. });
  34. Client.addMockResponse({
  35. url: `${ENDPOINT}15/`,
  36. body: TestStubs.Authenticators().Totp(),
  37. });
  38. Client.addMockResponse({
  39. url: ACCOUNT_EMAILS_ENDPOINT,
  40. body: TestStubs.AccountEmails(),
  41. });
  42. wrapper = mountWithTheme(
  43. <AccountSecurityWrapper router={router} params={params}>
  44. <AccountSecurityDetails router={router} params={params} />
  45. </AccountSecurityWrapper>,
  46. routerContext
  47. );
  48. });
  49. it('has enrolled circle indicator', function () {
  50. expect(wrapper.find('AuthenticatorStatus').prop('enabled')).toBe(true);
  51. });
  52. it('has created and last used dates', function () {
  53. expect(wrapper.find('AuthenticatorDate')).toHaveLength(2);
  54. });
  55. it('can remove method', async function () {
  56. const deleteMock = Client.addMockResponse({
  57. url: `${ENDPOINT}15/`,
  58. method: 'DELETE',
  59. });
  60. wrapper.find('RemoveConfirm Button').simulate('click');
  61. const modal = await mountGlobalModal();
  62. modal.find('Button[priority="primary"]').simulate('click');
  63. expect(deleteMock).toHaveBeenCalled();
  64. });
  65. it('can remove one of multiple 2fa methods when org requires 2fa', async function () {
  66. Client.addMockResponse({
  67. url: ORG_ENDPOINT,
  68. body: TestStubs.Organizations({require2FA: true}),
  69. });
  70. const deleteMock = Client.addMockResponse({
  71. url: `${ENDPOINT}15/`,
  72. method: 'DELETE',
  73. });
  74. wrapper = mountWithTheme(
  75. <AccountSecurityWrapper router={router} params={params}>
  76. <AccountSecurityDetails router={router} params={params} />
  77. </AccountSecurityWrapper>,
  78. routerContext
  79. );
  80. wrapper.find('RemoveConfirm Button').simulate('click');
  81. const modal = await mountGlobalModal();
  82. modal.find('Button[priority="primary"]').simulate('click');
  83. expect(deleteMock).toHaveBeenCalled();
  84. });
  85. it('can not remove last 2fa method when org requires 2fa', async function () {
  86. Client.addMockResponse({
  87. url: ORG_ENDPOINT,
  88. body: TestStubs.Organizations({require2FA: true}),
  89. });
  90. Client.addMockResponse({
  91. url: ENDPOINT,
  92. body: [TestStubs.Authenticators().Totp()],
  93. });
  94. const deleteMock = Client.addMockResponse({
  95. url: `${ENDPOINT}15/`,
  96. method: 'DELETE',
  97. });
  98. wrapper = mountWithTheme(
  99. <AccountSecurityWrapper router={router} params={params}>
  100. <AccountSecurityDetails router={router} params={params} />
  101. </AccountSecurityWrapper>,
  102. routerContext
  103. );
  104. wrapper.find('RemoveConfirm Button').simulate('click');
  105. const modal = await mountGlobalModal();
  106. expect(modal.find('Modal[show=true]').exists()).toBe(false);
  107. expect(deleteMock).not.toHaveBeenCalled();
  108. });
  109. });
  110. describe('Recovery', function () {
  111. beforeEach(function () {
  112. params = {authId: 16};
  113. ({router, routerContext} = initializeOrg({
  114. router: {
  115. params,
  116. },
  117. }));
  118. Client.clearMockResponses();
  119. Client.addMockResponse({
  120. url: ENDPOINT,
  121. body: TestStubs.AllAuthenticators(),
  122. });
  123. Client.addMockResponse({
  124. url: ORG_ENDPOINT,
  125. body: TestStubs.Organizations(),
  126. });
  127. Client.addMockResponse({
  128. url: `${ENDPOINT}16/`,
  129. body: TestStubs.Authenticators().Recovery(),
  130. });
  131. Client.addMockResponse({
  132. url: ACCOUNT_EMAILS_ENDPOINT,
  133. body: TestStubs.AccountEmails(),
  134. });
  135. wrapper = mountWithTheme(
  136. <AccountSecurityWrapper router={router} params={params}>
  137. <AccountSecurityDetails router={router} params={params} />
  138. </AccountSecurityWrapper>,
  139. routerContext
  140. );
  141. });
  142. it('has enrolled circle indicator', function () {
  143. expect(wrapper.find('AuthenticatorStatus').prop('enabled')).toBe(true);
  144. });
  145. it('has created and last used dates', function () {
  146. expect(wrapper.find('AuthenticatorDate')).toHaveLength(2);
  147. });
  148. it('does not have remove button', function () {
  149. expect(wrapper.find('RemoveConfirm')).toHaveLength(0);
  150. });
  151. it('regenerates codes', function () {
  152. const deleteMock = Client.addMockResponse({
  153. url: `${ENDPOINT}16/`,
  154. method: 'PUT',
  155. });
  156. wrapper.find('RecoveryCodes').prop('onRegenerateBackupCodes')();
  157. expect(deleteMock).toHaveBeenCalled();
  158. });
  159. it('has copy, print and download buttons', function () {
  160. const codes = 'ABCD-1234 \nEFGH-5678';
  161. const downloadCodes = `Button[href="data:text/plain;charset=utf-8,${codes}"]`;
  162. expect(wrapper.find(downloadCodes)).toHaveLength(1);
  163. wrapper.find(downloadCodes).simulate('click');
  164. expect(wrapper.find('button[aria-label="print"]')).toHaveLength(1);
  165. expect(wrapper.find('iframe[name="printable"]')).toHaveLength(1);
  166. expect(wrapper.find(`Clipboard[value="${codes}"]`)).toHaveLength(1);
  167. });
  168. });
  169. });