123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199 |
- import {mountWithTheme} from 'sentry-test/enzyme';
- import ExternalIssueForm from 'sentry/components/group/externalIssueForm';
- jest.mock('lodash/debounce', () => {
- const debounceMap = new Map();
- const mockDebounce =
- (fn, timeout) =>
- (...args) => {
- if (debounceMap.has(fn)) {
- clearTimeout(debounceMap.get(fn));
- }
- debounceMap.set(
- fn,
- setTimeout(() => {
- fn.apply(fn, args);
- debounceMap.delete(fn);
- }, timeout)
- );
- };
- return mockDebounce;
- });
- describe('ExternalIssueForm', () => {
- let group, integration, onChange, wrapper, formConfig;
- beforeEach(() => {
- MockApiClient.clearMockResponses();
- group = TestStubs.Group();
- integration = TestStubs.GitHubIntegration({externalIssues: []});
- onChange = jest.fn();
- });
- afterEach(() => {
- jest.useRealTimers();
- });
- const generateWrapper = (action = 'create') => {
- MockApiClient.addMockResponse({
- url: `/groups/${group.id}/integrations/${integration.id}/`,
- body: formConfig,
- match: [MockApiClient.matchQuery({action: 'create'})],
- });
- const component = mountWithTheme(
- <ExternalIssueForm
- Body={p => p.children}
- Header={p => p.children}
- group={group}
- integration={integration}
- onChange={onChange}
- />
- );
- component.instance().handleClick(action);
- return component;
- };
- describe('create', () => {
- // TODO: expand tests
- beforeEach(() => {
- formConfig = {
- createIssueConfig: [],
- };
- MockApiClient.addMockResponse({
- url: `/groups/${group.id}/integrations/${integration.id}/`,
- body: formConfig,
- });
- });
- it('renders', () => {
- wrapper = generateWrapper();
- expect(wrapper).toSnapshot();
- });
- });
- describe('link', () => {
- let externalIssueField, getFormConfigRequest;
- beforeEach(() => {
- externalIssueField = {
- name: 'externalIssue',
- default: '',
- required: true,
- choices: [],
- url: '/search',
- label: 'Issue',
- type: 'select',
- };
- formConfig = {
- status: 'active',
- name: 'scefali',
- domainName: 'github.com/scefali',
- linkIssueConfig: [
- {
- url: '/search',
- required: true,
- name: 'repo',
- default: 'scefali/test',
- updatesForm: true,
- choices: [
- ['scefali/test', 'test'],
- ['scefali/ZeldaBazaar', 'ZeldaBazaar'],
- ],
- type: 'select',
- label: 'GitHub Repository',
- },
- externalIssueField,
- {
- help: "Leave blank if you don't want to add a comment to the GitHub issue.",
- default: 'Default Value',
- required: false,
- label: 'Comment',
- type: 'textarea',
- name: 'comment',
- },
- ],
- accountType: 'User',
- provider: {
- canAdd: true,
- aspects: {
- disable_dialog: {
- body: 'Before deleting this integration, you must uninstall this integration from GitHub. After uninstalling, your integration will be disabled at which point you can choose to delete this integration.',
- actionText: 'Visit GitHub',
- },
- removal_dialog: {
- body: 'Deleting this integration will delete all associated repositories and commit data. This action cannot be undone. Are you sure you want to delete your integration?',
- actionText: 'Delete',
- },
- },
- features: ['commits', 'issue-basic'],
- canDisable: true,
- key: 'github',
- name: 'GitHub',
- },
- id: '5',
- };
- getFormConfigRequest = MockApiClient.addMockResponse({
- url: `/groups/${group.id}/integrations/${integration.id}/`,
- body: formConfig,
- match: [MockApiClient.matchQuery({action: 'link'})],
- });
- });
- it('renders', () => {
- wrapper = generateWrapper('link');
- expect(wrapper).toSnapshot();
- });
- it('load options', async () => {
- wrapper = generateWrapper('link');
- await tick();
- wrapper.update();
- expect(getFormConfigRequest).toHaveBeenCalled();
- });
- describe('options loaded', () => {
- let mockSuccessResponse;
- beforeEach(async () => {
- mockSuccessResponse = [42, 56];
- const mockFetchPromise = () =>
- new Promise(resolve => {
- setTimeout(() => {
- resolve({
- json: () => Promise.resolve(mockSuccessResponse),
- ok: true,
- });
- }, 50);
- });
- window.fetch = jest.fn().mockImplementation(mockFetchPromise);
- MockApiClient.addMockResponse({
- url: `/groups/${group.id}/integrations/${integration.id}/?action=link`,
- body: formConfig,
- });
- wrapper = generateWrapper('link');
- await tick();
- wrapper.update();
- });
- afterEach(() => {
- window.fetch.mockClear();
- delete window.fetch;
- });
- it('fast typing is debounced and uses trailing call when fetching data', () => {
- jest.useFakeTimers();
- wrapper.instance().getOptions(externalIssueField, 'd');
- wrapper.instance().getOptions(externalIssueField, 'do');
- wrapper.instance().getOptions(externalIssueField, 'doo');
- wrapper.instance().getOptions(externalIssueField, 'doOT');
- expect(window.fetch).toHaveBeenCalledTimes(0);
- jest.advanceTimersByTime(300);
- expect(window.fetch).toHaveBeenCalledTimes(1);
- expect(window.fetch).toHaveBeenCalledWith(
- '/search?field=externalIssue&query=doOT&repo=scefali%2Ftest'
- );
- });
- it('debounced function returns a promise with the options returned by fetch', async () => {
- const output = await wrapper.instance().getOptions(externalIssueField, 'd');
- expect(output).toEqual(mockSuccessResponse);
- });
- });
- });
- });
|