accountSecurityEnroll.spec.tsx 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171
  1. import {AuthenticatorsFixture} from 'sentry-fixture/authenticators';
  2. import {OrganizationFixture} from 'sentry-fixture/organization';
  3. import {RouterFixture} from 'sentry-fixture/routerFixture';
  4. import {render, screen, userEvent} from 'sentry-test/reactTestingLibrary';
  5. import OrganizationsStore from 'sentry/stores/organizationsStore';
  6. import AccountSecurityEnroll from 'sentry/views/settings/account/accountSecurity/accountSecurityEnroll';
  7. const ENDPOINT = '/users/me/authenticators/';
  8. const usorg = OrganizationFixture({
  9. slug: 'us-org',
  10. links: {
  11. organizationUrl: 'https://us-org.example.test',
  12. regionUrl: 'https://us.example.test',
  13. },
  14. });
  15. describe('AccountSecurityEnroll', function () {
  16. jest.spyOn(window.location, 'assign').mockImplementation(() => {});
  17. describe('Totp', function () {
  18. const authenticator = AuthenticatorsFixture().Totp({
  19. isEnrolled: false,
  20. qrcode: 'otpauth://totp/test%40sentry.io?issuer=Sentry&secret=secret',
  21. secret: 'secret',
  22. form: [
  23. {
  24. type: 'string',
  25. name: 'otp',
  26. label: 'OTP Code',
  27. },
  28. ],
  29. });
  30. const router = RouterFixture({
  31. params: {authId: authenticator.authId},
  32. });
  33. let location;
  34. beforeEach(function () {
  35. location = window.location;
  36. window.location = location;
  37. window.location.href = 'https://example.test';
  38. window.__initialData = {
  39. ...window.__initialData,
  40. links: {
  41. organizationUrl: undefined,
  42. regionUrl: undefined,
  43. sentryUrl: 'https://example.test',
  44. },
  45. };
  46. OrganizationsStore.load([usorg]);
  47. MockApiClient.clearMockResponses();
  48. MockApiClient.addMockResponse({
  49. url: `${ENDPOINT}${authenticator.authId}/enroll/`,
  50. body: authenticator,
  51. });
  52. });
  53. it('does not have enrolled circle indicator', function () {
  54. render(<AccountSecurityEnroll />, {router});
  55. expect(
  56. screen.getByRole('status', {name: 'Authentication Method Inactive'})
  57. ).toBeInTheDocument();
  58. });
  59. it('has qrcode component', function () {
  60. render(<AccountSecurityEnroll />, {router});
  61. expect(screen.getByLabelText('Enrollment QR Code')).toBeInTheDocument();
  62. });
  63. it('can enroll from org subdomain', async function () {
  64. window.location.href = 'https://us-org.example.test';
  65. window.__initialData = {
  66. ...window.__initialData,
  67. links: {
  68. organizationUrl: 'https://us-org.example.test',
  69. regionUrl: 'https://us.example.test',
  70. sentryUrl: 'https://example.test',
  71. },
  72. };
  73. const enrollMock = MockApiClient.addMockResponse({
  74. url: `${ENDPOINT}${authenticator.authId}/enroll/`,
  75. method: 'POST',
  76. });
  77. const fetchOrgsMock = MockApiClient.addMockResponse({
  78. url: `/organizations/`,
  79. body: [usorg],
  80. });
  81. render(<AccountSecurityEnroll />, {router});
  82. await userEvent.type(screen.getByRole('textbox', {name: 'OTP Code'}), 'otp{enter}');
  83. expect(enrollMock).toHaveBeenCalledWith(
  84. `${ENDPOINT}15/enroll/`,
  85. expect.objectContaining({
  86. method: 'POST',
  87. data: expect.objectContaining({
  88. secret: 'secret',
  89. otp: 'otp',
  90. }),
  91. })
  92. );
  93. expect(fetchOrgsMock).not.toHaveBeenCalled();
  94. expect(window.location.assign).not.toHaveBeenCalled();
  95. });
  96. it('can enroll from main domain', async function () {
  97. OrganizationsStore.load([]);
  98. window.__initialData = {
  99. ...window.__initialData,
  100. links: {
  101. organizationUrl: 'https://us-org.example.test',
  102. regionUrl: 'https://us.example.test',
  103. sentryUrl: 'https://example.test',
  104. },
  105. };
  106. const enrollMock = MockApiClient.addMockResponse({
  107. url: `${ENDPOINT}${authenticator.authId}/enroll/`,
  108. method: 'POST',
  109. });
  110. const fetchOrgsMock = MockApiClient.addMockResponse({
  111. url: `/organizations/`,
  112. body: [usorg],
  113. });
  114. render(<AccountSecurityEnroll />, {router});
  115. await userEvent.type(screen.getByRole('textbox', {name: 'OTP Code'}), 'otp{enter}');
  116. expect(enrollMock).toHaveBeenCalledWith(
  117. `${ENDPOINT}15/enroll/`,
  118. expect.objectContaining({
  119. method: 'POST',
  120. data: expect.objectContaining({
  121. secret: 'secret',
  122. otp: 'otp',
  123. }),
  124. })
  125. );
  126. expect(fetchOrgsMock).toHaveBeenCalledTimes(1);
  127. expect(window.location.assign).toHaveBeenCalledTimes(1);
  128. expect(window.location.assign).toHaveBeenCalledWith('http://us-org.example.test/');
  129. });
  130. it('can redirect with already enrolled error', function () {
  131. MockApiClient.addMockResponse({
  132. url: `${ENDPOINT}${authenticator.authId}/enroll/`,
  133. body: {details: 'Already enrolled'},
  134. statusCode: 400,
  135. });
  136. const pushMock = jest.fn();
  137. const routerWithMock = RouterFixture({
  138. push: pushMock,
  139. params: {authId: authenticator.authId},
  140. });
  141. render(<AccountSecurityEnroll />, {router: routerWithMock});
  142. expect(pushMock).toHaveBeenCalledWith('/settings/account/security/');
  143. });
  144. });
  145. });