accountSecurityEnroll.spec.tsx 5.5 KB

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