import {ProjectFixture} from 'sentry-fixture/project'; import {initializeOrg} from 'sentry-test/initializeOrg'; import { render, renderGlobalModal, screen, userEvent, } from 'sentry-test/reactTestingLibrary'; import {textWithMarkupMatcher} from 'sentry-test/utils'; import OrganizationsStore from 'sentry/stores/organizationsStore'; import type {OrgAuthToken} from 'sentry/types'; import {OrganizationAuthTokensAuthTokenRow} from 'sentry/views/settings/organizationAuthTokens/authTokenRow'; describe('OrganizationAuthTokensAuthTokenRow', function () { const {organization, router} = initializeOrg(); const revokeToken = jest.fn(); const token: OrgAuthToken = { id: '1', name: 'My Token', tokenLastCharacters: 'XYZ1', dateCreated: new Date('2023-01-01T00:00:00.000Z'), scopes: ['org:read'], }; const defaultProps = { organization, isRevoking: false, token, revokeToken, projectLastUsed: undefined, router, location: router.location, params: {orgId: organization.slug}, routes: router.routes, route: {}, routeParams: router.params, }; beforeEach(function () { OrganizationsStore.addOrReplace(organization); }); afterEach(function () { MockApiClient.clearMockResponses(); }); it('shows token without last used information', function () { render(); expect(screen.getByLabelText('Token preview')).toHaveTextContent( 'sntrys_************XYZ1' ); expect(screen.getByText('never used')).toBeInTheDocument(); expect(screen.getByText('My Token')).toBeInTheDocument(); }); describe('last used info', function () { it('shows full last used info', function () { const props = { ...defaultProps, projectLastUsed: ProjectFixture(), token: { ...token, dateLastUsed: new Date(), }, }; render(); expect(screen.getByLabelText('Token preview')).toHaveTextContent( 'sntrys_************XYZ1' ); expect( screen.getByText( textWithMarkupMatcher('a few seconds ago in project Project Name') ) ).toBeInTheDocument(); expect(screen.getByText('My Token')).toBeInTheDocument(); }); it('shows last used project only', function () { const props = { ...defaultProps, projectLastUsed: ProjectFixture(), token: { ...token, }, }; render(); expect(screen.getByLabelText('Token preview')).toHaveTextContent( 'sntrys_************XYZ1' ); expect( screen.getByText(textWithMarkupMatcher('in project Project Name')) ).toBeInTheDocument(); expect(screen.getByText('My Token')).toBeInTheDocument(); }); it('shows last used date only', function () { const props = { ...defaultProps, token: { ...token, dateLastUsed: new Date(), }, }; render(); expect(screen.getByLabelText('Token preview')).toHaveTextContent( 'sntrys_************XYZ1' ); expect( screen.getByText(textWithMarkupMatcher('a few seconds ago')) ).toBeInTheDocument(); expect(screen.getByText('My Token')).toBeInTheDocument(); }); }); describe('revoking', function () { it('does not allow to revoke without access', function () { const props = { ...defaultProps, revokeToken: undefined, }; render(); expect(screen.getByRole('button', {name: 'Revoke My Token'})).toBeDisabled(); }); it('allows to revoke', async function () { render(); renderGlobalModal(); expect(screen.getByRole('button', {name: 'Revoke My Token'})).toBeEnabled(); await userEvent.click(screen.getByRole('button', {name: 'Revoke My Token'})); // Confirm modal await userEvent.click(screen.getByRole('button', {name: 'Confirm'})); expect(revokeToken).toHaveBeenCalledWith(token); }); it('does not allow to revoke while revoking in progress', function () { const props = { ...defaultProps, isRevoking: true, }; render(); expect(screen.getByRole('button', {name: 'Revoke My Token'})).toBeDisabled(); }); }); });