Commit 191b422c authored by Daniel Tian's avatar Daniel Tian Committed by Nicolò Maria Mezzopera

Move slot content from RelatedIssueList to RelatedIssuableItem

Remove the slots in RelatedIssuableItem by moving the slot content from
RelatedIssueList to RelatedIssuableItem
parent 95af3936
......@@ -4,6 +4,7 @@ import { GlIcon, GlTooltip, GlTooltipDirective } from '@gitlab/ui';
import { sprintf } from '~/locale';
import IssueMilestone from './issue_milestone.vue';
import IssueAssignees from './issue_assignees.vue';
import IssueDueDate from '~/boards/components/issue_due_date.vue';
import relatedIssuableMixin from '../../mixins/related_issuable_mixin';
import CiIcon from '../ci_icon.vue';
......@@ -15,6 +16,8 @@ export default {
CiIcon,
GlIcon,
GlTooltip,
IssueWeight: () => import('ee_component/boards/components/issue_card_weight.vue'),
IssueDueDate,
},
directives: {
GlTooltip: GlTooltipDirective,
......@@ -120,8 +123,21 @@ export default {
/>
<!-- Flex order for slots is defined in the parent component: e.g. related_issues_block.vue -->
<slot name="dueDate"></slot>
<slot name="weight"></slot>
<span v-if="weight > 0" class="order-md-1">
<issue-weight
:weight="weight"
class="item-weight gl-display-flex gl-align-items-center"
tag-name="span"
/>
</span>
<span v-if="dueDate" class="order-md-1">
<issue-due-date
:date="dueDate"
tooltip-placement="top"
css-class="item-due-date gl-display-flex gl-align-items-center"
/>
</span>
<issue-assignees
v-if="hasAssignees"
......
<script>
import { GlLoadingIcon } from '@gitlab/ui';
import Sortable from 'sortablejs';
import IssueWeight from 'ee/boards/components/issue_card_weight.vue';
import sortableConfig from 'ee/sortable/sortable_config';
import IssueDueDate from '~/boards/components/issue_due_date.vue';
import RelatedIssuableItem from '~/vue_shared/components/issue/related_issuable_item.vue';
import tooltip from '~/vue_shared/directives/tooltip';
......@@ -14,8 +12,6 @@ export default {
},
components: {
GlLoadingIcon,
IssueDueDate,
IssueWeight,
RelatedIssuableItem,
},
props: {
......@@ -132,29 +128,15 @@ export default {
:assignees="issue.assignees"
:created-at="issue.createdAt"
:closed-at="issue.closedAt"
:weight="issue.weight"
:due-date="issue.dueDate"
:can-remove="canAdmin"
:can-reorder="canReorder"
:path-id-separator="pathIdSeparator"
event-namespace="relatedIssue"
class="qa-related-issuable-item"
@relatedIssueRemoveRequest="$emit('relatedIssueRemoveRequest', $event)"
>
<span v-if="issue.weight > 0" slot="weight" class="order-md-1">
<issue-weight
:weight="issue.weight"
class="item-weight d-flex align-items-center"
tag-name="span"
/>
</span>
<span v-if="issue.dueDate" slot="dueDate" class="order-md-1">
<issue-due-date
:date="issue.dueDate"
tooltip-placement="top"
css-class="item-due-date d-flex align-items-center"
/>
</span>
</related-issuable-item>
/>
</li>
</ul>
</div>
......
import { isAbsolute, isSafeURL } from '~/lib/utils/url_utility';
import { REGEXES } from './constants';
window.isAbsolute = isAbsolute;
window.isSafeURL = isSafeURL;
// Get the issue in the format expected by the descendant components of related_issues_block.vue.
export const getFormattedIssue = issue => ({
...issue,
......
import { mount } from '@vue/test-utils';
import RelatedIssuableItem from '~/vue_shared/components/issue/related_issuable_item.vue';
import IssueWeight from 'ee_component/boards/components/issue_card_weight.vue';
import {
defaultAssignees,
defaultMilestone,
} from 'jest/vue_shared/components/issue/related_issuable_mock_data';
import { TEST_HOST } from 'jest/helpers/test_constants';
describe('RelatedIssuableItem', () => {
let wrapper;
function mountComponent({ mountMethod = mount, stubs = {}, props = {}, slots = {} } = {}) {
wrapper = mountMethod(RelatedIssuableItem, {
propsData: props,
slots,
stubs,
});
}
const props = {
idKey: 1,
displayReference: 'gitlab-org/gitlab-test#1',
pathIdSeparator: '#',
path: `${TEST_HOST}/path`,
title: 'title',
confidential: true,
dueDate: '1990-12-31',
weight: 10,
createdAt: '2018-12-01T00:00:00.00Z',
milestone: defaultMilestone,
assignees: defaultAssignees,
eventNamespace: 'relatedIssue',
};
const slots = {
dueDate: '<div class="js-due-date-slot"></div>',
weight: '<div class="js-weight-slot"></div>',
};
beforeEach(() => {
mountComponent({ props, slots });
});
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
it('renders weight component with correct weight', () => {
expect(wrapper.find(IssueWeight).props('weight')).toBe(props.weight);
});
});
import Vue from 'vue';
import { mount } from '@vue/test-utils';
import { formatDate } from '~/lib/utils/datetime_utility';
import RelatedIssuableItem from '~/vue_shared/components/issue/related_issuable_item.vue';
import IssueDueDate from '~/boards/components/issue_due_date.vue';
import { defaultAssignees, defaultMilestone } from './related_issuable_mock_data';
import { TEST_HOST } from 'jest/helpers/test_constants';
......@@ -71,85 +71,65 @@ describe('RelatedIssuableItem', () => {
});
describe('token state', () => {
let tokenState;
const tokenState = () => wrapper.find({ ref: 'iconElementXL' });
beforeEach(done => {
beforeEach(() => {
wrapper.setProps({ state: 'opened' });
Vue.nextTick(() => {
tokenState = wrapper.find('.issue-token-state-icon-open');
done();
});
});
it('renders if hasState', () => {
expect(tokenState.exists()).toBe(true);
expect(tokenState().exists()).toBe(true);
});
it('renders state title', () => {
const stateTitle = tokenState.attributes('title');
const stateTitle = tokenState().attributes('title');
const formattedCreateDate = formatDate(props.createdAt);
expect(stateTitle).toContain('<span class="bold">Opened</span>');
expect(stateTitle).toContain(`<span class="text-tertiary">${formattedCreateDate}</span>`);
});
it('renders aria label', () => {
expect(tokenState.attributes('aria-label')).toEqual('opened');
expect(tokenState().attributes('aria-label')).toEqual('opened');
});
it('renders open icon when open state', () => {
expect(tokenState.classes('issue-token-state-icon-open')).toBe(true);
expect(tokenState().classes('issue-token-state-icon-open')).toBe(true);
});
it('renders close icon when close state', done => {
it('renders close icon when close state', async () => {
wrapper.setProps({
state: 'closed',
closedAt: '2018-12-01T00:00:00.00Z',
});
await wrapper.vm.$nextTick();
Vue.nextTick(() => {
expect(tokenState.classes('issue-token-state-icon-closed')).toBe(true);
done();
});
expect(tokenState().classes('issue-token-state-icon-closed')).toBe(true);
});
});
describe('token metadata', () => {
let tokenMetadata;
beforeEach(done => {
Vue.nextTick(() => {
tokenMetadata = wrapper.find('.item-meta');
done();
});
});
const tokenMetadata = () => wrapper.find('.item-meta');
it('renders item path and ID', () => {
const pathAndID = tokenMetadata.find('.item-path-id').text();
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 use');
const milestoneTitle = tokenMetadata.find('.item-milestone .milestone-title');
const milestoneIcon = tokenMetadata().find('.item-milestone svg use');
const milestoneTitle = tokenMetadata().find('.item-milestone .milestone-title');
expect(milestoneIcon.attributes('href')).toContain('clock');
expect(milestoneTitle.text()).toContain('Milestone title');
});
it('renders due date component', () => {
expect(tokenMetadata.find('.js-due-date-slot').exists()).toBe(true);
});
it('renders weight component', () => {
expect(tokenMetadata.find('.js-weight-slot').exists()).toBe(true);
it('renders due date component with correct due date', () => {
expect(wrapper.find(IssueDueDate).props('date')).toBe(props.dueDate);
});
});
......@@ -163,40 +143,30 @@ describe('RelatedIssuableItem', () => {
});
describe('remove button', () => {
let removeBtn;
const removeButton = () => wrapper.find({ ref: 'removeButton' });
beforeEach(done => {
beforeEach(() => {
wrapper.setProps({ canRemove: true });
Vue.nextTick(() => {
removeBtn = wrapper.find({ ref: 'removeButton' });
done();
});
});
it('renders if canRemove', () => {
expect(removeBtn.exists()).toBe(true);
expect(removeButton().exists()).toBe(true);
});
it('renders disabled button when removeDisabled', done => {
wrapper.vm.removeDisabled = true;
it('renders disabled button when removeDisabled', async () => {
wrapper.setData({ removeDisabled: true });
await wrapper.vm.$nextTick();
Vue.nextTick(() => {
expect(removeBtn.attributes('disabled')).toEqual('disabled');
done();
});
expect(removeButton().attributes('disabled')).toEqual('disabled');
});
it('triggers onRemoveRequest when clicked', () => {
removeBtn.trigger('click');
it('triggers onRemoveRequest when clicked', async () => {
removeButton().trigger('click');
await wrapper.vm.$nextTick();
const { relatedIssueRemoveRequest } = wrapper.emitted();
return wrapper.vm.$nextTick().then(() => {
const { relatedIssueRemoveRequest } = wrapper.emitted();
expect(relatedIssueRemoveRequest.length).toBe(1);
expect(relatedIssueRemoveRequest[0]).toEqual([props.idKey]);
});
expect(relatedIssueRemoveRequest.length).toBe(1);
expect(relatedIssueRemoveRequest[0]).toEqual([props.idKey]);
});
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment