accountSecurityEnroll.spec.tsx 5.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  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.href = 'https://example.test';
  43. window.__initialData = {
  44. ...window.__initialData,
  45. links: {
  46. organizationUrl: undefined,
  47. regionUrl: undefined,
  48. sentryUrl: 'https://example.test',
  49. },
  50. };
  51. OrganizationsStore.load([usorg]);
  52. MockApiClient.clearMockResponses();
  53. MockApiClient.addMockResponse({
  54. url: `${ENDPOINT}${authenticator.authId}/enroll/`,
  55. body: authenticator,
  56. });
  57. });
  58. beforeEach(function () {
  59. window.location = location;
  60. });
  61. it('does not have enrolled circle indicator', function () {
  62. render(<AccountSecurityEnroll />, {context: routerContext});
  63. expect(
  64. screen.getByRole('status', {name: 'Authentication Method Inactive'})
  65. ).toBeInTheDocument();
  66. });
  67. it('has qrcode component', function () {
  68. render(<AccountSecurityEnroll />, {context: routerContext});
  69. expect(screen.getByLabelText('Enrollment QR Code')).toBeInTheDocument();
  70. });
  71. it('can enroll from org subdomain', async function () {
  72. window.location.href = 'https://us-org.example.test';
  73. window.__initialData = {
  74. ...window.__initialData,
  75. links: {
  76. organizationUrl: 'https://us-org.example.test',
  77. regionUrl: 'https://us.example.test',
  78. sentryUrl: 'https://example.test',
  79. },
  80. };
  81. const enrollMock = MockApiClient.addMockResponse({
  82. url: `${ENDPOINT}${authenticator.authId}/enroll/`,
  83. method: 'POST',
  84. });
  85. const fetchOrgsMock = MockApiClient.addMockResponse({
  86. url: `/organizations/`,
  87. body: [usorg],
  88. });
  89. render(<AccountSecurityEnroll />, {context: routerContext});
  90. await userEvent.type(screen.getByRole('textbox', {name: 'OTP Code'}), 'otp{enter}');
  91. expect(enrollMock).toHaveBeenCalledWith(
  92. `${ENDPOINT}15/enroll/`,
  93. expect.objectContaining({
  94. method: 'POST',
  95. data: expect.objectContaining({
  96. secret: 'secret',
  97. otp: 'otp',
  98. }),
  99. })
  100. );
  101. expect(fetchOrgsMock).not.toHaveBeenCalled();
  102. expect(window.location.assign).not.toHaveBeenCalled();
  103. });
  104. it('can enroll from main domain', async function () {
  105. OrganizationsStore.load([]);
  106. window.__initialData = {
  107. ...window.__initialData,
  108. links: {
  109. organizationUrl: 'https://us-org.example.test',
  110. regionUrl: 'https://us.example.test',
  111. sentryUrl: 'https://example.test',
  112. },
  113. };
  114. const enrollMock = MockApiClient.addMockResponse({
  115. url: `${ENDPOINT}${authenticator.authId}/enroll/`,
  116. method: 'POST',
  117. });
  118. const fetchOrgsMock = MockApiClient.addMockResponse({
  119. url: `/organizations/`,
  120. body: [usorg],
  121. });
  122. render(<AccountSecurityEnroll />, {context: routerContext});
  123. await userEvent.type(screen.getByRole('textbox', {name: 'OTP Code'}), 'otp{enter}');
  124. expect(enrollMock).toHaveBeenCalledWith(
  125. `${ENDPOINT}15/enroll/`,
  126. expect.objectContaining({
  127. method: 'POST',
  128. data: expect.objectContaining({
  129. secret: 'secret',
  130. otp: 'otp',
  131. }),
  132. })
  133. );
  134. expect(fetchOrgsMock).toHaveBeenCalledTimes(1);
  135. expect(window.location.assign).toHaveBeenCalledTimes(1);
  136. expect(window.location.assign).toHaveBeenCalledWith('http://us-org.example.test/');
  137. });
  138. it('can redirect with already enrolled error', function () {
  139. MockApiClient.addMockResponse({
  140. url: `${ENDPOINT}${authenticator.authId}/enroll/`,
  141. body: {details: 'Already enrolled'},
  142. statusCode: 400,
  143. });
  144. const pushMock = jest.fn();
  145. const routerContextWithMock = RouterContextFixture([
  146. {
  147. router: {
  148. ...RouterFixture({push: pushMock}),
  149. params: {authId: authenticator.authId},
  150. },
  151. },
  152. ]);
  153. render(<AccountSecurityEnroll />, {context: routerContextWithMock});
  154. expect(pushMock).toHaveBeenCalledWith('/settings/account/security/');
  155. });
  156. });
  157. });