authTokenRow.spec.tsx 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. import {ProjectFixture} from 'sentry-fixture/project';
  2. import {initializeOrg} from 'sentry-test/initializeOrg';
  3. import {
  4. render,
  5. renderGlobalModal,
  6. screen,
  7. userEvent,
  8. } from 'sentry-test/reactTestingLibrary';
  9. import {textWithMarkupMatcher} from 'sentry-test/utils';
  10. import OrganizationsStore from 'sentry/stores/organizationsStore';
  11. import type {OrgAuthToken} from 'sentry/types';
  12. import {OrganizationAuthTokensAuthTokenRow} from 'sentry/views/settings/organizationAuthTokens/authTokenRow';
  13. describe('OrganizationAuthTokensAuthTokenRow', function () {
  14. const {organization, router} = initializeOrg();
  15. const revokeToken = jest.fn();
  16. const token: OrgAuthToken = {
  17. id: '1',
  18. name: 'My Token',
  19. tokenLastCharacters: 'XYZ1',
  20. dateCreated: new Date('2023-01-01T00:00:00.000Z'),
  21. scopes: ['org:read'],
  22. };
  23. const defaultProps = {
  24. organization,
  25. isRevoking: false,
  26. token,
  27. revokeToken,
  28. projectLastUsed: undefined,
  29. router,
  30. location: router.location,
  31. params: {orgId: organization.slug},
  32. routes: router.routes,
  33. route: {},
  34. routeParams: router.params,
  35. };
  36. beforeEach(function () {
  37. OrganizationsStore.addOrReplace(organization);
  38. });
  39. afterEach(function () {
  40. MockApiClient.clearMockResponses();
  41. });
  42. it('shows token without last used information', function () {
  43. render(<OrganizationAuthTokensAuthTokenRow {...defaultProps} />);
  44. expect(screen.getByLabelText('Token preview')).toHaveTextContent(
  45. 'sntrys_************XYZ1'
  46. );
  47. expect(screen.getByText('never used')).toBeInTheDocument();
  48. expect(screen.getByText('My Token')).toBeInTheDocument();
  49. });
  50. describe('last used info', function () {
  51. it('shows full last used info', function () {
  52. const props = {
  53. ...defaultProps,
  54. projectLastUsed: ProjectFixture(),
  55. token: {
  56. ...token,
  57. dateLastUsed: new Date(),
  58. },
  59. };
  60. render(<OrganizationAuthTokensAuthTokenRow {...props} />);
  61. expect(screen.getByLabelText('Token preview')).toHaveTextContent(
  62. 'sntrys_************XYZ1'
  63. );
  64. expect(
  65. screen.getByText(
  66. textWithMarkupMatcher('a few seconds ago in project Project Name')
  67. )
  68. ).toBeInTheDocument();
  69. expect(screen.getByText('My Token')).toBeInTheDocument();
  70. });
  71. it('shows last used project only', function () {
  72. const props = {
  73. ...defaultProps,
  74. projectLastUsed: ProjectFixture(),
  75. token: {
  76. ...token,
  77. },
  78. };
  79. render(<OrganizationAuthTokensAuthTokenRow {...props} />);
  80. expect(screen.getByLabelText('Token preview')).toHaveTextContent(
  81. 'sntrys_************XYZ1'
  82. );
  83. expect(
  84. screen.getByText(textWithMarkupMatcher('in project Project Name'))
  85. ).toBeInTheDocument();
  86. expect(screen.getByText('My Token')).toBeInTheDocument();
  87. });
  88. it('shows last used date only', function () {
  89. const props = {
  90. ...defaultProps,
  91. token: {
  92. ...token,
  93. dateLastUsed: new Date(),
  94. },
  95. };
  96. render(<OrganizationAuthTokensAuthTokenRow {...props} />);
  97. expect(screen.getByLabelText('Token preview')).toHaveTextContent(
  98. 'sntrys_************XYZ1'
  99. );
  100. expect(
  101. screen.getByText(textWithMarkupMatcher('a few seconds ago'))
  102. ).toBeInTheDocument();
  103. expect(screen.getByText('My Token')).toBeInTheDocument();
  104. });
  105. });
  106. describe('revoking', function () {
  107. it('does not allow to revoke without access', function () {
  108. const props = {
  109. ...defaultProps,
  110. revokeToken: undefined,
  111. };
  112. render(<OrganizationAuthTokensAuthTokenRow {...props} />);
  113. expect(screen.getByRole('button', {name: 'Revoke My Token'})).toBeDisabled();
  114. });
  115. it('allows to revoke', async function () {
  116. render(<OrganizationAuthTokensAuthTokenRow {...defaultProps} />);
  117. renderGlobalModal();
  118. expect(screen.getByRole('button', {name: 'Revoke My Token'})).toBeEnabled();
  119. await userEvent.click(screen.getByRole('button', {name: 'Revoke My Token'}));
  120. // Confirm modal
  121. await userEvent.click(screen.getByRole('button', {name: 'Confirm'}));
  122. expect(revokeToken).toHaveBeenCalledWith(token);
  123. });
  124. it('does not allow to revoke while revoking in progress', function () {
  125. const props = {
  126. ...defaultProps,
  127. isRevoking: true,
  128. };
  129. render(<OrganizationAuthTokensAuthTokenRow {...props} />);
  130. expect(screen.getByRole('button', {name: 'Revoke My Token'})).toBeDisabled();
  131. });
  132. });
  133. });