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