Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/issuable/components/related_issuable_item_spec.js')
-rw-r--r--spec/frontend/issuable/components/related_issuable_item_spec.js233
1 files changed, 148 insertions, 85 deletions
diff --git a/spec/frontend/issuable/components/related_issuable_item_spec.js b/spec/frontend/issuable/components/related_issuable_item_spec.js
index 6b48f83041a..3f9f048605a 100644
--- a/spec/frontend/issuable/components/related_issuable_item_spec.js
+++ b/spec/frontend/issuable/components/related_issuable_item_spec.js
@@ -1,23 +1,25 @@
-import { mount } from '@vue/test-utils';
-import { nextTick } from 'vue';
+import { GlIcon, GlLink, GlButton } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
import { TEST_HOST } from 'helpers/test_constants';
import IssueDueDate from '~/boards/components/issue_due_date.vue';
import { formatDate } from '~/lib/utils/datetime_utility';
+import { updateHistory } from '~/lib/utils/url_utility';
+import { __ } from '~/locale';
import RelatedIssuableItem from '~/issuable/components/related_issuable_item.vue';
+import IssueMilestone from '~/issuable/components/issue_milestone.vue';
+import IssueAssignees from '~/issuable/components/issue_assignees.vue';
+import WorkItemDetailModal from '~/work_items/components/work_item_detail_modal.vue';
import { defaultAssignees, defaultMilestone } from './related_issuable_mock_data';
+jest.mock('~/lib/utils/url_utility', () => ({
+ ...jest.requireActual('~/lib/utils/url_utility'),
+ updateHistory: jest.fn(),
+}));
+
describe('RelatedIssuableItem', () => {
let wrapper;
- function mountComponent({ mountMethod = mount, stubs = {}, props = {}, slots = {} } = {}) {
- wrapper = mountMethod(RelatedIssuableItem, {
- propsData: props,
- slots,
- stubs,
- });
- }
-
- const props = {
+ const defaultProps = {
idKey: 1,
displayReference: 'gitlab-org/gitlab-test#1',
pathIdSeparator: '#',
@@ -31,84 +33,94 @@ describe('RelatedIssuableItem', () => {
assignees: defaultAssignees,
eventNamespace: 'relatedIssue',
};
- const slots = {
- dueDate: '<div class="js-due-date-slot"></div>',
- weight: '<div class="js-weight-slot"></div>',
- };
-
- const findRemoveButton = () => wrapper.find({ ref: 'removeButton' });
- const findLockIcon = () => wrapper.find({ ref: 'lockIcon' });
- beforeEach(() => {
- mountComponent({ props, slots });
- });
+ const findIcon = () => wrapper.findComponent(GlIcon);
+ const findIssueDueDate = () => wrapper.findComponent(IssueDueDate);
+ const findLockIcon = () => wrapper.find('[data-testid="lockIcon"]');
+ const findRemoveButton = () => wrapper.findComponent(GlButton);
+ const findTitleLink = () => wrapper.findComponent(GlLink);
+ const findWorkItemDetailModal = () => wrapper.findComponent(WorkItemDetailModal);
+
+ function mountComponent({ data = {}, props = {} } = {}) {
+ wrapper = shallowMount(RelatedIssuableItem, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ data() {
+ return data;
+ },
+ });
+ }
afterEach(() => {
wrapper.destroy();
});
it('contains issuable-info-container class when canReorder is false', () => {
- expect(wrapper.props('canReorder')).toBe(false);
- expect(wrapper.find('.issuable-info-container').exists()).toBe(true);
+ mountComponent({ props: { canReorder: false } });
+
+ expect(wrapper.classes('issuable-info-container')).toBe(true);
});
it('does not render token state', () => {
+ mountComponent();
+
expect(wrapper.find('.text-secondary svg').exists()).toBe(false);
});
it('does not render remove button', () => {
- expect(wrapper.find({ ref: 'removeButton' }).exists()).toBe(false);
+ mountComponent();
+
+ expect(findRemoveButton().exists()).toBe(false);
});
describe('token title', () => {
+ beforeEach(() => {
+ mountComponent();
+ });
+
it('links to computedPath', () => {
- expect(wrapper.find('.item-title a').attributes('href')).toEqual(wrapper.props('path'));
+ expect(findTitleLink().attributes('href')).toBe(defaultProps.path);
});
it('renders confidential icon', () => {
- expect(wrapper.find('.confidential-icon').exists()).toBe(true);
+ expect(findIcon().attributes('title')).toBe(__('Confidential'));
});
it('renders title', () => {
- expect(wrapper.find('.item-title a').text()).toEqual(props.title);
+ expect(findTitleLink().text()).toBe(defaultProps.title);
});
});
describe('token state', () => {
- const tokenState = () => wrapper.find({ ref: 'iconElementXL' });
-
- beforeEach(() => {
- wrapper.setProps({ state: 'opened' });
- });
-
- it('renders if hasState', () => {
- expect(tokenState().exists()).toBe(true);
- });
-
it('renders state title', () => {
- const stateTitle = tokenState().attributes('title');
- const formattedCreateDate = formatDate(props.createdAt);
+ mountComponent({ props: { state: 'opened' } });
+ const stateTitle = findIcon().attributes('title');
+ const formattedCreateDate = formatDate(defaultProps.createdAt);
expect(stateTitle).toContain('<span class="bold">Created</span>');
expect(stateTitle).toContain(`<span class="text-tertiary">${formattedCreateDate}</span>`);
});
it('renders aria label', () => {
- expect(tokenState().attributes('aria-label')).toEqual('opened');
+ mountComponent({ props: { state: 'opened' } });
+
+ expect(findIcon().attributes('arialabel')).toBe('opened');
});
it('renders open icon when open state', () => {
- expect(tokenState().classes('issue-token-state-icon-open')).toBe(true);
+ mountComponent({ props: { state: 'opened' } });
+
+ expect(findIcon().props('name')).toBe('issue-open-m');
+ expect(findIcon().classes('issue-token-state-icon-open')).toBe(true);
});
- it('renders close icon when close state', async () => {
- wrapper.setProps({
- state: 'closed',
- closedAt: '2018-12-01T00:00:00.00Z',
- });
- await nextTick();
+ it('renders close icon when close state', () => {
+ mountComponent({ props: { state: 'closed', closedAt: '2018-12-01T00:00:00.00Z' } });
- expect(tokenState().classes('issue-token-state-icon-closed')).toBe(true);
+ expect(findIcon().props('name')).toBe('issue-close');
+ expect(findIcon().classes('issue-token-state-icon-closed')).toBe(true);
});
});
@@ -116,75 +128,66 @@ describe('RelatedIssuableItem', () => {
const tokenMetadata = () => wrapper.find('.item-meta');
it('renders item path and ID', () => {
+ mountComponent();
const pathAndID = tokenMetadata().find('.item-path-id').text();
expect(pathAndID).toContain('gitlab-org/gitlab-test');
expect(pathAndID).toContain('#1');
});
- it('renders milestone icon and name', () => {
- const milestoneIcon = tokenMetadata().find('.item-milestone svg');
- const milestoneTitle = tokenMetadata().find('.item-milestone .milestone-title');
+ it('renders milestone', () => {
+ mountComponent();
- expect(milestoneIcon.attributes('data-testid')).toBe('clock-icon');
- expect(milestoneTitle.text()).toContain('Milestone title');
+ expect(wrapper.findComponent(IssueMilestone).props('milestone')).toEqual(
+ defaultProps.milestone,
+ );
});
it('renders due date component with correct due date', () => {
- expect(wrapper.find(IssueDueDate).props('date')).toBe(props.dueDate);
+ mountComponent();
+
+ expect(findIssueDueDate().props('date')).toBe(defaultProps.dueDate);
});
- it('does not render red icon for overdue issue that is closed', async () => {
- mountComponent({
- props: {
- ...props,
- closedAt: '2018-12-01T00:00:00.00Z',
- },
- });
- await nextTick();
+ it('does not render red icon for overdue issue that is closed', () => {
+ mountComponent({ props: { closedAt: '2018-12-01T00:00:00.00Z' } });
- expect(wrapper.find(IssueDueDate).props('closed')).toBe(true);
+ expect(findIssueDueDate().props('closed')).toBe(true);
});
});
describe('token assignees', () => {
it('renders assignees avatars', () => {
- // Expect 2 times 2 because assignees are rendered twice, due to layout issues
- expect(wrapper.findAll('.item-assignees .user-avatar-link').length).toBeDefined();
+ mountComponent();
- expect(wrapper.find('.item-assignees .avatar-counter').text()).toContain('+2');
+ expect(wrapper.findComponent(IssueAssignees).props('assignees')).toEqual(
+ defaultProps.assignees,
+ );
});
});
describe('remove button', () => {
beforeEach(() => {
- wrapper.setProps({ canRemove: true });
+ mountComponent({ props: { canRemove: true }, data: { removeDisabled: true } });
});
it('renders if canRemove', () => {
- expect(findRemoveButton().exists()).toBe(true);
+ expect(findRemoveButton().props('icon')).toBe('close');
+ expect(findRemoveButton().attributes('aria-label')).toBe(__('Remove'));
});
it('does not render the lock icon', () => {
expect(findLockIcon().exists()).toBe(false);
});
- it('renders disabled button when removeDisabled', async () => {
- // setData usage is discouraged. See https://gitlab.com/groups/gitlab-org/-/epics/7330 for details
- // eslint-disable-next-line no-restricted-syntax
- wrapper.setData({ removeDisabled: true });
- await nextTick();
-
- expect(findRemoveButton().attributes('disabled')).toEqual('disabled');
+ it('renders disabled button when removeDisabled', () => {
+ expect(findRemoveButton().attributes('disabled')).toBe('true');
});
- it('triggers onRemoveRequest when clicked', async () => {
- findRemoveButton().trigger('click');
- await nextTick();
- const { relatedIssueRemoveRequest } = wrapper.emitted();
+ it('triggers onRemoveRequest when clicked', () => {
+ findRemoveButton().vm.$emit('click');
- expect(relatedIssueRemoveRequest.length).toBe(1);
- expect(relatedIssueRemoveRequest[0]).toEqual([props.idKey]);
+ expect(wrapper.emitted('relatedIssueRemoveRequest')).toEqual([[defaultProps.idKey]]);
});
});
@@ -192,10 +195,7 @@ describe('RelatedIssuableItem', () => {
const lockedMessage = 'Issues created from a vulnerability cannot be removed';
beforeEach(() => {
- wrapper.setProps({
- isLocked: true,
- lockedMessage,
- });
+ mountComponent({ props: { isLocked: true, lockedMessage } });
});
it('does not render the remove button', () => {
@@ -206,4 +206,67 @@ describe('RelatedIssuableItem', () => {
expect(findLockIcon().attributes('title')).toBe(lockedMessage);
});
});
+
+ describe('work item modal', () => {
+ const workItem = 'gid://gitlab/WorkItem/1';
+
+ it('renders', () => {
+ mountComponent();
+
+ expect(findWorkItemDetailModal().props('workItemId')).toBe(workItem);
+ });
+
+ describe('when work item is issue and the related issue title is clicked', () => {
+ it('does not open', () => {
+ mountComponent({ props: { workItemType: 'ISSUE' } });
+ wrapper.vm.$refs.modal.show = jest.fn();
+
+ findTitleLink().vm.$emit('click', { preventDefault: () => {} });
+
+ expect(wrapper.vm.$refs.modal.show).not.toHaveBeenCalled();
+ });
+ });
+
+ describe('when work item is task and the related issue title is clicked', () => {
+ beforeEach(() => {
+ mountComponent({ props: { workItemType: 'TASK' } });
+ wrapper.vm.$refs.modal.show = jest.fn();
+ findTitleLink().vm.$emit('click', { preventDefault: () => {} });
+ });
+
+ it('opens', () => {
+ expect(wrapper.vm.$refs.modal.show).toHaveBeenCalled();
+ });
+
+ it('updates the url params with the work item id', () => {
+ expect(updateHistory).toHaveBeenCalledWith({
+ url: `${TEST_HOST}/?work_item_id=1`,
+ replace: true,
+ });
+ });
+ });
+
+ describe('when it emits "workItemDeleted" event', () => {
+ it('emits "relatedIssueRemoveRequest" event', () => {
+ mountComponent();
+
+ findWorkItemDetailModal().vm.$emit('workItemDeleted', workItem);
+
+ expect(wrapper.emitted('relatedIssueRemoveRequest')).toEqual([[workItem]]);
+ });
+ });
+
+ describe('when it emits "close" event', () => {
+ it('removes the work item id from the url params', () => {
+ mountComponent();
+
+ findWorkItemDetailModal().vm.$emit('close');
+
+ expect(updateHistory).toHaveBeenCalledWith({
+ url: `${TEST_HOST}/`,
+ replace: true,
+ });
+ });
+ });
+ });
});