2018-05-09 12:01:36 +05:30
|
|
|
import $ from 'jquery';
|
2022-07-16 23:28:13 +05:30
|
|
|
import Vue, { nextTick } from 'vue';
|
|
|
|
import VueApollo from 'vue-apollo';
|
2019-12-04 20:38:33 +05:30
|
|
|
import '~/behaviors/markdown/render_gfm';
|
2022-06-21 17:19:12 +05:30
|
|
|
import { GlTooltip, GlModal } from '@gitlab/ui';
|
2022-07-16 23:28:13 +05:30
|
|
|
|
2022-06-21 17:19:12 +05:30
|
|
|
import setWindowLocation from 'helpers/set_window_location_helper';
|
2022-04-04 11:22:00 +05:30
|
|
|
import { stubComponent } from 'helpers/stub_component';
|
2020-05-24 23:13:21 +05:30
|
|
|
import { TEST_HOST } from 'helpers/test_constants';
|
2022-05-07 20:08:51 +05:30
|
|
|
import { mockTracking } from 'helpers/tracking_helper';
|
2022-07-16 23:28:13 +05:30
|
|
|
import createMockApollo from 'helpers/mock_apollo_helper';
|
|
|
|
import waitForPromises from 'helpers/wait_for_promises';
|
2022-05-07 20:08:51 +05:30
|
|
|
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
|
2022-07-16 23:28:13 +05:30
|
|
|
|
2022-10-11 01:57:18 +05:30
|
|
|
import createFlash from '~/flash';
|
2022-01-26 12:08:38 +05:30
|
|
|
import Description from '~/issues/show/components/description.vue';
|
2022-06-21 17:19:12 +05:30
|
|
|
import { updateHistory } from '~/lib/utils/url_utility';
|
2022-07-16 23:28:13 +05:30
|
|
|
import workItemQuery from '~/work_items/graphql/work_item.query.graphql';
|
2022-08-13 15:12:31 +05:30
|
|
|
import workItemTypesQuery from '~/work_items/graphql/project_work_item_types.query.graphql';
|
|
|
|
import createWorkItemFromTaskMutation from '~/work_items/graphql/create_work_item_from_task.mutation.graphql';
|
2020-05-24 23:13:21 +05:30
|
|
|
import TaskList from '~/task_list';
|
2022-05-07 20:08:51 +05:30
|
|
|
import WorkItemDetailModal from '~/work_items/components/work_item_detail_modal.vue';
|
2022-07-23 23:45:48 +05:30
|
|
|
import { TRACKING_CATEGORY_SHOW } from '~/work_items/constants';
|
2022-08-13 15:12:31 +05:30
|
|
|
import {
|
|
|
|
projectWorkItemTypesQueryResponse,
|
|
|
|
createWorkItemFromTaskMutationResponse,
|
|
|
|
} from 'jest/work_items/mock_data';
|
2022-04-04 11:22:00 +05:30
|
|
|
import {
|
|
|
|
descriptionProps as initialProps,
|
|
|
|
descriptionHtmlWithCheckboxes,
|
2022-06-21 17:19:12 +05:30
|
|
|
descriptionHtmlWithTask,
|
2022-04-04 11:22:00 +05:30
|
|
|
} from '../mock_data/mock_data';
|
2020-05-24 23:13:21 +05:30
|
|
|
|
2022-05-07 20:08:51 +05:30
|
|
|
jest.mock('~/flash');
|
2022-06-21 17:19:12 +05:30
|
|
|
jest.mock('~/lib/utils/url_utility', () => ({
|
|
|
|
...jest.requireActual('~/lib/utils/url_utility'),
|
|
|
|
updateHistory: jest.fn(),
|
|
|
|
}));
|
2020-05-24 23:13:21 +05:30
|
|
|
jest.mock('~/task_list');
|
2017-09-10 17:25:29 +05:30
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
const showModal = jest.fn();
|
|
|
|
const hideModal = jest.fn();
|
2022-07-16 23:28:13 +05:30
|
|
|
const showDetailsModal = jest.fn();
|
2022-06-21 17:19:12 +05:30
|
|
|
const $toast = {
|
|
|
|
show: jest.fn(),
|
|
|
|
};
|
2022-04-04 11:22:00 +05:30
|
|
|
|
2022-07-16 23:28:13 +05:30
|
|
|
const workItemQueryResponse = {
|
|
|
|
data: {
|
|
|
|
workItem: null,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const queryHandler = jest.fn().mockResolvedValue(workItemQueryResponse);
|
2022-08-13 15:12:31 +05:30
|
|
|
const workItemTypesQueryHandler = jest.fn().mockResolvedValue(projectWorkItemTypesQueryResponse);
|
|
|
|
const createWorkItemFromTaskSuccessHandler = jest
|
|
|
|
.fn()
|
|
|
|
.mockResolvedValue(createWorkItemFromTaskMutationResponse);
|
2022-07-16 23:28:13 +05:30
|
|
|
|
2017-09-10 17:25:29 +05:30
|
|
|
describe('Description component', () => {
|
2022-04-04 11:22:00 +05:30
|
|
|
let wrapper;
|
|
|
|
|
2022-07-16 23:28:13 +05:30
|
|
|
Vue.use(VueApollo);
|
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
const findGfmContent = () => wrapper.find('[data-testid="gfm-content"]');
|
|
|
|
const findTextarea = () => wrapper.find('[data-testid="textarea"]');
|
|
|
|
const findTaskActionButtons = () => wrapper.findAll('.js-add-task');
|
2022-06-21 17:19:12 +05:30
|
|
|
const findConvertToTaskButton = () => wrapper.find('.js-add-task');
|
2022-07-16 23:28:13 +05:30
|
|
|
const findTaskLink = () => wrapper.find('a.gfm-issue');
|
2022-04-04 11:22:00 +05:30
|
|
|
|
2022-06-21 17:19:12 +05:30
|
|
|
const findTooltips = () => wrapper.findAllComponents(GlTooltip);
|
2022-04-04 11:22:00 +05:30
|
|
|
const findModal = () => wrapper.findComponent(GlModal);
|
2022-05-07 20:08:51 +05:30
|
|
|
const findWorkItemDetailModal = () => wrapper.findComponent(WorkItemDetailModal);
|
2022-04-04 11:22:00 +05:30
|
|
|
|
2022-10-11 01:57:18 +05:30
|
|
|
function createComponent({
|
|
|
|
props = {},
|
|
|
|
provide,
|
|
|
|
createWorkItemFromTaskHandler = createWorkItemFromTaskSuccessHandler,
|
|
|
|
} = {}) {
|
2022-05-07 20:08:51 +05:30
|
|
|
wrapper = shallowMountExtended(Description, {
|
2022-04-04 11:22:00 +05:30
|
|
|
propsData: {
|
2022-06-21 17:19:12 +05:30
|
|
|
issueId: 1,
|
2022-04-04 11:22:00 +05:30
|
|
|
...initialProps,
|
|
|
|
...props,
|
|
|
|
},
|
2022-08-13 15:12:31 +05:30
|
|
|
provide: {
|
|
|
|
fullPath: 'gitlab-org/gitlab-test',
|
|
|
|
...provide,
|
|
|
|
},
|
|
|
|
apolloProvider: createMockApollo([
|
|
|
|
[workItemQuery, queryHandler],
|
|
|
|
[workItemTypesQuery, workItemTypesQueryHandler],
|
2022-10-11 01:57:18 +05:30
|
|
|
[createWorkItemFromTaskMutation, createWorkItemFromTaskHandler],
|
2022-08-13 15:12:31 +05:30
|
|
|
]),
|
2022-06-21 17:19:12 +05:30
|
|
|
mocks: {
|
|
|
|
$toast,
|
|
|
|
},
|
2022-04-04 11:22:00 +05:30
|
|
|
stubs: {
|
|
|
|
GlModal: stubComponent(GlModal, {
|
|
|
|
methods: {
|
|
|
|
show: showModal,
|
|
|
|
hide: hideModal,
|
|
|
|
},
|
|
|
|
}),
|
2022-07-16 23:28:13 +05:30
|
|
|
WorkItemDetailModal: stubComponent(WorkItemDetailModal, {
|
|
|
|
methods: {
|
|
|
|
show: showDetailsModal,
|
|
|
|
},
|
|
|
|
}),
|
2022-04-04 11:22:00 +05:30
|
|
|
},
|
|
|
|
});
|
|
|
|
}
|
2017-09-10 17:25:29 +05:30
|
|
|
|
|
|
|
beforeEach(() => {
|
2022-06-21 17:19:12 +05:30
|
|
|
setWindowLocation(TEST_HOST);
|
|
|
|
|
2017-09-10 17:25:29 +05:30
|
|
|
if (!document.querySelector('.issuable-meta')) {
|
|
|
|
const metaData = document.createElement('div');
|
|
|
|
metaData.classList.add('issuable-meta');
|
2019-03-02 22:35:43 +05:30
|
|
|
metaData.innerHTML =
|
|
|
|
'<div class="flash-container"></div><span id="task_status"></span><span id="task_status_short"></span>';
|
2017-09-10 17:25:29 +05:30
|
|
|
|
|
|
|
document.body.appendChild(metaData);
|
|
|
|
}
|
2018-03-17 18:26:18 +05:30
|
|
|
});
|
|
|
|
|
|
|
|
afterEach(() => {
|
2022-04-04 11:22:00 +05:30
|
|
|
wrapper.destroy();
|
2017-09-10 17:25:29 +05:30
|
|
|
});
|
|
|
|
|
2019-03-02 22:35:43 +05:30
|
|
|
afterAll(() => {
|
|
|
|
$('.issuable-meta .flash-container').remove();
|
|
|
|
});
|
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
it('doesnt animate first description changes', async () => {
|
|
|
|
createComponent();
|
|
|
|
await wrapper.setProps({
|
|
|
|
descriptionHtml: 'changed',
|
2020-11-24 15:15:51 +05:30
|
|
|
});
|
2022-04-04 11:22:00 +05:30
|
|
|
|
|
|
|
expect(findGfmContent().classes()).not.toContain('issue-realtime-pre-pulse');
|
2020-11-24 15:15:51 +05:30
|
|
|
});
|
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
it('animates description changes on live update', async () => {
|
|
|
|
createComponent();
|
|
|
|
await wrapper.setProps({
|
|
|
|
descriptionHtml: 'changed',
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(findGfmContent().classes()).not.toContain('issue-realtime-pre-pulse');
|
|
|
|
|
|
|
|
await wrapper.setProps({
|
|
|
|
descriptionHtml: 'changed second time',
|
|
|
|
});
|
|
|
|
|
|
|
|
expect(findGfmContent().classes()).toContain('issue-realtime-pre-pulse');
|
|
|
|
|
|
|
|
await jest.runOnlyPendingTimers();
|
|
|
|
|
|
|
|
expect(findGfmContent().classes()).toContain('issue-realtime-trigger-pulse');
|
2017-09-10 17:25:29 +05:30
|
|
|
});
|
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
it('applies syntax highlighting and math when description changed', async () => {
|
2020-05-24 23:13:21 +05:30
|
|
|
const prototypeSpy = jest.spyOn($.prototype, 'renderGFM');
|
2022-04-04 11:22:00 +05:30
|
|
|
createComponent();
|
2018-10-15 14:42:47 +05:30
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
await wrapper.setProps({
|
|
|
|
descriptionHtml: 'changed',
|
2020-05-24 23:13:21 +05:30
|
|
|
});
|
2022-04-04 11:22:00 +05:30
|
|
|
|
|
|
|
expect(findGfmContent().exists()).toBe(true);
|
|
|
|
expect(prototypeSpy).toHaveBeenCalled();
|
2020-05-24 23:13:21 +05:30
|
|
|
});
|
|
|
|
|
|
|
|
it('sets data-update-url', () => {
|
2022-04-04 11:22:00 +05:30
|
|
|
createComponent();
|
|
|
|
expect(findTextarea().attributes('data-update-url')).toBe(TEST_HOST);
|
2020-05-24 23:13:21 +05:30
|
|
|
});
|
|
|
|
|
|
|
|
describe('TaskList', () => {
|
2018-03-17 18:26:18 +05:30
|
|
|
beforeEach(() => {
|
2020-05-24 23:13:21 +05:30
|
|
|
TaskList.mockClear();
|
2018-03-17 18:26:18 +05:30
|
|
|
});
|
|
|
|
|
2020-05-24 23:13:21 +05:30
|
|
|
it('re-inits the TaskList when description changed', () => {
|
2022-04-04 11:22:00 +05:30
|
|
|
createComponent({
|
|
|
|
props: {
|
|
|
|
issuableType: 'issuableType',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
wrapper.setProps({
|
|
|
|
descriptionHtml: 'changed',
|
|
|
|
});
|
2018-03-17 18:26:18 +05:30
|
|
|
|
2020-05-24 23:13:21 +05:30
|
|
|
expect(TaskList).toHaveBeenCalled();
|
2018-03-17 18:26:18 +05:30
|
|
|
});
|
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
it('does not re-init the TaskList when canUpdate is false', async () => {
|
|
|
|
createComponent({
|
|
|
|
props: {
|
|
|
|
issuableType: 'issuableType',
|
|
|
|
canUpdate: false,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
wrapper.setProps({
|
|
|
|
descriptionHtml: 'changed',
|
|
|
|
});
|
2018-03-17 18:26:18 +05:30
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
expect(TaskList).not.toHaveBeenCalled();
|
2018-03-17 18:26:18 +05:30
|
|
|
});
|
|
|
|
|
2020-05-24 23:13:21 +05:30
|
|
|
it('calls with issuableType dataType', () => {
|
2022-04-04 11:22:00 +05:30
|
|
|
createComponent({
|
|
|
|
props: {
|
|
|
|
issuableType: 'issuableType',
|
|
|
|
},
|
|
|
|
});
|
|
|
|
wrapper.setProps({
|
|
|
|
descriptionHtml: 'changed',
|
|
|
|
});
|
2018-03-17 18:26:18 +05:30
|
|
|
|
2020-05-24 23:13:21 +05:30
|
|
|
expect(TaskList).toHaveBeenCalledWith({
|
|
|
|
dataType: 'issuableType',
|
|
|
|
fieldName: 'description',
|
|
|
|
selector: '.detail-page-description',
|
2021-12-11 22:18:48 +05:30
|
|
|
onUpdate: expect.any(Function),
|
|
|
|
onSuccess: expect.any(Function),
|
2020-05-24 23:13:21 +05:30
|
|
|
onError: expect.any(Function),
|
|
|
|
lockVersion: 0,
|
2018-03-17 18:26:18 +05:30
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2017-09-10 17:25:29 +05:30
|
|
|
|
|
|
|
describe('taskStatus', () => {
|
2022-04-04 11:22:00 +05:30
|
|
|
it('adds full taskStatus', async () => {
|
|
|
|
createComponent({
|
|
|
|
props: {
|
|
|
|
taskStatus: '1 of 1',
|
|
|
|
},
|
2017-09-10 17:25:29 +05:30
|
|
|
});
|
2022-04-04 11:22:00 +05:30
|
|
|
await nextTick();
|
2017-09-10 17:25:29 +05:30
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
expect(document.querySelector('.issuable-meta #task_status').textContent.trim()).toBe(
|
|
|
|
'1 of 1',
|
|
|
|
);
|
|
|
|
});
|
2017-09-10 17:25:29 +05:30
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
it('adds short taskStatus', async () => {
|
|
|
|
createComponent({
|
|
|
|
props: {
|
|
|
|
taskStatus: '1 of 1',
|
|
|
|
},
|
2017-09-10 17:25:29 +05:30
|
|
|
});
|
2022-04-04 11:22:00 +05:30
|
|
|
await nextTick();
|
2017-09-10 17:25:29 +05:30
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
expect(document.querySelector('.issuable-meta #task_status_short').textContent.trim()).toBe(
|
2022-08-27 11:52:29 +05:30
|
|
|
'1/1 checklist item',
|
2022-04-04 11:22:00 +05:30
|
|
|
);
|
|
|
|
});
|
2017-09-10 17:25:29 +05:30
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
it('clears task status text when no tasks are present', async () => {
|
|
|
|
createComponent({
|
|
|
|
props: {
|
|
|
|
taskStatus: '0 of 0',
|
|
|
|
},
|
2017-09-10 17:25:29 +05:30
|
|
|
});
|
2022-04-04 11:22:00 +05:30
|
|
|
|
|
|
|
await nextTick();
|
|
|
|
|
|
|
|
expect(document.querySelector('.issuable-meta #task_status').textContent.trim()).toBe('');
|
2017-09-10 17:25:29 +05:30
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2022-08-27 11:52:29 +05:30
|
|
|
describe('with work_items_create_from_markdown feature flag enabled', () => {
|
2022-04-04 11:22:00 +05:30
|
|
|
describe('empty description', () => {
|
2022-05-07 20:08:51 +05:30
|
|
|
beforeEach(() => {
|
2022-04-04 11:22:00 +05:30
|
|
|
createComponent({
|
|
|
|
props: {
|
|
|
|
descriptionHtml: '',
|
|
|
|
},
|
|
|
|
provide: {
|
|
|
|
glFeatures: {
|
2022-08-27 11:52:29 +05:30
|
|
|
workItemsCreateFromMarkdown: true,
|
2022-04-04 11:22:00 +05:30
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
2022-05-07 20:08:51 +05:30
|
|
|
return nextTick();
|
2022-04-04 11:22:00 +05:30
|
|
|
});
|
2021-12-11 22:18:48 +05:30
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
it('renders without error', () => {
|
|
|
|
expect(findTaskActionButtons()).toHaveLength(0);
|
|
|
|
});
|
2021-12-11 22:18:48 +05:30
|
|
|
});
|
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
describe('description with checkboxes', () => {
|
2022-05-07 20:08:51 +05:30
|
|
|
beforeEach(() => {
|
2022-04-04 11:22:00 +05:30
|
|
|
createComponent({
|
|
|
|
props: {
|
|
|
|
descriptionHtml: descriptionHtmlWithCheckboxes,
|
|
|
|
},
|
|
|
|
provide: {
|
|
|
|
glFeatures: {
|
2022-08-27 11:52:29 +05:30
|
|
|
workItemsCreateFromMarkdown: true,
|
2022-04-04 11:22:00 +05:30
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
2022-05-07 20:08:51 +05:30
|
|
|
return nextTick();
|
2022-04-04 11:22:00 +05:30
|
|
|
});
|
2021-12-11 22:18:48 +05:30
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
it('renders a list of hidden buttons corresponding to checkboxes in description HTML', () => {
|
|
|
|
expect(findTaskActionButtons()).toHaveLength(3);
|
|
|
|
});
|
2021-12-11 22:18:48 +05:30
|
|
|
|
2022-06-21 17:19:12 +05:30
|
|
|
it('renders a list of tooltips corresponding to checkboxes in description HTML', () => {
|
|
|
|
expect(findTooltips()).toHaveLength(3);
|
|
|
|
expect(findTooltips().at(0).props('target')).toBe(
|
2022-04-04 11:22:00 +05:30
|
|
|
findTaskActionButtons().at(0).attributes('id'),
|
|
|
|
);
|
|
|
|
});
|
2021-12-11 22:18:48 +05:30
|
|
|
|
2022-04-04 11:22:00 +05:30
|
|
|
it('does not show a modal by default', () => {
|
2022-08-13 15:12:31 +05:30
|
|
|
expect(findModal().exists()).toBe(false);
|
2022-04-04 11:22:00 +05:30
|
|
|
});
|
2019-03-02 22:35:43 +05:30
|
|
|
|
2022-10-11 01:57:18 +05:30
|
|
|
it('shows toast after delete success', async () => {
|
|
|
|
const newDesc = 'description';
|
|
|
|
findWorkItemDetailModal().vm.$emit('workItemDeleted', newDesc);
|
|
|
|
|
|
|
|
expect(wrapper.emitted('updateDescription')).toEqual([[newDesc]]);
|
|
|
|
expect($toast.show).toHaveBeenCalledWith('Task deleted');
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('creating work item from checklist item', () => {
|
2022-08-13 15:12:31 +05:30
|
|
|
it('emits `updateDescription` after creating new work item', async () => {
|
2022-10-11 01:57:18 +05:30
|
|
|
createComponent({
|
|
|
|
props: {
|
|
|
|
descriptionHtml: descriptionHtmlWithCheckboxes,
|
|
|
|
},
|
|
|
|
provide: {
|
|
|
|
glFeatures: {
|
|
|
|
workItemsCreateFromMarkdown: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
});
|
|
|
|
|
2022-08-13 15:12:31 +05:30
|
|
|
const newDescription = `<p>New description</p>`;
|
2022-04-04 11:22:00 +05:30
|
|
|
|
2022-06-21 17:19:12 +05:30
|
|
|
await findConvertToTaskButton().trigger('click');
|
2019-03-02 22:35:43 +05:30
|
|
|
|
2022-08-13 15:12:31 +05:30
|
|
|
await waitForPromises();
|
|
|
|
|
2022-06-21 17:19:12 +05:30
|
|
|
expect(wrapper.emitted('updateDescription')).toEqual([[newDescription]]);
|
|
|
|
});
|
|
|
|
|
2022-10-11 01:57:18 +05:30
|
|
|
it('shows flash message when creating task fails', async () => {
|
|
|
|
createComponent({
|
|
|
|
props: {
|
|
|
|
descriptionHtml: descriptionHtmlWithCheckboxes,
|
|
|
|
},
|
|
|
|
provide: {
|
|
|
|
glFeatures: {
|
|
|
|
workItemsCreateFromMarkdown: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
createWorkItemFromTaskHandler: jest.fn().mockRejectedValue({}),
|
|
|
|
});
|
2022-04-04 11:22:00 +05:30
|
|
|
|
2022-10-11 01:57:18 +05:30
|
|
|
await findConvertToTaskButton().trigger('click');
|
|
|
|
|
|
|
|
await waitForPromises();
|
|
|
|
|
|
|
|
expect(createFlash).toHaveBeenCalledWith(
|
|
|
|
expect.objectContaining({
|
|
|
|
message: 'Something went wrong when creating task. Please try again.',
|
|
|
|
}),
|
|
|
|
);
|
2022-04-04 11:22:00 +05:30
|
|
|
});
|
2019-03-02 22:35:43 +05:30
|
|
|
});
|
2022-05-07 20:08:51 +05:30
|
|
|
|
|
|
|
describe('work items detail', () => {
|
2022-06-21 17:19:12 +05:30
|
|
|
describe('when opening and closing', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
createComponent({
|
|
|
|
props: {
|
|
|
|
descriptionHtml: descriptionHtmlWithTask,
|
|
|
|
},
|
|
|
|
provide: {
|
2022-08-27 11:52:29 +05:30
|
|
|
glFeatures: { workItemsCreateFromMarkdown: true },
|
2022-06-21 17:19:12 +05:30
|
|
|
},
|
|
|
|
});
|
|
|
|
return nextTick();
|
2022-05-07 20:08:51 +05:30
|
|
|
});
|
|
|
|
|
2022-06-21 17:19:12 +05:30
|
|
|
it('opens when task button is clicked', async () => {
|
|
|
|
await findTaskLink().trigger('click');
|
2022-05-07 20:08:51 +05:30
|
|
|
|
2022-07-16 23:28:13 +05:30
|
|
|
expect(showDetailsModal).toHaveBeenCalled();
|
2022-06-21 17:19:12 +05:30
|
|
|
expect(updateHistory).toHaveBeenCalledWith({
|
|
|
|
url: `${TEST_HOST}/?work_item_id=2`,
|
|
|
|
replace: true,
|
|
|
|
});
|
|
|
|
});
|
2022-05-07 20:08:51 +05:30
|
|
|
|
2022-06-21 17:19:12 +05:30
|
|
|
it('closes from an open state', async () => {
|
|
|
|
await findTaskLink().trigger('click');
|
2022-05-07 20:08:51 +05:30
|
|
|
|
2022-06-21 17:19:12 +05:30
|
|
|
findWorkItemDetailModal().vm.$emit('close');
|
|
|
|
await nextTick();
|
2022-05-07 20:08:51 +05:30
|
|
|
|
2022-06-21 17:19:12 +05:30
|
|
|
expect(updateHistory).toHaveBeenLastCalledWith({
|
|
|
|
url: `${TEST_HOST}/`,
|
|
|
|
replace: true,
|
|
|
|
});
|
|
|
|
});
|
2022-05-07 20:08:51 +05:30
|
|
|
|
2022-06-21 17:19:12 +05:30
|
|
|
it('tracks when opened', async () => {
|
|
|
|
const trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn);
|
2022-05-07 20:08:51 +05:30
|
|
|
|
2022-06-21 17:19:12 +05:30
|
|
|
await findTaskLink().trigger('click');
|
2022-05-07 20:08:51 +05:30
|
|
|
|
2022-06-21 17:19:12 +05:30
|
|
|
expect(trackingSpy).toHaveBeenCalledWith(
|
2022-07-23 23:45:48 +05:30
|
|
|
TRACKING_CATEGORY_SHOW,
|
2022-06-21 17:19:12 +05:30
|
|
|
'viewed_work_item_from_modal',
|
|
|
|
{
|
2022-07-23 23:45:48 +05:30
|
|
|
category: TRACKING_CATEGORY_SHOW,
|
2022-06-21 17:19:12 +05:30
|
|
|
label: 'work_item_view',
|
|
|
|
property: 'type_task',
|
|
|
|
},
|
|
|
|
);
|
|
|
|
});
|
2022-05-07 20:08:51 +05:30
|
|
|
});
|
|
|
|
|
2022-06-21 17:19:12 +05:30
|
|
|
describe('when url query `work_item_id` exists', () => {
|
|
|
|
it.each`
|
2022-07-16 23:28:13 +05:30
|
|
|
behavior | workItemId | modalOpened
|
|
|
|
${'opens'} | ${'2'} | ${1}
|
|
|
|
${'does not open'} | ${'123'} | ${0}
|
|
|
|
${'does not open'} | ${'123e'} | ${0}
|
|
|
|
${'does not open'} | ${'12e3'} | ${0}
|
|
|
|
${'does not open'} | ${'1e23'} | ${0}
|
|
|
|
${'does not open'} | ${'x'} | ${0}
|
|
|
|
${'does not open'} | ${'undefined'} | ${0}
|
2022-06-21 17:19:12 +05:30
|
|
|
`(
|
|
|
|
'$behavior when url contains `work_item_id=$workItemId`',
|
2022-07-16 23:28:13 +05:30
|
|
|
async ({ workItemId, modalOpened }) => {
|
2022-06-21 17:19:12 +05:30
|
|
|
setWindowLocation(`?work_item_id=${workItemId}`);
|
|
|
|
|
|
|
|
createComponent({
|
|
|
|
props: { descriptionHtml: descriptionHtmlWithTask },
|
2022-08-27 11:52:29 +05:30
|
|
|
provide: { glFeatures: { workItemsCreateFromMarkdown: true } },
|
2022-06-21 17:19:12 +05:30
|
|
|
});
|
|
|
|
|
2022-07-16 23:28:13 +05:30
|
|
|
expect(showDetailsModal).toHaveBeenCalledTimes(modalOpened);
|
2022-06-21 17:19:12 +05:30
|
|
|
},
|
|
|
|
);
|
2022-05-07 20:08:51 +05:30
|
|
|
});
|
|
|
|
});
|
2022-07-16 23:28:13 +05:30
|
|
|
|
|
|
|
describe('when hovering task links', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
createComponent({
|
|
|
|
props: {
|
|
|
|
descriptionHtml: descriptionHtmlWithTask,
|
|
|
|
},
|
|
|
|
provide: {
|
2022-08-27 11:52:29 +05:30
|
|
|
glFeatures: { workItemsCreateFromMarkdown: true },
|
2022-07-16 23:28:13 +05:30
|
|
|
},
|
|
|
|
});
|
|
|
|
return nextTick();
|
|
|
|
});
|
|
|
|
|
|
|
|
it('prefetches work item detail after work item link is hovered for 150ms', async () => {
|
|
|
|
await findTaskLink().trigger('mouseover');
|
|
|
|
jest.advanceTimersByTime(150);
|
|
|
|
await waitForPromises();
|
|
|
|
|
|
|
|
expect(queryHandler).toHaveBeenCalledWith({
|
|
|
|
id: 'gid://gitlab/WorkItem/2',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('does not work item detail after work item link is hovered for less than 150ms', async () => {
|
|
|
|
await findTaskLink().trigger('mouseover');
|
|
|
|
await findTaskLink().trigger('mouseout');
|
|
|
|
jest.advanceTimersByTime(150);
|
|
|
|
await waitForPromises();
|
|
|
|
|
|
|
|
expect(queryHandler).not.toHaveBeenCalled();
|
|
|
|
});
|
|
|
|
});
|
2019-03-02 22:35:43 +05:30
|
|
|
});
|
2017-09-10 17:25:29 +05:30
|
|
|
});
|