import {mountWithTheme} from 'sentry-test/enzyme';
import {changeInputValue, selectByValue} from 'sentry-test/select-new';
import {Client} from 'sentry/api';
import SentryAppExternalIssueForm from 'sentry/components/group/sentryAppExternalIssueForm';
import {addQueryParamsToExistingUrl} from 'sentry/utils/queryString';
const optionLabelSelector = label => `[label="${label}"]`;
describe('SentryAppExternalIssueForm', () => {
let wrapper;
let group;
let sentryApp;
let sentryAppInstallation;
let component;
let submitUrl;
let externalIssueRequest;
beforeEach(() => {
group = TestStubs.Group({
title: 'ApiError: Broken',
shortId: 'SEN123',
permalink: 'https://sentry.io/organizations/sentry/issues/123/?project=1',
});
component = TestStubs.SentryAppComponent();
sentryApp = TestStubs.SentryApp();
sentryAppInstallation = TestStubs.SentryAppInstallation({sentryApp});
submitUrl = `/sentry-app-installations/${sentryAppInstallation.uuid}/external-issue-actions/`;
externalIssueRequest = Client.addMockResponse({
url: submitUrl,
method: 'POST',
body: {},
});
});
describe('create', () => {
beforeEach(() => {
wrapper = mountWithTheme(
);
});
it('renders each required_fields field', () => {
component.schema.create.required_fields.forEach(field => {
expect(wrapper.exists(`#${field.name}`)).toBe(true);
});
});
it('does not submit form if required fields are not set', () => {
wrapper.find('form').simulate('submit');
expect(externalIssueRequest).not.toHaveBeenCalled();
});
it('submits to the New External Issue endpoint', () => {
selectByValue(wrapper, 'number_1', {name: 'numbers', control: true});
wrapper.find('form').simulate('submit');
expect(externalIssueRequest).toHaveBeenCalledWith(
submitUrl,
expect.objectContaining({
data: {
action: 'create',
description:
'Sentry Issue: [SEN123](https://sentry.io/organizations/sentry/issues/123/?project=1&referrer=Sample%20App)',
groupId: '1',
numbers: 'number_1',
title: 'ApiError: Broken',
},
method: 'POST',
})
);
});
it('renders prepopulated defaults', () => {
const titleField = wrapper.find('Input#title');
const descriptionField = wrapper.find('TextArea#description');
const url = addQueryParamsToExistingUrl(group.permalink, {
referrer: sentryApp.name,
});
expect(titleField.prop('value')).toEqual(`${group.title}`);
expect(descriptionField.prop('value')).toEqual(
`Sentry Issue: [${group.shortId}](${url})`
);
});
});
describe('link', () => {
beforeEach(() => {
wrapper = mountWithTheme(
);
});
it('renders each required_fields field', () => {
component.schema.link.required_fields.forEach(field => {
expect(wrapper.exists(`#${field.name}`)).toBe(true);
});
});
it('submits to the New External Issue endpoint', () => {
wrapper
.find('input[name="issue"]')
.simulate('change', {target: {value: 'my issue'}});
wrapper.find('form').simulate('submit');
expect(externalIssueRequest).toHaveBeenCalledWith(
submitUrl,
expect.objectContaining({
data: {
action: 'link',
groupId: '1',
issue: 'my issue',
},
method: 'POST',
})
);
});
});
});
describe('SentryAppExternalIssueForm Async Field', () => {
let wrapper;
let group;
let sentryApp;
let sentryAppInstallation;
const component = TestStubs.SentryAppComponentAsync();
beforeEach(() => {
group = TestStubs.Group({
title: 'ApiError: Broken',
shortId: 'SEN123',
permalink: 'https://sentry.io/organizations/sentry/issues/123/?project=1',
});
sentryApp = TestStubs.SentryApp();
sentryAppInstallation = TestStubs.SentryAppInstallation({sentryApp});
});
afterEach(() => {
Client.clearMockResponses();
});
describe('renders', () => {
it('renders each required_fields field', async function () {
const mockGetOptions = Client.addMockResponse({
method: 'GET',
url: '/sentry-app-installations/d950595e-cba2-46f6-8a94-b79e42806f98/external-requests/',
body: {
choices: [
[1, 'Issue 1'],
[2, 'Issue 2'],
],
},
});
wrapper = mountWithTheme(
);
const thisInput = wrapper.find('input').at(0);
changeInputValue(thisInput, 'I');
await tick();
wrapper.update();
expect(mockGetOptions).toHaveBeenCalled();
expect(wrapper.find(optionLabelSelector('Issue 1')).exists()).toBe(true);
expect(wrapper.find(optionLabelSelector('Issue 2')).exists()).toBe(true);
});
});
});
describe('SentryAppExternalIssueForm Dependent fields', () => {
let wrapper;
let group;
let sentryApp;
let sentryAppInstallation;
const component = TestStubs.SentryAppComponentDependent();
beforeEach(() => {
group = TestStubs.Group({
title: 'ApiError: Broken',
shortId: 'SEN123',
permalink: 'https://sentry.io/organizations/sentry/issues/123/?project=1',
});
sentryApp = TestStubs.SentryApp();
sentryAppInstallation = TestStubs.SentryAppInstallation({sentryApp});
wrapper = mountWithTheme(
);
});
afterEach(() => {
Client.clearMockResponses();
});
describe('create', () => {
it('load options for field that has dependencies when the dependent option is selected', async () => {
const url = `/sentry-app-installations/${sentryAppInstallation.uuid}/external-requests/`;
Client.addMockResponse({
method: 'GET',
url,
body: {
choices: [
['A', 'project A'],
['B', 'project B'],
],
},
match: [MockApiClient.matchQuery({uri: '/integrations/sentry/projects'})],
});
const boardMock = Client.addMockResponse({
method: 'GET',
url,
body: {
choices: [
['R', 'board R'],
['S', 'board S'],
],
},
match: [
MockApiClient.matchQuery({
uri: '/integrations/sentry/boards',
dependentData: JSON.stringify({project_id: 'A'}),
}),
],
});
const projectInput = wrapper.find('[data-test-id="project_id"] input').at(0);
changeInputValue(projectInput, 'p');
await tick();
wrapper.update();
expect(wrapper.find(optionLabelSelector('project A')).exists()).toBe(true);
expect(wrapper.find(optionLabelSelector('project B')).exists()).toBe(true);
// project select should be disabled and we shouldn't fetch the options yet
expect(wrapper.find('SelectControl#board_id').prop('disabled')).toBe(true);
expect(boardMock).not.toHaveBeenCalled();
// when we set the value for project we should get the values for the board
selectByValue(wrapper, 'A', {name: 'project_id'});
await tick();
wrapper.update();
expect(boardMock).toHaveBeenCalled();
expect(wrapper.find('SelectControl#board_id').prop('disabled')).toBe(false);
const boardInput = wrapper.find('[data-test-id="board_id"] input').at(0);
changeInputValue(boardInput, 'b');
await tick();
wrapper.update();
expect(wrapper.find(optionLabelSelector('board R')).exists()).toBe(true);
expect(wrapper.find(optionLabelSelector('board S')).exists()).toBe(true);
});
});
});