import {AccountEmailsFixture} from 'sentry-fixture/accountEmails';
import {
AllAuthenticatorsFixture,
AuthenticatorsFixture,
} from 'sentry-fixture/authenticators';
import {OrganizationsFixture} from 'sentry-fixture/organizations';
import {initializeOrg} from 'sentry-test/initializeOrg';
import {
render,
renderGlobalModal,
screen,
userEvent,
} from 'sentry-test/reactTestingLibrary';
import AccountSecurityDetails from 'sentry/views/settings/account/accountSecurity/accountSecurityDetails';
import AccountSecurityWrapper from 'sentry/views/settings/account/accountSecurity/accountSecurityWrapper';
const ENDPOINT = '/users/me/authenticators/';
const ACCOUNT_EMAILS_ENDPOINT = '/users/me/emails/';
const ORG_ENDPOINT = '/organizations/';
describe('AccountSecurityDetails', function () {
beforeEach(() => {
MockApiClient.clearMockResponses();
});
describe('Totp', function () {
beforeEach(function () {
MockApiClient.addMockResponse({
url: ENDPOINT,
body: AllAuthenticatorsFixture(),
});
MockApiClient.addMockResponse({
url: ORG_ENDPOINT,
body: OrganizationsFixture(),
});
MockApiClient.addMockResponse({
url: `${ENDPOINT}15/`,
body: AuthenticatorsFixture().Totp(),
});
MockApiClient.addMockResponse({
url: ACCOUNT_EMAILS_ENDPOINT,
body: AccountEmailsFixture(),
});
});
it('has enrolled circle indicator', async function () {
const params = {
authId: '15',
};
const {routerProps, routerContext} = initializeOrg({
router: {
params,
},
});
render(
,
{context: routerContext}
);
expect(await screen.findByTestId('auth-status-enabled')).toBeInTheDocument();
// has created and last used dates
expect(screen.getByText('Created at')).toBeInTheDocument();
expect(screen.getByText('Last used')).toBeInTheDocument();
});
it('can remove method', async function () {
const deleteMock = MockApiClient.addMockResponse({
url: `${ENDPOINT}15/`,
method: 'DELETE',
});
const params = {
authId: '15',
};
const {routerProps, routerContext} = initializeOrg({
router: {
params,
},
});
render(
,
{context: routerContext}
);
await userEvent.click(await screen.findByRole('button', {name: 'Remove'}));
renderGlobalModal();
await userEvent.click(await screen.findByRole('button', {name: 'Confirm'}));
expect(deleteMock).toHaveBeenCalled();
});
it('can remove one of multiple 2fa methods when org requires 2fa', async function () {
MockApiClient.addMockResponse({
url: ORG_ENDPOINT,
body: OrganizationsFixture({require2FA: true}),
});
const deleteMock = MockApiClient.addMockResponse({
url: `${ENDPOINT}15/`,
method: 'DELETE',
});
const params = {
authId: '15',
};
const {routerProps, routerContext} = initializeOrg({
router: {
params,
},
});
render(
,
{context: routerContext}
);
await userEvent.click(await screen.findByRole('button', {name: 'Remove'}));
renderGlobalModal();
await userEvent.click(await screen.findByRole('button', {name: 'Confirm'}));
expect(deleteMock).toHaveBeenCalled();
});
it('can not remove last 2fa method when org requires 2fa', async function () {
MockApiClient.addMockResponse({
url: ORG_ENDPOINT,
body: OrganizationsFixture({require2FA: true}),
});
MockApiClient.addMockResponse({
url: ENDPOINT,
body: [AuthenticatorsFixture().Totp()],
});
const params = {
authId: '15',
};
const {routerContext, routerProps} = initializeOrg({
router: {
params,
},
});
render(
,
{context: routerContext}
);
expect(await screen.findByRole('button', {name: 'Remove'})).toBeDisabled();
});
});
describe('Recovery', function () {
beforeEach(function () {
MockApiClient.addMockResponse({
url: ENDPOINT,
body: AllAuthenticatorsFixture(),
});
MockApiClient.addMockResponse({
url: ORG_ENDPOINT,
body: OrganizationsFixture(),
});
MockApiClient.addMockResponse({
url: `${ENDPOINT}16/`,
body: AuthenticatorsFixture().Recovery(),
});
MockApiClient.addMockResponse({
url: ACCOUNT_EMAILS_ENDPOINT,
body: AccountEmailsFixture(),
});
});
it('has enrolled circle indicator', async function () {
const params = {
authId: '16',
};
const {routerProps, routerContext} = initializeOrg({
router: {
params,
},
});
render(
,
{context: routerContext}
);
expect(await screen.findByTestId('auth-status-enabled')).toBeInTheDocument();
// does not have remove button
expect(screen.queryByRole('button', {name: 'Remove'})).not.toBeInTheDocument();
});
it('regenerates codes', async function () {
const deleteMock = MockApiClient.addMockResponse({
url: `${ENDPOINT}16/`,
method: 'PUT',
});
const params = {
authId: '16',
};
const {routerProps, routerContext} = initializeOrg({
router: {
params,
},
});
render(
,
{context: routerContext}
);
await userEvent.click(
await screen.findByRole('button', {name: 'Regenerate Codes'})
);
renderGlobalModal();
expect(
await screen.findByText(
'Are you sure you want to regenerate recovery codes? Your old codes will no longer work.'
)
).toBeInTheDocument();
await userEvent.click(screen.getByRole('button', {name: 'Confirm'}));
expect(deleteMock).toHaveBeenCalled();
});
it('has copy, print and download buttons', async function () {
const params = {
authId: '16',
};
const {routerProps, routerContext} = initializeOrg({
router: {
params,
},
});
Object.defineProperty(document, 'queryCommandSupported', {
value: () => true,
});
render(
,
{context: routerContext}
);
expect(await screen.findByRole('button', {name: 'print'})).toBeInTheDocument();
expect(screen.getByRole('button', {name: 'download'})).toHaveAttribute(
'href',
'data:text/plain;charset=utf-8,ABCD-1234 \nEFGH-5678'
);
expect(screen.getByTestId('frame')).toBeInTheDocument();
expect(screen.getByRole('button', {name: 'Copy'})).toBeInTheDocument();
});
});
});