Commit 2f02dc07 authored by Savas Vedova's avatar Savas Vedova

Merge branch '343523-use-date-attributes-when-listing-iterations' into 'master'

Use start and due date attributes when listing iterations

See merge request gitlab-org/gitlab!72847
parents 2da743f6 393773cf
...@@ -15,6 +15,8 @@ import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants'; ...@@ -15,6 +15,8 @@ import { BV_HIDE_TOOLTIP } from '~/lib/utils/constants';
import { n__, s__, __ } from '~/locale'; import { n__, s__, __ } from '~/locale';
import sidebarEventHub from '~/sidebar/event_hub'; import sidebarEventHub from '~/sidebar/event_hub';
import Tracking from '~/tracking'; import Tracking from '~/tracking';
import { formatDate } from '~/lib/utils/datetime_utility';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import AccessorUtilities from '../../lib/utils/accessor'; import AccessorUtilities from '../../lib/utils/accessor';
import { inactiveId, LIST, ListType, toggleFormEventPrefix } from '../constants'; import { inactiveId, LIST, ListType, toggleFormEventPrefix } from '../constants';
import eventHub from '../eventhub'; import eventHub from '../eventhub';
...@@ -40,7 +42,7 @@ export default { ...@@ -40,7 +42,7 @@ export default {
directives: { directives: {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
}, },
mixins: [Tracking.mixin()], mixins: [Tracking.mixin(), glFeatureFlagMixin()],
inject: { inject: {
boardId: { boardId: {
default: '', default: '',
...@@ -86,6 +88,13 @@ export default { ...@@ -86,6 +88,13 @@ export default {
listTitle() { listTitle() {
return this.list?.label?.description || this.list?.assignee?.name || this.list.title || ''; return this.list?.label?.description || this.list?.assignee?.name || this.list.title || '';
}, },
listIterationPeriod() {
const iteration = this.list?.iteration;
return iteration ? this.getIterationPeriod(iteration) : '';
},
isIterationList() {
return this.listType === ListType.iteration;
},
showListHeaderButton() { showListHeaderButton() {
return !this.disabled && this.listType !== ListType.closed; return !this.disabled && this.listType !== ListType.closed;
}, },
...@@ -96,7 +105,10 @@ export default { ...@@ -96,7 +105,10 @@ export default {
return this.listType === ListType.assignee && this.showListDetails; return this.listType === ListType.assignee && this.showListDetails;
}, },
showIterationListDetails() { showIterationListDetails() {
return this.listType === ListType.iteration && this.showListDetails; return this.isIterationList && this.showListDetails;
},
iterationCadencesAvailable() {
return this.isIterationList && this.glFeatures.iterationCadences;
}, },
showListDetails() { showListDetails() {
return !this.list.collapsed || !this.isSwimlanesHeader; return !this.list.collapsed || !this.isSwimlanesHeader;
...@@ -208,6 +220,16 @@ export default { ...@@ -208,6 +220,16 @@ export default {
updateListFunction() { updateListFunction() {
this.updateList({ listId: this.list.id, collapsed: this.list.collapsed }); this.updateList({ listId: this.list.id, collapsed: this.list.collapsed });
}, },
/**
* TODO: https://gitlab.com/gitlab-org/gitlab/-/issues/344619
* This method also exists as a utility function in ee/../iterations/utils.js
* Remove the duplication when the EE code is separated from this compoment.
*/
getIterationPeriod({ startDate, dueDate }) {
const start = formatDate(startDate, 'mmm d, yyyy', true);
const due = formatDate(dueDate, 'mmm d, yyyy', true);
return `${start} - ${due}`;
},
}, },
}; };
</script> </script>
...@@ -307,6 +329,13 @@ export default { ...@@ -307,6 +329,13 @@ export default {
class="board-title-main-text gl-text-truncate" class="board-title-main-text gl-text-truncate"
> >
{{ listTitle }} {{ listTitle }}
<div
v-if="iterationCadencesAvailable"
class="gl-display-inline-block"
data-testid="board-list-iteration-period"
>
<time class="gl-text-gray-400">{{ listIterationPeriod }}</time>
</div>
</span> </span>
<span <span
v-if="listType === 'assignee'" v-if="listType === 'assignee'"
......
...@@ -13,6 +13,9 @@ import BoardAddNewColumnForm from '~/boards/components/board_add_new_column_form ...@@ -13,6 +13,9 @@ import BoardAddNewColumnForm from '~/boards/components/board_add_new_column_form
import { ListType } from '~/boards/constants'; import { ListType } from '~/boards/constants';
import { isScopedLabel } from '~/lib/utils/common_utils'; import { isScopedLabel } from '~/lib/utils/common_utils';
import { __ } from '~/locale'; import { __ } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { getIterationPeriod } from 'ee/iterations/utils';
import IterationPeriod from 'ee/iterations/components/iteration_period.vue';
export const listTypeInfo = { export const listTypeInfo = {
[ListType.label]: { [ListType.label]: {
...@@ -57,10 +60,12 @@ export default { ...@@ -57,10 +60,12 @@ export default {
GlFormGroup, GlFormGroup,
GlFormRadio, GlFormRadio,
GlFormRadioGroup, GlFormRadioGroup,
IterationPeriod,
}, },
directives: { directives: {
GlTooltip, GlTooltip,
}, },
mixins: [glFeatureFlagMixin()],
inject: [ inject: [
'scopedLabelsAvailable', 'scopedLabelsAvailable',
'milestoneListsAvailable', 'milestoneListsAvailable',
...@@ -221,6 +226,7 @@ export default { ...@@ -221,6 +226,7 @@ export default {
this.selectedItem = { ...item }; this.selectedItem = { ...item };
} }
}, },
getIterationPeriod,
}, },
}; };
</script> </script>
...@@ -318,7 +324,14 @@ export default { ...@@ -318,7 +324,14 @@ export default {
:sub-label="`@${item.username}`" :sub-label="`@${item.username}`"
:src="item.avatarUrl" :src="item.avatarUrl"
/> />
<span v-else>{{ item.title }}</span> <div v-else class="gl-display-inline-block">
{{ item.title }}
<IterationPeriod
v-if="iterationTypeSelected && glFeatures.iterationCadences"
data-testid="new-column-iteration-period"
>{{ getIterationPeriod(item) }}</IterationPeriod
>
</div>
</label> </label>
</gl-form-radio-group> </gl-form-radio-group>
......
...@@ -20,6 +20,8 @@ fragment BoardListFragment on BoardList { ...@@ -20,6 +20,8 @@ fragment BoardListFragment on BoardList {
iteration { iteration {
id id
title title
startDate
dueDate
webPath webPath
description description
} }
......
...@@ -13,6 +13,8 @@ import { ...@@ -13,6 +13,8 @@ import {
import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import { fetchPolicies } from '~/lib/graphql'; import { fetchPolicies } from '~/lib/graphql';
import { __, s__ } from '~/locale'; import { __, s__ } from '~/locale';
import IterationPeriod from 'ee/iterations/components/iteration_period.vue';
import { getIterationPeriod } from '../utils';
import { Namespace } from '../constants'; import { Namespace } from '../constants';
import groupQuery from '../queries/group_iterations_in_cadence.query.graphql'; import groupQuery from '../queries/group_iterations_in_cadence.query.graphql';
import projectQuery from '../queries/project_iterations_in_cadence.query.graphql'; import projectQuery from '../queries/project_iterations_in_cadence.query.graphql';
...@@ -51,6 +53,7 @@ export default { ...@@ -51,6 +53,7 @@ export default {
GlModal, GlModal,
GlSkeletonLoader, GlSkeletonLoader,
TimeboxStatusBadge, TimeboxStatusBadge,
IterationPeriod,
}, },
apollo: { apollo: {
workspace: { workspace: {
...@@ -218,6 +221,7 @@ export default { ...@@ -218,6 +221,7 @@ export default {
focusMenu() { focusMenu() {
this.$refs.menu.$el.focus(); this.$refs.menu.$el.focus();
}, },
getIterationPeriod,
}, },
}; };
</script> </script>
...@@ -300,11 +304,12 @@ export default { ...@@ -300,11 +304,12 @@ export default {
<li <li
v-for="iteration in iterations" v-for="iteration in iterations"
:key="iteration.id" :key="iteration.id"
class="gl-bg-gray-10 gl-p-5 gl-border-t-solid gl-border-gray-100 gl-border-t-1 gl-list-style-position-inside" class="gl-bg-gray-10 gl-p-5 gl-border-t-solid gl-border-gray-100 gl-border-t-1"
> >
<router-link :to="path(iteration.id)"> <router-link :to="path(iteration.id)">
{{ iteration.title }} {{ iteration.title }}
</router-link> </router-link>
<IterationPeriod class="gl-pt-2">{{ getIterationPeriod(iteration) }}</IterationPeriod>
<timebox-status-badge v-if="showStateBadge" :state="iteration.state" /> <timebox-status-badge v-if="showStateBadge" :state="iteration.state" />
</li> </li>
</ol> </ol>
......
<template>
<div>
<time class="gl-text-gray-400">
<slot></slot>
</time>
</div>
</template>
import { formatDate } from '~/lib/utils/datetime_utility';
const PERIOD_DATE_FORMAT = 'mmm d, yyyy';
/**
* The arguments are two date strings in formatted in ISO 8601 (YYYY-MM-DD)
*
* @returns {string} ex. "Oct 1, 2021 - Oct 10, 2021"
*/
export function getIterationPeriod({ startDate, dueDate }) {
const start = formatDate(startDate, PERIOD_DATE_FORMAT, true);
const due = formatDate(dueDate, PERIOD_DATE_FORMAT, true);
return `${start} - ${due}`;
}
...@@ -10,6 +10,8 @@ import { ...@@ -10,6 +10,8 @@ import {
} from '@gitlab/ui'; } from '@gitlab/ui';
import { __ } from '~/locale'; import { __ } from '~/locale';
import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import IterationPeriod from 'ee/iterations/components/iteration_period.vue';
import { getIterationPeriod } from 'ee/iterations/utils';
import { iterationSelectTextMap, iterationDisplayState } from '../constants'; import { iterationSelectTextMap, iterationDisplayState } from '../constants';
import groupIterationsQuery from '../queries/iterations.query.graphql'; import groupIterationsQuery from '../queries/iterations.query.graphql';
...@@ -25,6 +27,7 @@ export default { ...@@ -25,6 +27,7 @@ export default {
GlSearchBoxByType, GlSearchBoxByType,
GlDropdownSectionHeader, GlDropdownSectionHeader,
GlLoadingIcon, GlLoadingIcon,
IterationPeriod,
}, },
mixins: [glFeatureFlagMixin()], mixins: [glFeatureFlagMixin()],
apollo: { apollo: {
...@@ -73,7 +76,11 @@ export default { ...@@ -73,7 +76,11 @@ export default {
return; return;
} }
const { title } = iteration.iterationCadence; const { title } = iteration.iterationCadence;
const cadenceIteration = { id: iteration.id, title: iteration.title }; const cadenceIteration = {
id: iteration.id,
title: iteration.title,
period: getIterationPeriod(iteration),
};
const cadence = cadences.find((cad) => cad.title === title); const cadence = cadences.find((cad) => cad.title === title);
if (cadence) { if (cadence) {
cadence.iterations.push(cadenceIteration); cadence.iterations.push(cadenceIteration);
...@@ -144,8 +151,10 @@ export default { ...@@ -144,8 +151,10 @@ export default {
:is-check-item="true" :is-check-item="true"
:is-checked="isIterationChecked(iterationItem.id)" :is-checked="isIterationChecked(iterationItem.id)"
@click="onClick(iterationItem)" @click="onClick(iterationItem)"
>{{ iterationItem.title }}</gl-dropdown-item
> >
{{ iterationItem.title }}
<IterationPeriod>{{ iterationItem.period }}</IterationPeriod>
</gl-dropdown-item>
</template> </template>
</template> </template>
</gl-dropdown> </gl-dropdown>
......
...@@ -7,7 +7,9 @@ import { ...@@ -7,7 +7,9 @@ import {
GlLink, GlLink,
} from '@gitlab/ui'; } from '@gitlab/ui';
import SidebarDropdownWidget from 'ee/sidebar/components/sidebar_dropdown_widget.vue'; import SidebarDropdownWidget from 'ee/sidebar/components/sidebar_dropdown_widget.vue';
import IterationPeriod from 'ee/iterations/components/iteration_period.vue';
import { IssuableType } from '~/issue_show/constants'; import { IssuableType } from '~/issue_show/constants';
import { getIterationPeriod } from 'ee/iterations/utils';
import { IssuableAttributeType } from '../constants'; import { IssuableAttributeType } from '../constants';
export default { export default {
...@@ -19,6 +21,7 @@ export default { ...@@ -19,6 +21,7 @@ export default {
GlIcon, GlIcon,
GlLink, GlLink,
SidebarDropdownWidget, SidebarDropdownWidget,
IterationPeriod,
}, },
props: { props: {
attrWorkspacePath: { attrWorkspacePath: {
...@@ -45,6 +48,9 @@ export default { ...@@ -45,6 +48,9 @@ export default {
getCadenceTitle(currentIteration) { getCadenceTitle(currentIteration) {
return currentIteration?.iterationCadence?.title; return currentIteration?.iterationCadence?.title;
}, },
getIterationPeriod(iteration) {
return getIterationPeriod({ startDate: iteration?.startDate, dueDate: iteration?.dueDate });
},
getIterationCadences(iterations) { getIterationCadences(iterations) {
const cadences = []; const cadences = [];
iterations.forEach((iteration) => { iterations.forEach((iteration) => {
...@@ -52,7 +58,11 @@ export default { ...@@ -52,7 +58,11 @@ export default {
return; return;
} }
const { title } = iteration.iterationCadence; const { title } = iteration.iterationCadence;
const cadenceIteration = { id: iteration.id, title: iteration.title }; const cadenceIteration = {
id: iteration.id,
title: iteration.title,
period: this.getIterationPeriod(iteration),
};
const cadence = cadences.find((cad) => cad.title === title); const cadence = cadences.find((cad) => cad.title === title);
if (cadence) { if (cadence) {
cadence.iterations.push(cadenceIteration); cadence.iterations.push(cadenceIteration);
...@@ -83,8 +93,11 @@ export default { ...@@ -83,8 +93,11 @@ export default {
:href="attributeUrl" :href="attributeUrl"
data-qa-selector="iteration_link" data-qa-selector="iteration_link"
> >
<div>
<gl-icon name="iteration" class="gl-mr-1" /> <gl-icon name="iteration" class="gl-mr-1" />
{{ attributeTitle }} {{ attributeTitle }}
</div>
<IterationPeriod>{{ getIterationPeriod(currentAttribute) }}</IterationPeriod>
</gl-link> </gl-link>
</template> </template>
<template #list="{ attributesList = [], isAttributeChecked, updateAttribute }"> <template #list="{ attributesList = [], isAttributeChecked, updateAttribute }">
...@@ -102,6 +115,7 @@ export default { ...@@ -102,6 +115,7 @@ export default {
@click="updateAttribute(iteration.id)" @click="updateAttribute(iteration.id)"
> >
{{ iteration.title }} {{ iteration.title }}
<IterationPeriod>{{ iteration.period }}</IterationPeriod>
</gl-dropdown-item> </gl-dropdown-item>
</template> </template>
</template> </template>
......
fragment IterationFragment on Iteration { fragment IterationFragment on Iteration {
id id
title title
startDate
dueDate
webUrl webUrl
iterationCadence { iterationCadence {
id id
......
...@@ -209,6 +209,7 @@ RSpec.describe 'Issue Sidebar' do ...@@ -209,6 +209,7 @@ RSpec.describe 'Issue Sidebar' do
within '[data-testid="iteration-edit"]' do within '[data-testid="iteration-edit"]' do
expect(page).to have_text(iteration_cadence.title) expect(page).to have_text(iteration_cadence.title)
expect(page).to have_text(iteration.title) expect(page).to have_text(iteration.title)
expect(page).to have_text(iteration_period(iteration))
end end
select_iteration(iteration.title) select_iteration(iteration.title)
...@@ -216,6 +217,7 @@ RSpec.describe 'Issue Sidebar' do ...@@ -216,6 +217,7 @@ RSpec.describe 'Issue Sidebar' do
within '[data-testid="select-iteration"]' do within '[data-testid="select-iteration"]' do
expect(page).to have_text(iteration_cadence.title) expect(page).to have_text(iteration_cadence.title)
expect(page).to have_text(iteration.title) expect(page).to have_text(iteration.title)
expect(page).to have_text(iteration_period(iteration))
end end
find_and_click_edit_iteration find_and_click_edit_iteration
...@@ -295,4 +297,8 @@ RSpec.describe 'Issue Sidebar' do ...@@ -295,4 +297,8 @@ RSpec.describe 'Issue Sidebar' do
wait_for_requests wait_for_requests
end end
end end
def iteration_period(iteration)
iteration.start_date.strftime("%b%e, %Y") + ' - ' + iteration.due_date.strftime("%b%e, %Y")
end
end end
...@@ -38,6 +38,7 @@ describe('BoardAddNewColumn', () => { ...@@ -38,6 +38,7 @@ describe('BoardAddNewColumn', () => {
iterations = [], iterations = [],
getListByTypeId = jest.fn(), getListByTypeId = jest.fn(),
actions = {}, actions = {},
glFeatures = {},
} = {}) => { } = {}) => {
wrapper = extendedWrapper( wrapper = extendedWrapper(
shallowMount(BoardAddNewColumn, { shallowMount(BoardAddNewColumn, {
...@@ -75,6 +76,7 @@ describe('BoardAddNewColumn', () => { ...@@ -75,6 +76,7 @@ describe('BoardAddNewColumn', () => {
milestoneListsAvailable: true, milestoneListsAvailable: true,
assigneeListsAvailable: true, assigneeListsAvailable: true,
iterationListsAvailable: true, iterationListsAvailable: true,
glFeatures,
}, },
}), }),
); );
...@@ -92,6 +94,8 @@ describe('BoardAddNewColumn', () => { ...@@ -92,6 +94,8 @@ describe('BoardAddNewColumn', () => {
const findForm = () => wrapper.findComponent(BoardAddNewColumnForm); const findForm = () => wrapper.findComponent(BoardAddNewColumnForm);
const cancelButton = () => wrapper.findByTestId('cancelAddNewColumn'); const cancelButton = () => wrapper.findByTestId('cancelAddNewColumn');
const submitButton = () => wrapper.findByTestId('addNewColumnButton'); const submitButton = () => wrapper.findByTestId('addNewColumnButton');
const findLabels = () => wrapper.findComponent(GlDropdown).findAll('label');
const findIterationPeriod = (item) => item.find('[data-testid="new-column-iteration-period"]');
const listTypeSelect = (type) => { const listTypeSelect = (type) => {
const radio = wrapper const radio = wrapper
.findAllComponents(GlFormRadio) .findAllComponents(GlFormRadio)
...@@ -100,6 +104,11 @@ describe('BoardAddNewColumn', () => { ...@@ -100,6 +104,11 @@ describe('BoardAddNewColumn', () => {
radio.element.value = type; radio.element.value = type;
radio.vm.$emit('change', type); radio.vm.$emit('change', type);
}; };
const selectIteration = async () => {
listTypeSelect(ListType.iteration);
await nextTick();
};
it('clicking cancel hides the form', () => { it('clicking cancel hides the form', () => {
const setAddColumnFormVisibility = jest.fn(); const setAddColumnFormVisibility = jest.fn();
...@@ -203,17 +212,19 @@ describe('BoardAddNewColumn', () => { ...@@ -203,17 +212,19 @@ describe('BoardAddNewColumn', () => {
}); });
describe('iteration list', () => { describe('iteration list', () => {
beforeEach(async () => { const iterationMountOptions = {
mountComponent({
iterations: mockIterations, iterations: mockIterations,
actions: { actions: {
fetchIterations: jest.fn(), fetchIterations: jest.fn(),
}, },
}); };
listTypeSelect(ListType.iteration); beforeEach(async () => {
mountComponent({
...iterationMountOptions,
});
await nextTick(); await selectIteration();
}); });
it('sets iteration placeholder text in form', () => { it('sets iteration placeholder text in form', () => {
...@@ -230,5 +241,32 @@ describe('BoardAddNewColumn', () => { ...@@ -230,5 +241,32 @@ describe('BoardAddNewColumn', () => {
expect(itemList.at(0).attributes('value')).toBe(mockIterations[0].id); expect(itemList.at(0).attributes('value')).toBe(mockIterations[0].id);
expect(itemList.at(1).attributes('value')).toBe(mockIterations[1].id); expect(itemList.at(1).attributes('value')).toBe(mockIterations[1].id);
}); });
describe('iteration_cadences feature flag is off', () => {
it('does not display iteration period', async () => {
const labels = findLabels();
expect(findIterationPeriod(labels.at(0)).exists()).toBe(false);
expect(findIterationPeriod(labels.at(1)).exists()).toBe(false);
});
});
describe('iteration_cadences feature flag is on', () => {
it('displays iteration period', async () => {
mountComponent({
...iterationMountOptions,
glFeatures: {
iterationCadences: true,
},
});
await selectIteration();
const labels = findLabels();
expect(labels.at(0).text()).toContain('Oct 5, 2021 - Oct 10, 2021');
expect(findIterationPeriod(labels.at(0)).isVisible()).toBe(true);
expect(labels.at(1).text()).toContain('Oct 12, 2021 - Oct 17, 2021');
expect(findIterationPeriod(labels.at(1)).isVisible()).toBe(true);
});
});
}); });
}); });
...@@ -4,7 +4,7 @@ import Vuex from 'vuex'; ...@@ -4,7 +4,7 @@ import Vuex from 'vuex';
import BoardListHeader from 'ee/boards/components/board_list_header.vue'; import BoardListHeader from 'ee/boards/components/board_list_header.vue';
import defaultGetters from 'ee/boards/stores/getters'; import defaultGetters from 'ee/boards/stores/getters';
import { mockLabelList } from 'jest/boards/mock_data'; import { mockList, mockLabelList } from 'jest/boards/mock_data';
import { ListType, inactiveId } from '~/boards/constants'; import { ListType, inactiveId } from '~/boards/constants';
import boardsEventHub from '~/boards/eventhub'; import boardsEventHub from '~/boards/eventhub';
import sidebarEventHub from '~/sidebar/event_hub'; import sidebarEventHub from '~/sidebar/event_hub';
...@@ -13,6 +13,24 @@ const localVue = createLocalVue(); ...@@ -13,6 +13,24 @@ const localVue = createLocalVue();
localVue.use(Vuex); localVue.use(Vuex);
const listMocks = {
[ListType.assignee]: {
assignee: {},
},
[ListType.iteration]: {
iteration: {
startDate: '2021-11-01',
dueDate: '2021-11-05',
},
},
[ListType.label]: {
...mockLabelList,
},
[ListType.backlog]: {
...mockList,
},
};
describe('Board List Header Component', () => { describe('Board List Header Component', () => {
let store; let store;
let wrapper; let wrapper;
...@@ -26,20 +44,16 @@ describe('Board List Header Component', () => { ...@@ -26,20 +44,16 @@ describe('Board List Header Component', () => {
currentUserId = 1, currentUserId = 1,
state = { activeId: inactiveId }, state = { activeId: inactiveId },
getters = {}, getters = {},
glFeatures = {},
} = {}) => { } = {}) => {
const boardId = '1'; const boardId = '1';
const listMock = { const listMock = {
...mockLabelList, ...listMocks[listType],
listType, listType,
collapsed, collapsed,
}; };
if (listType === ListType.assignee) {
delete listMock.label;
listMock.assignee = {};
}
if (withLocalStorage) { if (withLocalStorage) {
localStorage.setItem( localStorage.setItem(
`boards.${boardId}.${listMock.listType}.${listMock.id}.expanded`, `boards.${boardId}.${listMock.listType}.${listMock.id}.expanded`,
...@@ -69,11 +83,13 @@ describe('Board List Header Component', () => { ...@@ -69,11 +83,13 @@ describe('Board List Header Component', () => {
boardId, boardId,
weightFeatureAvailable, weightFeatureAvailable,
currentUserId, currentUserId,
glFeatures,
}, },
}); });
}; };
const findSettingsButton = () => wrapper.find({ ref: 'settingsBtn' }); const findSettingsButton = () => wrapper.find({ ref: 'settingsBtn' });
const findIterationPeriod = () => wrapper.find('[data-testid="board-list-iteration-period"]');
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
...@@ -107,7 +123,7 @@ describe('Board List Header Component', () => { ...@@ -107,7 +123,7 @@ describe('Board List Header Component', () => {
it('emits `toggle-epic-form` event on Sidebar eventHub when clicked', async () => { it('emits `toggle-epic-form` event on Sidebar eventHub when clicked', async () => {
await newEpicButton.vm.$emit('click'); await newEpicButton.vm.$emit('click');
expect(boardsEventHub.$emit).toHaveBeenCalledWith(`toggle-epic-form-${mockLabelList.id}`); expect(boardsEventHub.$emit).toHaveBeenCalledWith(`toggle-epic-form-${mockList.id}`);
expect(boardsEventHub.$emit).toHaveBeenCalledTimes(1); expect(boardsEventHub.$emit).toHaveBeenCalledTimes(1);
}); });
}); });
...@@ -184,4 +200,28 @@ describe('Board List Header Component', () => { ...@@ -184,4 +200,28 @@ describe('Board List Header Component', () => {
expect(wrapper.find({ ref: 'weightTooltip' }).exists()).toBe(false); expect(wrapper.find({ ref: 'weightTooltip' }).exists()).toBe(false);
}); });
}); });
describe('iteration cadence', () => {
describe('iteration_cadences feature flag is on', () => {
it('displays iteration period', () => {
createComponent({
listType: ListType.iteration,
glFeatures: {
iterationCadences: true,
},
});
expect(findIterationPeriod().text()).toContain('Nov 1, 2021 - Nov 5, 2021');
expect(findIterationPeriod().isVisible()).toBe(true);
});
});
describe('iteration_cadences feature flag is off', () => {
it('does not display iteration period', () => {
createComponent({ listType: ListType.iteration });
expect(findIterationPeriod().exists()).toBe(false);
});
});
});
}); });
...@@ -108,10 +108,14 @@ export const mockIterations = [ ...@@ -108,10 +108,14 @@ export const mockIterations = [
{ {
id: 'gid://gitlab/Iteration/1', id: 'gid://gitlab/Iteration/1',
title: 'Iteration 1', title: 'Iteration 1',
startDate: '2021-10-05',
dueDate: '2021-10-10',
}, },
{ {
id: 'gid://gitlab/Iteration/2', id: 'gid://gitlab/Iteration/2',
title: 'Iteration 2', title: 'Iteration 2',
startDate: '2021-10-12',
dueDate: '2021-10-17',
}, },
]; ];
......
...@@ -44,6 +44,8 @@ describe('Iteration cadence list item', () => { ...@@ -44,6 +44,8 @@ describe('Iteration cadence list item', () => {
}, },
]; ];
const iterationPeriods = ['Aug 13, 2021 - Aug 14, 2021'];
const cadence = { const cadence = {
id: 'gid://gitlab/Iterations::Cadence/561', id: 'gid://gitlab/Iterations::Cadence/561',
title: 'Weekly cadence', title: 'Weekly cadence',
...@@ -180,15 +182,16 @@ describe('Iteration cadence list item', () => { ...@@ -180,15 +182,16 @@ describe('Iteration cadence list item', () => {
expect(findCreateIterationButton().exists()).toBe(canCreateIteration); expect(findCreateIterationButton().exists()).toBe(canCreateIteration);
}); });
it('shows iterations after loading', async () => { it('shows iterations with dates after loading', async () => {
await createComponent(); await createComponent();
expand(); expand();
await waitForPromises(); await waitForPromises();
iterations.forEach(({ title }) => { iterations.forEach(({ title }, i) => {
expect(wrapper.text()).toContain(title); expect(wrapper.text()).toContain(title);
expect(wrapper.text()).toContain(iterationPeriods[i]);
}); });
}); });
......
...@@ -22,6 +22,8 @@ const TEST_ITERATIONS = [ ...@@ -22,6 +22,8 @@ const TEST_ITERATIONS = [
{ {
id: '11', id: '11',
title: 'Test Title', title: 'Test Title',
startDate: '2021-10-01',
dueDate: '2021-10-05',
webUrl: '', webUrl: '',
state: '', state: '',
iterationCadence: { iterationCadence: {
...@@ -32,6 +34,8 @@ const TEST_ITERATIONS = [ ...@@ -32,6 +34,8 @@ const TEST_ITERATIONS = [
{ {
id: '22', id: '22',
title: 'Another Test Title', title: 'Another Test Title',
startDate: '2021-10-06',
dueDate: '2021-10-10',
webUrl: '', webUrl: '',
state: '', state: '',
iterationCadence: { iterationCadence: {
...@@ -42,6 +46,8 @@ const TEST_ITERATIONS = [ ...@@ -42,6 +46,8 @@ const TEST_ITERATIONS = [
{ {
id: '33', id: '33',
title: 'Yet Another Test Title', title: 'Yet Another Test Title',
startDate: '2021-10-11',
dueDate: '2021-10-15',
webUrl: '', webUrl: '',
state: '', state: '',
iterationCadence: { iterationCadence: {
...@@ -265,16 +271,19 @@ describe('IterationDropdown', () => { ...@@ -265,16 +271,19 @@ describe('IterationDropdown', () => {
const dropdownItems = wrapper.findAll('li'); const dropdownItems = wrapper.findAll('li');
expect(dropdownItems.at(0).text()).toBe('Assign Iteration'); expect(dropdownItems.at(0).text()).toBe('Assign Iteration');
expect(dropdownItems.at(1).text()).toBe('No iteration'); expect(dropdownItems.at(1).text()).toContain('No iteration');
expect(dropdownItems.at(2).findComponent(GlDropdownDivider).exists()).toBe(true); expect(dropdownItems.at(2).findComponent(GlDropdownDivider).exists()).toBe(true);
expect(dropdownItems.at(3).findComponent(GlDropdownSectionHeader).text()).toBe('My Cadence'); expect(dropdownItems.at(3).findComponent(GlDropdownSectionHeader).text()).toBe('My Cadence');
expect(dropdownItems.at(4).text()).toBe('Test Title'); expect(dropdownItems.at(4).text()).toContain('Test Title');
expect(dropdownItems.at(5).text()).toBe('Yet Another Test Title'); expect(dropdownItems.at(4).text()).toContain('Oct 1, 2021 - Oct 5, 2021');
expect(dropdownItems.at(5).text()).toContain('Yet Another Test Title');
expect(dropdownItems.at(5).text()).toContain('Oct 11, 2021 - Oct 15, 2021');
expect(dropdownItems.at(6).findComponent(GlDropdownDivider).exists()).toBe(true); expect(dropdownItems.at(6).findComponent(GlDropdownDivider).exists()).toBe(true);
expect(dropdownItems.at(7).findComponent(GlDropdownSectionHeader).text()).toBe( expect(dropdownItems.at(7).findComponent(GlDropdownSectionHeader).text()).toBe(
'My Second Cadence', 'My Second Cadence',
); );
expect(dropdownItems.at(8).text()).toBe('Another Test Title'); expect(dropdownItems.at(8).text()).toContain('Another Test Title');
expect(dropdownItems.at(8).text()).toContain('Oct 6, 2021 - Oct 10, 2021');
}); });
}); });
}); });
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