import {OrganizationFixture} from 'sentry-fixture/organization';
import {initializeOrg} from 'sentry-test/initializeOrg';
import {render, screen, userEvent, waitFor} from 'sentry-test/reactTestingLibrary';
import ConfigStore from 'sentry/stores/configStore';
import App from 'sentry/views/app';
describe('Sudo Modal', function () {
const setHasPasswordAuth = hasPasswordAuth =>
ConfigStore.set('user', {...ConfigStore.get('user'), hasPasswordAuth});
beforeEach(function () {
window.__initialData = {
...window.__initialData,
links: {
organizationUrl: 'https://albertos-apples.sentry.io',
regionUrl: 'https://albertos-apples.sentry.io',
sentryUrl: 'https://sentry.io',
},
};
const organization = OrganizationFixture();
MockApiClient.clearMockResponses();
MockApiClient.addMockResponse({
url: '/assistant/',
body: [],
});
MockApiClient.addMockResponse({
url: '/organizations/',
body: [organization],
});
MockApiClient.addMockResponse({
url: '/organizations/org-slug/',
body: organization,
});
MockApiClient.addMockResponse({
url: '/organizations/org-slug/teams/',
body: [],
});
MockApiClient.addMockResponse({
url: '/organizations/org-slug/projects/',
body: [],
});
MockApiClient.addMockResponse({
url: '/organizations/org-slug/',
method: 'DELETE',
statusCode: 401,
body: {
detail: {
code: 'sudo-required',
username: 'test@test.com',
},
},
});
MockApiClient.addMockResponse({
url: '/authenticators/',
body: [],
});
});
it('can delete an org with sudo flow', async function () {
const {routerProps} = initializeOrg({router: {params: {}}});
setHasPasswordAuth(true);
const successCb = jest.fn();
const errorCb = jest.fn();
// Should return w/ `sudoRequired`
new MockApiClient().request('/organizations/org-slug/', {
method: 'DELETE',
success: successCb,
error: errorCb,
});
render(
placeholder content
);
// Should have Modal + input
expect(await screen.findByRole('dialog')).toBeInTheDocument();
// Original callbacks should not have been called
expect(successCb).not.toHaveBeenCalled();
expect(errorCb).not.toHaveBeenCalled();
// Clear mocks and allow DELETE
MockApiClient.clearMockResponses();
MockApiClient.addMockResponse({
url: '/authenticators/',
body: [],
});
const orgDeleteMock = MockApiClient.addMockResponse({
url: '/organizations/org-slug/',
method: 'DELETE',
statusCode: 200,
});
const sudoMock = MockApiClient.addMockResponse({
url: '/auth/',
method: 'PUT',
statusCode: 200,
});
expect(sudoMock).not.toHaveBeenCalled();
// "Sudo" auth
await userEvent.type(screen.getByRole('textbox', {name: 'Password'}), 'password');
await userEvent.click(screen.getByRole('button', {name: 'Confirm Password'}));
expect(sudoMock).toHaveBeenCalledWith(
'/auth/',
expect.objectContaining({
method: 'PUT',
data: {isSuperuserModal: false, password: 'password'},
})
);
// Retry API request
await waitFor(() => expect(successCb).toHaveBeenCalled());
expect(orgDeleteMock).toHaveBeenCalledWith(
'/organizations/org-slug/',
expect.objectContaining({
method: 'DELETE',
})
);
// Sudo Modal should be closed
await waitFor(() => expect(screen.queryByRole('dialog')).not.toBeInTheDocument());
});
it('shows button to redirect if user does not have password auth', async function () {
const {routerProps} = initializeOrg({router: {params: {}}});
setHasPasswordAuth(false);
// Should return w/ `sudoRequired` and trigger the modal to open
new MockApiClient().request('/organizations/org-slug/', {method: 'DELETE'});
render(
placeholder content
);
// Should have Modal + input
expect(await screen.findByRole('dialog')).toBeInTheDocument();
expect(screen.queryByLabelText('Password')).not.toBeInTheDocument();
expect(screen.getByRole('button', {name: 'Continue'})).toHaveAttribute(
'href',
'/auth/login/?next=http%3A%2F%2Flocalhost%2F'
);
});
});