import {OrganizationFixture} from 'sentry-fixture/organization';
import {SentryAppFixture} from 'sentry-fixture/sentryApp';
import {initializeOrg} from 'sentry-test/initializeOrg';
import {
render,
renderGlobalModal,
screen,
userEvent,
waitFor,
within,
} from 'sentry-test/reactTestingLibrary';
import OrganizationDeveloperSettings from 'sentry/views/settings/organizationDeveloperSettings/index';
describe('Organization Developer Settings', function () {
const {organization: org, routerProps, router} = initializeOrg();
const sentryApp = SentryAppFixture({
scopes: [
'team:read',
'project:releases',
'event:read',
'event:write',
'org:read',
'org:write',
],
});
beforeEach(() => {
MockApiClient.clearMockResponses();
});
describe('when no Apps exist', () => {
it('displays empty state', async () => {
MockApiClient.addMockResponse({
url: `/organizations/${org.slug}/sentry-apps/`,
body: [],
});
render();
await waitFor(() => {
expect(
screen.getByText('No internal integrations have been created yet.')
).toBeInTheDocument();
});
});
});
describe('with unpublished apps', () => {
beforeEach(() => {
MockApiClient.addMockResponse({
url: `/organizations/${org.slug}/sentry-apps/`,
body: [sentryApp],
});
});
it('internal integrations list is empty', () => {
render(, {
organization: org,
});
expect(
screen.getByText('No internal integrations have been created yet.')
).toBeInTheDocument();
});
it('public integrations list contains 1 item', () => {
render(
,
{organization: org}
);
expect(screen.getByText('Sample App')).toBeInTheDocument();
expect(screen.getByText('unpublished')).toBeInTheDocument();
});
it('allows for deletion', async () => {
MockApiClient.addMockResponse({
url: `/sentry-apps/${sentryApp.slug}/`,
method: 'DELETE',
body: [],
});
render(
);
const deleteButton = await screen.findByRole('button', {name: 'Delete'});
expect(deleteButton).toHaveAttribute('aria-disabled', 'false');
await userEvent.click(deleteButton);
renderGlobalModal();
const dialog = await screen.findByRole('dialog');
expect(dialog).toBeInTheDocument();
const input = await within(dialog).findByPlaceholderText('sample-app');
await userEvent.type(input, 'sample-app');
const confirmDeleteButton = await screen.findByRole('button', {name: 'Confirm'});
await userEvent.click(confirmDeleteButton);
await screen.findByText('No public integrations have been created yet.');
});
it('can make a request to publish an integration', async () => {
const mock = MockApiClient.addMockResponse({
url: `/sentry-apps/${sentryApp.slug}/publish-request/`,
method: 'POST',
});
render(
);
const publishButton = await screen.findByRole('button', {name: 'Publish'});
expect(publishButton).toHaveAttribute('aria-disabled', 'false');
await userEvent.click(publishButton);
renderGlobalModal();
const dialog = await screen.findByRole('dialog');
expect(dialog).toBeInTheDocument();
const questionnaire = [
{
answer: 'Answer 0',
question: 'What does your integration do? Please be as detailed as possible.',
},
{answer: 'Answer 1', question: 'What value does it offer customers?'},
{
answer: 'Answer 2',
question: 'Do you operate the web service your integration communicates with?',
},
{
answer: 'Answer 3',
question:
'Please justify why you are requesting each of the following permissions: Team Read, Release Admin, Event Write, Organization Write.',
},
];
for (const {question, answer} of questionnaire) {
const element = within(dialog).getByRole('textbox', {name: question});
await userEvent.type(element, answer);
}
const requestPublishButton =
await within(dialog).findByLabelText('Request Publication');
expect(requestPublishButton).toHaveAttribute('aria-disabled', 'false');
await userEvent.click(requestPublishButton);
expect(mock).toHaveBeenCalledWith(
`/sentry-apps/${sentryApp.slug}/publish-request/`,
expect.objectContaining({
data: {questionnaire},
})
);
});
});
describe('with published apps', () => {
beforeEach(() => {
const publishedSentryApp = SentryAppFixture({status: 'published'});
MockApiClient.addMockResponse({
url: `/organizations/${org.slug}/sentry-apps/`,
body: [publishedSentryApp],
});
});
it('shows the published status', () => {
render(
);
expect(screen.getByText('published')).toBeInTheDocument();
});
it('trash button is disabled', async () => {
render(
);
const deleteButton = await screen.findByRole('button', {name: 'Delete'});
expect(deleteButton).toHaveAttribute('aria-disabled', 'true');
});
it('publish button is disabled', async () => {
render(
);
const publishButton = await screen.findByRole('button', {name: 'Publish'});
expect(publishButton).toHaveAttribute('aria-disabled', 'true');
});
});
describe('with Internal Integrations', () => {
beforeEach(() => {
const internalIntegration = SentryAppFixture({status: 'internal'});
MockApiClient.addMockResponse({
url: `/organizations/${org.slug}/sentry-apps/`,
body: [internalIntegration],
});
});
it('allows deleting', async () => {
render();
const deleteButton = await screen.findByRole('button', {name: 'Delete'});
expect(deleteButton).toHaveAttribute('aria-disabled', 'false');
});
it('publish button does not exist', () => {
render();
expect(screen.queryByText('Publish')).not.toBeInTheDocument();
});
});
describe('without Owner permissions', () => {
const newOrg = OrganizationFixture({access: ['org:read']});
beforeEach(() => {
MockApiClient.addMockResponse({
url: `/organizations/${newOrg.slug}/sentry-apps/`,
body: [sentryApp],
});
});
it('trash button is disabled', async () => {
render(
,
{organization: newOrg}
);
const deleteButton = await screen.findByRole('button', {name: 'Delete'});
expect(deleteButton).toHaveAttribute('aria-disabled', 'true');
});
it('publish button is disabled', async () => {
render(
,
{organization: newOrg}
);
const publishButton = await screen.findByRole('button', {name: 'Publish'});
expect(publishButton).toHaveAttribute('aria-disabled', 'true');
});
});
});