authTokenRow.spec.tsx 4.5 KB

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