Commit d213000c authored by Florie Guibert's avatar Florie Guibert Committed by Natalia Tepluhina

Epic board sidebar - Edit epic labels [RUN AS-IF-FOSS]

parent ca836edd
......@@ -18,6 +18,8 @@ export default {
? BoardColumn
: BoardColumnDeprecated,
BoardContentSidebar: () => import('~/boards/components/board_content_sidebar.vue'),
EpicBoardContentSidebar: () =>
import('ee_component/boards/components/epic_board_content_sidebar.vue'),
EpicsSwimlanes: () => import('ee_component/boards/components/epics_swimlanes.vue'),
GlAlert,
},
......@@ -133,7 +135,14 @@ export default {
<board-content-sidebar
v-if="isSwimlanesOn || glFeatures.graphqlBoardLists"
class="issue-boards-sidebar"
class="boards-sidebar"
data-testid="issue-boards-sidebar"
/>
<epic-board-content-sidebar
v-else-if="isEpicBoard"
class="boards-sidebar"
data-testid="epic-boards-sidebar"
/>
</div>
</template>
......@@ -34,7 +34,7 @@ export default {
computed: {
...mapGetters([
'isSidebarOpen',
'activeIssue',
'activeBoardItem',
'groupPathForActiveIssue',
'projectPathForActiveIssue',
]),
......@@ -46,13 +46,13 @@ export default {
return this.isIssuableSidebar && this.isSidebarOpen;
},
fullPath() {
return this.activeIssue?.referencePath?.split('#')[0] || '';
return this.activeBoardItem?.referencePath?.split('#')[0] || '';
},
},
methods: {
...mapActions(['toggleBoardItem', 'setAssignees']),
handleClose() {
this.toggleBoardItem({ boardItem: this.activeIssue, sidebarType: this.sidebarType });
this.toggleBoardItem({ boardItem: this.activeBoardItem, sidebarType: this.sidebarType });
},
},
};
......@@ -61,7 +61,6 @@ export default {
<template>
<gl-drawer
v-if="showSidebar"
data-testid="sidebar-drawer"
:open="isSidebarOpen"
:header-height="$options.headerHeight"
@close="handleClose"
......@@ -70,9 +69,9 @@ export default {
<template #default>
<board-sidebar-issue-title />
<sidebar-assignees-widget
:iid="activeIssue.iid"
:iid="activeBoardItem.iid"
:full-path="fullPath"
:initial-assignees="activeIssue.assignees"
:initial-assignees="activeBoardItem.assignees"
class="assignee"
@assignees-updated="setAssignees"
/>
......@@ -80,7 +79,7 @@ export default {
<div>
<board-sidebar-milestone-select />
<sidebar-iteration-widget
:iid="activeIssue.iid"
:iid="activeBoardItem.iid"
:workspace-path="projectPathForActiveIssue"
:iterations-workspace-path="groupPathForActiveIssue"
:issuable-type="issuableType"
......
......@@ -18,16 +18,16 @@ export default {
};
},
computed: {
...mapGetters(['activeIssue', 'projectPathForActiveIssue']),
...mapGetters(['activeBoardItem', 'projectPathForActiveIssue']),
hasDueDate() {
return this.activeIssue.dueDate != null;
return this.activeBoardItem.dueDate != null;
},
parsedDueDate() {
if (!this.hasDueDate) {
return null;
}
return parsePikadayDate(this.activeIssue.dueDate);
return parsePikadayDate(this.activeBoardItem.dueDate);
},
formattedDueDate() {
if (!this.hasDueDate) {
......
......@@ -27,7 +27,7 @@ export default {
};
},
computed: {
...mapGetters({ issue: 'activeIssue' }),
...mapGetters({ issue: 'activeBoardItem' }),
pendingChangesStorageKey() {
return this.getPendingChangesKey(this.issue);
},
......
......@@ -21,9 +21,9 @@ export default {
};
},
computed: {
...mapGetters(['activeIssue', 'projectPathForActiveIssue']),
...mapGetters(['activeBoardItem', 'projectPathForActiveIssue']),
selectedLabels() {
const { labels = [] } = this.activeIssue;
const { labels = [] } = this.activeBoardItem;
return labels.map((label) => ({
...label,
......@@ -31,7 +31,7 @@ export default {
}));
},
issueLabels() {
const { labels = [] } = this.activeIssue;
const { labels = [] } = this.activeBoardItem;
return labels.map((label) => ({
...label,
......@@ -40,7 +40,7 @@ export default {
},
},
methods: {
...mapActions(['setActiveIssueLabels']),
...mapActions(['setActiveBoardItemLabels']),
async setLabels(payload) {
this.loading = true;
this.$refs.sidebarItem.collapse();
......@@ -52,7 +52,7 @@ export default {
.map((label) => label.id);
const input = { addLabelIds, removeLabelIds, projectPath: this.projectPathForActiveIssue };
await this.setActiveIssueLabels(input);
await this.setActiveBoardItemLabels(input);
} catch (e) {
createFlash({ message: __('An error occurred while updating labels.') });
} finally {
......@@ -65,7 +65,7 @@ export default {
try {
const removeLabelIds = [getIdFromGraphQLId(id)];
const input = { removeLabelIds, projectPath: this.projectPathForActiveIssue };
await this.setActiveIssueLabels(input);
await this.setActiveBoardItemLabels(input);
} catch (e) {
createFlash({ message: __('An error occurred when removing the label.') });
} finally {
......
......@@ -56,20 +56,20 @@ export default {
},
},
computed: {
...mapGetters(['activeIssue']),
...mapGetters(['activeBoardItem']),
hasMilestone() {
return this.activeIssue.milestone !== null;
return this.activeBoardItem.milestone !== null;
},
groupFullPath() {
const { referencePath = '' } = this.activeIssue;
const { referencePath = '' } = this.activeBoardItem;
return referencePath.slice(0, referencePath.indexOf('/'));
},
projectPath() {
const { referencePath = '' } = this.activeIssue;
const { referencePath = '' } = this.activeBoardItem;
return referencePath.slice(0, referencePath.indexOf('#'));
},
dropdownText() {
return this.activeIssue.milestone?.title ?? this.$options.i18n.noMilestone;
return this.activeBoardItem.milestone?.title ?? this.$options.i18n.noMilestone;
},
},
methods: {
......@@ -118,7 +118,7 @@ export default {
@close="handleClose"
>
<template v-if="hasMilestone" #collapsed>
<strong class="gl-text-gray-900">{{ activeIssue.milestone.title }}</strong>
<strong class="gl-text-gray-900">{{ activeBoardItem.milestone.title }}</strong>
</template>
<gl-dropdown
ref="dropdown"
......@@ -131,7 +131,7 @@ export default {
<gl-dropdown-item
data-testid="no-milestone-item"
:is-check-item="true"
:is-checked="!activeIssue.milestone"
:is-checked="!activeBoardItem.milestone"
@click="setMilestone(null)"
>
{{ $options.i18n.noMilestone }}
......@@ -143,7 +143,7 @@ export default {
v-for="milestone in milestones"
:key="milestone.id"
:is-check-item="true"
:is-checked="activeIssue.milestone && milestone.id === activeIssue.milestone.id"
:is-checked="activeBoardItem.milestone && milestone.id === activeBoardItem.milestone.id"
data-testid="milestone-item"
@click="setMilestone(milestone.id)"
>
......
......@@ -27,9 +27,9 @@ export default {
};
},
computed: {
...mapGetters(['activeIssue', 'projectPathForActiveIssue']),
...mapGetters(['activeBoardItem', 'projectPathForActiveIssue']),
notificationText() {
return this.activeIssue.emailsDisabled
return this.activeBoardItem.emailsDisabled
? this.$options.i18n.header.subscribeDisabledDescription
: this.$options.i18n.header.title;
},
......@@ -41,7 +41,7 @@ export default {
try {
await this.setActiveIssueSubscribed({
subscribed: !this.activeIssue.subscribed,
subscribed: !this.activeBoardItem.subscribed,
projectPath: this.projectPathForActiveIssue,
});
} catch (error) {
......@@ -61,8 +61,8 @@ export default {
>
<span data-testid="notification-header-text"> {{ notificationText }} </span>
<gl-toggle
v-if="!activeIssue.emailsDisabled"
:value="activeIssue.subscribed"
v-if="!activeBoardItem.emailsDisabled"
:value="activeBoardItem.subscribed"
:is-loading="loading"
:label="$options.i18n.header.title"
label-position="hidden"
......
......@@ -8,17 +8,17 @@ export default {
},
inject: ['timeTrackingLimitToHours'],
computed: {
...mapGetters(['activeIssue']),
...mapGetters(['activeBoardItem']),
},
};
</script>
<template>
<issuable-time-tracker
:time-estimate="activeIssue.timeEstimate"
:time-spent="activeIssue.totalTimeSpent"
:human-time-estimate="activeIssue.humanTimeEstimate"
:human-time-spent="activeIssue.humanTotalTimeSpent"
:time-estimate="activeBoardItem.timeEstimate"
:time-spent="activeBoardItem.totalTimeSpent"
:human-time-estimate="activeBoardItem.humanTimeEstimate"
:human-time-spent="activeBoardItem.humanTotalTimeSpent"
:limit-to-hours="timeTrackingLimitToHours"
:show-collapsed="false"
/>
......
......@@ -371,20 +371,20 @@ export default {
},
setAssignees: ({ commit, getters }, assigneeUsernames) => {
commit('UPDATE_ISSUE_BY_ID', {
issueId: getters.activeIssue.id,
commit('UPDATE_BOARD_ITEM_BY_ID', {
itemId: getters.activeBoardItem.id,
prop: 'assignees',
value: assigneeUsernames,
});
},
setActiveIssueMilestone: async ({ commit, getters }, input) => {
const { activeIssue } = getters;
const { activeBoardItem } = getters;
const { data } = await gqlClient.mutate({
mutation: issueSetMilestoneMutation,
variables: {
input: {
iid: String(activeIssue.iid),
iid: String(activeBoardItem.iid),
milestoneId: getIdFromGraphQLId(input.milestoneId),
projectPath: input.projectPath,
},
......@@ -395,8 +395,8 @@ export default {
throw new Error(data.updateIssue.errors);
}
commit(types.UPDATE_ISSUE_BY_ID, {
issueId: activeIssue.id,
commit(types.UPDATE_BOARD_ITEM_BY_ID, {
itemId: activeBoardItem.id,
prop: 'milestone',
value: data.updateIssue.issue.milestone,
});
......@@ -447,13 +447,17 @@ export default {
.catch(() => commit(types.ADD_ISSUE_TO_LIST_FAILURE, { list, issueId: issueInput.id }));
},
setActiveBoardItemLabels: ({ dispatch }, params) => {
dispatch('setActiveIssueLabels', params);
},
setActiveIssueLabels: async ({ commit, getters }, input) => {
const { activeIssue } = getters;
const { activeBoardItem } = getters;
const { data } = await gqlClient.mutate({
mutation: issueSetLabelsMutation,
variables: {
input: {
iid: String(activeIssue.iid),
iid: String(activeBoardItem.iid),
addLabelIds: input.addLabelIds ?? [],
removeLabelIds: input.removeLabelIds ?? [],
projectPath: input.projectPath,
......@@ -465,20 +469,20 @@ export default {
throw new Error(data.updateIssue.errors);
}
commit(types.UPDATE_ISSUE_BY_ID, {
issueId: activeIssue.id,
commit(types.UPDATE_BOARD_ITEM_BY_ID, {
itemId: activeBoardItem.id,
prop: 'labels',
value: data.updateIssue.issue.labels.nodes,
});
},
setActiveIssueDueDate: async ({ commit, getters }, input) => {
const { activeIssue } = getters;
const { activeBoardItem } = getters;
const { data } = await gqlClient.mutate({
mutation: issueSetDueDateMutation,
variables: {
input: {
iid: String(activeIssue.iid),
iid: String(activeBoardItem.iid),
projectPath: input.projectPath,
dueDate: input.dueDate,
},
......@@ -489,8 +493,8 @@ export default {
throw new Error(data.updateIssue.errors);
}
commit(types.UPDATE_ISSUE_BY_ID, {
issueId: activeIssue.id,
commit(types.UPDATE_BOARD_ITEM_BY_ID, {
itemId: activeBoardItem.id,
prop: 'dueDate',
value: data.updateIssue.issue.dueDate,
});
......@@ -501,7 +505,7 @@ export default {
mutation: issueSetSubscriptionMutation,
variables: {
input: {
iid: String(getters.activeIssue.iid),
iid: String(getters.activeBoardItem.iid),
projectPath: input.projectPath,
subscribedState: input.subscribed,
},
......@@ -512,20 +516,20 @@ export default {
throw new Error(data.issueSetSubscription.errors);
}
commit(types.UPDATE_ISSUE_BY_ID, {
issueId: getters.activeIssue.id,
commit(types.UPDATE_BOARD_ITEM_BY_ID, {
itemId: getters.activeBoardItem.id,
prop: 'subscribed',
value: data.issueSetSubscription.issue.subscribed,
});
},
setActiveIssueTitle: async ({ commit, getters }, input) => {
const { activeIssue } = getters;
const { activeBoardItem } = getters;
const { data } = await gqlClient.mutate({
mutation: issueSetTitleMutation,
variables: {
input: {
iid: String(activeIssue.iid),
iid: String(activeBoardItem.iid),
projectPath: input.projectPath,
title: input.title,
},
......@@ -536,8 +540,8 @@ export default {
throw new Error(data.updateIssue.errors);
}
commit(types.UPDATE_ISSUE_BY_ID, {
issueId: activeIssue.id,
commit(types.UPDATE_BOARD_ITEM_BY_ID, {
itemId: activeBoardItem.id,
prop: 'title',
value: data.updateIssue.issue.title,
});
......@@ -578,10 +582,10 @@ export default {
const { selectedBoardItems } = state;
const index = selectedBoardItems.indexOf(boardItem);
// If user already selected an item (activeIssue) without using mult-select,
// If user already selected an item (activeBoardItem) without using mult-select,
// include that item in the selection and unset state.ActiveId to hide the sidebar.
if (getters.activeIssue) {
commit(types.ADD_BOARD_ITEM_TO_SELECTION, getters.activeIssue);
if (getters.activeBoardItem) {
commit(types.ADD_BOARD_ITEM_TO_SELECTION, getters.activeBoardItem);
dispatch('unsetActiveId');
}
......
......@@ -15,17 +15,17 @@ export default {
return listItemsIds.map((id) => getters.getBoardItemById(id));
},
activeIssue: (state) => {
activeBoardItem: (state) => {
return state.boardItems[state.activeId] || {};
},
groupPathForActiveIssue: (_, getters) => {
const { referencePath = '' } = getters.activeIssue;
const { referencePath = '' } = getters.activeBoardItem;
return referencePath.slice(0, referencePath.indexOf('/'));
},
projectPathForActiveIssue: (_, getters) => {
const { referencePath = '' } = getters.activeIssue;
const { referencePath = '' } = getters.activeBoardItem;
return referencePath.slice(0, referencePath.indexOf('#'));
},
......
......@@ -36,7 +36,7 @@ export const REMOVE_ISSUE_FROM_LIST = 'REMOVE_ISSUE_FROM_LIST';
export const SET_CURRENT_PAGE = 'SET_CURRENT_PAGE';
export const TOGGLE_EMPTY_STATE = 'TOGGLE_EMPTY_STATE';
export const SET_ACTIVE_ID = 'SET_ACTIVE_ID';
export const UPDATE_ISSUE_BY_ID = 'UPDATE_ISSUE_BY_ID';
export const UPDATE_BOARD_ITEM_BY_ID = 'UPDATE_BOARD_ITEM_BY_ID';
export const SET_ASSIGNEE_LOADING = 'SET_ASSIGNEE_LOADING';
export const RESET_ISSUES = 'RESET_ISSUES';
export const REQUEST_GROUP_PROJECTS = 'REQUEST_GROUP_PROJECTS';
......
......@@ -158,13 +158,13 @@ export default {
});
},
[mutationTypes.UPDATE_ISSUE_BY_ID]: (state, { issueId, prop, value }) => {
if (!state.boardItems[issueId]) {
[mutationTypes.UPDATE_BOARD_ITEM_BY_ID]: (state, { itemId, prop, value }) => {
if (!state.boardItems[itemId]) {
/* eslint-disable-next-line @gitlab/require-i18n-strings */
throw new Error('No issue found.');
}
Vue.set(state.boardItems[issueId], prop, value);
Vue.set(state.boardItems[itemId], prop, value);
},
[mutationTypes.SET_ASSIGNEE_LOADING](state, isLoading) {
......
......@@ -365,7 +365,7 @@
margin: 5px;
}
.right-sidebar.issue-boards-sidebar {
.right-sidebar.boards-sidebar {
.gutter-toggle {
bottom: 15px;
width: 22px;
......@@ -462,7 +462,7 @@
overflow-x: scroll;
}
.issue-boards-sidebar {
.boards-sidebar {
height: 100%;
top: 0;
}
......
......@@ -287,7 +287,7 @@
padding-top: 10px;
}
&:not(.issue-boards-sidebar):not([data-signed-in]):not([data-always-show-toggle]) {
&:not(.boards-sidebar):not([data-signed-in]):not([data-always-show-toggle]) {
.issuable-sidebar-header {
display: none;
}
......
%board-sidebar{ "inline-template" => true, ":current-user" => (UserSerializer.new.represent(current_user) || {}).to_json }
%transition{ name: "boards-sidebar-slide" }
%aside.right-sidebar.right-sidebar-expanded.issue-boards-sidebar{ "v-show" => "showSidebar", 'aria-label': s_('Boards|Board') }
%aside.right-sidebar.right-sidebar-expanded.boards-sidebar{ "v-show" => "showSidebar", 'aria-label': s_('Boards|Board'), 'data-testid': 'issue-boards-sidebar' }
.issuable-sidebar
.block.issuable-sidebar-header.position-relative
%span.issuable-header-text.hide-collapsed.float-left
......
<script>
import { GlDrawer } from '@gitlab/ui';
import { mapState, mapActions, mapGetters } from 'vuex';
import BoardSidebarLabelsSelect from '~/boards/components/sidebar/board_sidebar_labels_select.vue';
import { ISSUABLE } from '~/boards/constants';
import { contentTop } from '~/lib/utils/common_utils';
export default {
headerHeight: `${contentTop()}px`,
components: {
GlDrawer,
BoardSidebarLabelsSelect,
},
computed: {
...mapGetters(['isSidebarOpen', 'activeBoardItem']),
...mapState(['sidebarType']),
isIssuableSidebar() {
return this.sidebarType === ISSUABLE;
},
showSidebar() {
return this.isIssuableSidebar && this.isSidebarOpen;
},
},
methods: {
...mapActions(['toggleBoardItem']),
handleClose() {
this.toggleBoardItem({ boardItem: this.activeBoardItem, sidebarType: this.sidebarType });
},
},
};
</script>
<template>
<gl-drawer
v-if="showSidebar"
:open="isSidebarOpen"
:header-height="$options.headerHeight"
@close="handleClose"
>
<template #header>{{ __('Epic details') }}</template>
<template #default>
<board-sidebar-labels-select class="labels" />
</template>
</gl-drawer>
</template>
......@@ -26,9 +26,9 @@ export default {
inject: ['groupId'],
computed: {
...mapState(['epics', 'epicsCacheById', 'epicFetchInProgress']),
...mapGetters(['activeIssue', 'projectPathForActiveIssue']),
...mapGetters(['activeBoardItem', 'projectPathForActiveIssue']),
epic() {
return this.activeIssue.epic;
return this.activeBoardItem.epic;
},
epicData() {
const hasEpic = this.epic !== null;
......
......@@ -23,13 +23,13 @@ export default {
};
},
computed: {
...mapGetters(['activeIssue', 'projectPathForActiveIssue']),
...mapGetters(['activeBoardItem', 'projectPathForActiveIssue']),
hasWeight() {
return this.activeIssue.weight > 0;
return this.activeBoardItem.weight > 0;
},
},
watch: {
activeIssue: {
activeBoardItem: {
handler(updatedIssue) {
this.weight = updatedIssue.weight;
},
......@@ -45,7 +45,7 @@ export default {
async setWeight(provided) {
const weight = provided ?? this.weight;
if (this.loading || weight === this.activeIssue.weight) {
if (this.loading || weight === this.activeBoardItem.weight) {
return;
}
......@@ -55,7 +55,7 @@ export default {
await this.setActiveIssueWeight({ weight, projectPath: this.projectPathForActiveIssue });
this.weight = weight;
} catch (e) {
this.weight = this.activeIssue.weight;
this.weight = this.activeBoardItem.weight;
createFlash({ message: __('An error occurred when updating the issue weight') });
} finally {
this.loading = false;
......@@ -77,7 +77,7 @@ export default {
<strong
class="gl-text-gray-900 js-weight-weight-label-value"
data-qa-selector="weight_label_value"
>{{ activeIssue.weight }}</strong
>{{ activeBoardItem.weight }}</strong
>
<span class="gl-mx-2">-</span>
<gl-button
......
mutation updateEpic($input: UpdateEpicInput!) {
updateEpic(input: $input) {
epic {
id
labels {
nodes {
id
title
color
description
}
}
}
errors
}
}
......@@ -46,6 +46,7 @@ import projectBoardAssigneesQuery from '../graphql/project_board_assignees.query
import projectBoardIterationsQuery from '../graphql/project_board_iterations.query.graphql';
import projectBoardMilestonesQuery from '../graphql/project_board_milestones.query.graphql';
import updateBoardEpicUserPreferencesMutation from '../graphql/update_board_epic_user_preferences.mutation.graphql';
import updateEpicLabelsMutation from '../graphql/update_epic_labels.mutation.graphql';
import boardsStoreEE from './boards_store_ee';
import * as types from './mutation_types';
......@@ -379,13 +380,13 @@ export default {
},
fetchEpicForActiveIssue: async ({ state, commit, getters }) => {
if (!getters.activeIssue.epic) {
if (!getters.activeBoardItem.epic) {
return false;
}
const {
epic: { id, iid },
} = getters.activeIssue;
} = getters.activeBoardItem;
if (state.epicsCacheById[id]) {
return false;
......@@ -421,7 +422,7 @@ export default {
mutation: issueSetEpicMutation,
variables: {
input: {
iid: String(getters.activeIssue.iid),
iid: String(getters.activeBoardItem.iid),
epicId,
projectPath: getters.projectPathForActiveIssue,
},
......@@ -439,8 +440,8 @@ export default {
commit(types.UPDATE_CACHED_EPICS, [epic]);
}
commit(typesCE.UPDATE_ISSUE_BY_ID, {
issueId: getters.activeIssue.id,
commit(typesCE.UPDATE_BOARD_ITEM_BY_ID, {
itemId: getters.activeBoardItem.id,
prop: 'epic',
value: epic ? { id: epic.id, iid: epic.iid } : null,
});
......@@ -452,7 +453,7 @@ export default {
mutation: issueSetWeightMutation,
variables: {
input: {
iid: String(getters.activeIssue.iid),
iid: String(getters.activeBoardItem.iid),
weight: input.weight,
projectPath: input.projectPath,
},
......@@ -463,8 +464,8 @@ export default {
throw new Error(data.issueSetWeight?.errors);
}
commit(typesCE.UPDATE_ISSUE_BY_ID, {
issueId: getters.activeIssue.id,
commit(typesCE.UPDATE_BOARD_ITEM_BY_ID, {
itemId: getters.activeBoardItem.id,
prop: 'weight',
value: data.issueSetWeight.issue.weight,
});
......@@ -765,4 +766,37 @@ export default {
throw e;
});
},
setActiveBoardItemLabels: ({ getters, dispatch }, params) => {
if (!getters.isEpicBoard) {
dispatch('setActiveIssueLabels', params);
} else {
dispatch('setActiveEpicLabels', params);
}
},
setActiveEpicLabels: async ({ commit, getters, state }, input) => {
const { activeBoardItem } = getters;
const { data } = await gqlClient.mutate({
mutation: updateEpicLabelsMutation,
variables: {
input: {
iid: String(activeBoardItem.iid),
addLabelIds: input.addLabelIds ?? [],
removeLabelIds: input.removeLabelIds ?? [],
groupPath: state.fullPath,
},
},
});
if (data.updateEpic?.errors?.length > 0) {
throw new Error(data.updateEpic.errors);
}
commit(typesCE.UPDATE_BOARD_ITEM_BY_ID, {
itemId: activeBoardItem.id,
prop: 'labels',
value: data.updateEpic.epic.labels.nodes,
});
},
};
......@@ -36,7 +36,7 @@ RSpec.describe 'Issue Boards new issue', :js do
find('.board-card').click
end
page.within(first('.issue-boards-sidebar')) do
page.within(first('[data-testid="issue-boards-sidebar"]')) do
find('.weight [data-testid="edit-button"]').click
find('.weight .form-control').set("10\n")
end
......
# frozen_string_literal: true
require 'spec_helper'
RSpec.describe 'Epic boards sidebar', :js do
include BoardHelpers
let_it_be(:user) { create(:user) }
let_it_be(:group) { create(:group, :public) }
let_it_be(:bug) { create(:group_label, group: group, name: 'Bug') }
let_it_be(:epic_board) { create(:epic_board, group: group) }
let_it_be(:backlog_list) { create(:epic_list, epic_board: epic_board, list_type: :backlog) }
let_it_be(:closed_list) { create(:epic_list, epic_board: epic_board, list_type: :closed) }
let_it_be(:epic1) { create(:epic, group: group, title: 'Epic1') }
let(:card) { find('.board:nth-child(1)').first("[data-testid='board_card']") }
before do
stub_licensed_features(epics: true)
group.add_maintainer(user)
sign_in(user)
visit group_epic_boards_path(group)
wait_for_requests
end
it 'shows sidebar when clicking epic' do
click_card(card)
expect(page).to have_selector('[data-testid="epic-boards-sidebar"]')
end
it 'closes sidebar when clicking epic' do
click_card(card)
expect(page).to have_selector('[data-testid="epic-boards-sidebar"]')
click_card(card)
expect(page).not_to have_selector('[data-testid="epic-boards-sidebar"]')
end
it 'closes sidebar when clicking close button' do
click_card(card)
expect(page).to have_selector('[data-testid="epic-boards-sidebar"]')
find('[data-testid="close-icon"]').click
expect(page).not_to have_selector('[data-testid="epic-boards-sidebar"]')
end
context 'labels' do
it 'adds a single label' do
click_card(card)
page.within('.labels') do
click_button 'Edit'
wait_for_requests
click_link bug.title
find('[data-testid="close-icon"]').click
wait_for_requests
page.within('.value') do
expect(page).to have_selector('.gl-label-text', count: 1)
expect(page).to have_content(bug.title)
end
end
expect(card).to have_selector('.gl-label', count: 1)
expect(card).to have_content(bug.title)
end
end
end
......@@ -20,7 +20,7 @@ describe('ee/BoardContentSidebar', () => {
issuableType: issuableTypes.issue,
},
getters: {
activeIssue: () => {
activeBoardItem: () => {
return { ...mockIssue, epic: null };
},
projectPathForActiveIssue: () => mockIssueProjectPath,
......
import { GlDrawer } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import Vuex from 'vuex';
import EpicBoardContentSidebar from 'ee_component/boards/components/epic_board_content_sidebar.vue';
import { stubComponent } from 'helpers/stub_component';
import BoardSidebarLabelsSelect from '~/boards/components/sidebar/board_sidebar_labels_select.vue';
import { ISSUABLE } from '~/boards/constants';
import { mockEpic } from '../mock_data';
describe('EpicBoardContentSidebar', () => {
let wrapper;
let store;
const createStore = ({ mockGetters = {}, mockActions = {} } = {}) => {
store = new Vuex.Store({
state: {
sidebarType: ISSUABLE,
boardItems: { [mockEpic.id]: mockEpic },
activeId: mockEpic.id,
issuableType: 'epic',
},
getters: {
activeBoardItem: () => {
return mockEpic;
},
isSidebarOpen: () => true,
...mockGetters,
},
actions: mockActions,
});
};
const createComponent = () => {
wrapper = shallowMount(EpicBoardContentSidebar, {
provide: {
canUpdate: true,
rootPath: '/',
groupId: 1,
},
store,
stubs: {
GlDrawer: stubComponent(GlDrawer, {
template: '<div><slot name="header"></slot><slot></slot></div>',
}),
},
});
};
beforeEach(() => {
createStore();
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
it('confirms we render GlDrawer', () => {
expect(wrapper.find(GlDrawer).exists()).toBe(true);
});
it('does not render GlDrawer when isSidebarOpen is false', () => {
createStore({ mockGetters: { isSidebarOpen: () => false } });
createComponent();
expect(wrapper.find(GlDrawer).exists()).toBe(false);
});
it('applies an open attribute', () => {
expect(wrapper.find(GlDrawer).props('open')).toBe(true);
});
it('renders BoardSidebarLabelsSelect', () => {
expect(wrapper.find(BoardSidebarLabelsSelect).exists()).toBe(true);
});
describe('when we emit close', () => {
let toggleBoardItem;
beforeEach(() => {
toggleBoardItem = jest.fn();
createStore({ mockActions: { toggleBoardItem } });
createComponent();
});
it('calls toggleBoardItem with correct parameters', async () => {
wrapper.find(GlDrawer).vm.$emit('close');
expect(toggleBoardItem).toHaveBeenCalledTimes(1);
expect(toggleBoardItem).toHaveBeenCalledWith(expect.any(Object), {
boardItem: mockEpic,
sidebarType: ISSUABLE,
});
});
});
});
......@@ -115,7 +115,7 @@ export const mockIterations = [
},
];
const labels = [
export const labels = [
{
id: 'gid://gitlab/GroupLabel/5',
title: 'Cosync',
......
......@@ -15,6 +15,7 @@ import * as typesCE from '~/boards/stores/mutation_types';
import * as commonUtils from '~/lib/utils/common_utils';
import { mergeUrlParams, removeParams } from '~/lib/utils/url_utility';
import {
labels,
mockLists,
mockIssue,
mockIssue2,
......@@ -578,7 +579,7 @@ describe('fetchEpicForActiveIssue', () => {
};
describe("when active issue doesn't have an assigned epic", () => {
const getters = { activeIssue: { ...mockIssue, epic: null } };
const getters = { activeBoardItem: { ...mockIssue, epic: null } };
it('should not fetch any epic', async () => {
await testAction(actions.fetchEpicForActiveIssue, undefined, { ...getters }, [], []);
......@@ -586,7 +587,7 @@ describe('fetchEpicForActiveIssue', () => {
});
describe('when the assigned epic for active issue is found in state.epicsCacheById', () => {
const getters = { activeIssue: { ...mockIssue, epic: assignedEpic } };
const getters = { activeBoardItem: { ...mockIssue, epic: assignedEpic } };
const state = { epicsCacheById: { [assignedEpic.id]: assignedEpic } };
it('should not fetch any epic', async () => {
......@@ -601,7 +602,7 @@ describe('fetchEpicForActiveIssue', () => {
});
describe('when fetching fails', () => {
const getters = { activeIssue: { ...mockIssue, epic: assignedEpic } };
const getters = { activeBoardItem: { ...mockIssue, epic: assignedEpic } };
const state = { epicsCacheById: {} };
it('should not commit UPDATE_CACHED_EPICS mutation and should throw an error', () => {
......@@ -630,7 +631,7 @@ describe('fetchEpicForActiveIssue', () => {
});
describe("when the assigned epic for active issue isn't found in state.epicsCacheById", () => {
const getters = { activeIssue: { ...mockIssue, epic: assignedEpic } };
const getters = { activeBoardItem: { ...mockIssue, epic: assignedEpic } };
const state = { epicsCacheById: {} };
it('should commit mutation SET_EPIC_FETCH_IN_PROGRESS before and after committing mutation UPDATE_CACHED_EPICS', async () => {
......@@ -664,7 +665,7 @@ describe('setActiveIssueEpic', () => {
const state = {
epics: [{ id: 'gid://gitlab/Epic/422', iid: 99, title: 'existing epic' }],
};
const getters = { activeIssue: { ...mockIssue, projectPath: 'h/b' } };
const getters = { activeBoardItem: { ...mockIssue, projectPath: 'h/b' } };
const epicWithData = {
id: 'gid://gitlab/Epic/42',
iid: 1,
......@@ -672,7 +673,7 @@ describe('setActiveIssueEpic', () => {
};
describe('when the updated issue has an assigned epic', () => {
it('should commit mutation RECEIVE_EPICS_SUCCESS, UPDATE_CACHED_EPICS and UPDATE_ISSUE_BY_ID on success', async () => {
it('should commit mutation RECEIVE_EPICS_SUCCESS, UPDATE_CACHED_EPICS and UPDATE_BOARD_ITEM_BY_ID on success', async () => {
jest
.spyOn(gqlClient, 'mutate')
.mockResolvedValue({ data: { issueSetEpic: { issue: { epic: epicWithData } } } });
......@@ -695,9 +696,9 @@ describe('setActiveIssueEpic', () => {
payload: [epicWithData],
},
{
type: typesCE.UPDATE_ISSUE_BY_ID,
type: typesCE.UPDATE_BOARD_ITEM_BY_ID,
payload: {
issueId: mockIssue.id,
itemId: mockIssue.id,
prop: 'epic',
value: { id: epicWithData.id, iid: epicWithData.iid },
},
......@@ -713,7 +714,7 @@ describe('setActiveIssueEpic', () => {
});
describe('when the updated issue does not have an epic (unassigned)', () => {
it('should only commit UPDATE_ISSUE_BY_ID on success', async () => {
it('should only commit UPDATE_BOARD_ITEM_BY_ID on success', async () => {
jest
.spyOn(gqlClient, 'mutate')
.mockResolvedValue({ data: { issueSetEpic: { issue: { epic: null } } } });
......@@ -728,8 +729,8 @@ describe('setActiveIssueEpic', () => {
payload: true,
},
{
type: typesCE.UPDATE_ISSUE_BY_ID,
payload: { issueId: mockIssue.id, prop: 'epic', value: null },
type: typesCE.UPDATE_BOARD_ITEM_BY_ID,
payload: { itemId: mockIssue.id, prop: 'epic', value: null },
},
{
type: types.SET_EPIC_FETCH_IN_PROGRESS,
......@@ -752,7 +753,7 @@ describe('setActiveIssueEpic', () => {
describe('setActiveIssueWeight', () => {
const state = { boardItems: { [mockIssue.id]: mockIssue } };
const getters = { activeIssue: mockIssue };
const getters = { activeBoardItem: mockIssue };
const testWeight = mockIssue.weight + 1;
const input = {
weight: testWeight,
......@@ -772,7 +773,7 @@ describe('setActiveIssueWeight', () => {
});
const payload = {
issueId: getters.activeIssue.id,
itemId: getters.activeBoardItem.id,
prop: 'weight',
value: testWeight,
};
......@@ -783,7 +784,7 @@ describe('setActiveIssueWeight', () => {
{ ...state, ...getters },
[
{
type: typesCE.UPDATE_ISSUE_BY_ID,
type: typesCE.UPDATE_BOARD_ITEM_BY_ID,
payload,
},
],
......@@ -1367,3 +1368,48 @@ describe('fetchAssignees', () => {
});
});
});
describe('setActiveEpicLabels', () => {
const state = { boardItems: { [mockEpic.id]: mockEpic } };
const getters = { activeBoardItem: mockEpic };
const testLabelIds = labels.map((label) => label.id);
const input = {
addLabelIds: testLabelIds,
removeLabelIds: [],
groupPath: 'h/b',
};
it('should assign labels on success', (done) => {
jest
.spyOn(gqlClient, 'mutate')
.mockResolvedValue({ data: { updateEpic: { epic: { labels: { nodes: labels } } } } });
const payload = {
itemId: getters.activeBoardItem.id,
prop: 'labels',
value: labels,
};
testAction(
actions.setActiveEpicLabels,
input,
{ ...state, ...getters },
[
{
type: typesCE.UPDATE_BOARD_ITEM_BY_ID,
payload,
},
],
[],
done,
);
});
it('throws error if fails', async () => {
jest
.spyOn(gqlClient, 'mutate')
.mockResolvedValue({ data: { updateEpic: { errors: ['failed mutation'] } } });
await expect(actions.setActiveEpicLabels({ getters }, input)).rejects.toThrow(Error);
});
});
......@@ -12108,6 +12108,9 @@ msgstr ""
msgid "Epic cannot be found."
msgstr ""
msgid "Epic details"
msgstr ""
msgid "Epic events"
msgstr ""
......
......@@ -90,7 +90,7 @@ RSpec.describe 'Issue Boards new issue', :js do
wait_for_requests
expect(page).to have_selector('.issue-boards-sidebar')
expect(page).to have_selector('[data-testid="issue-boards-sidebar"]')
end
it 'successfuly loads labels to be added to newly created issue' do
......@@ -109,7 +109,7 @@ RSpec.describe 'Issue Boards new issue', :js do
find('.board-card').click
end
page.within(first('.issue-boards-sidebar')) do
page.within(first('[data-testid="issue-boards-sidebar"]')) do
find('.labels [data-testid="edit-button"]').click
wait_for_requests
......
......@@ -24,7 +24,7 @@ describe('BoardContentSidebar', () => {
issuableType: 'issue',
},
getters: {
activeIssue: () => {
activeBoardItem: () => {
return { ...mockIssue, epic: null };
},
groupPathForActiveIssue: () => mockIssueGroupPath,
......
......@@ -64,7 +64,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
beforeEach(async () => {
createWrapper();
jest.spyOn(wrapper.vm, 'setActiveIssueLabels').mockImplementation(() => TEST_LABELS);
jest.spyOn(wrapper.vm, 'setActiveBoardItemLabels').mockImplementation(() => TEST_LABELS);
findLabelsSelect().vm.$emit('updateSelectedLabels', TEST_LABELS_PAYLOAD);
store.state.boardItems[TEST_ISSUE.id].labels = TEST_LABELS;
await wrapper.vm.$nextTick();
......@@ -76,7 +76,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
});
it('commits change to the server', () => {
expect(wrapper.vm.setActiveIssueLabels).toHaveBeenCalledWith({
expect(wrapper.vm.setActiveBoardItemLabels).toHaveBeenCalledWith({
addLabelIds: TEST_LABELS.map((label) => label.id),
projectPath: 'gitlab-org/test-subgroup/gitlab-test',
removeLabelIds: [],
......@@ -94,13 +94,13 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
beforeEach(async () => {
createWrapper({ labels: TEST_LABELS });
jest.spyOn(wrapper.vm, 'setActiveIssueLabels').mockImplementation(() => expectedLabels);
jest.spyOn(wrapper.vm, 'setActiveBoardItemLabels').mockImplementation(() => expectedLabels);
findLabelsSelect().vm.$emit('updateSelectedLabels', testLabelsPayload);
await wrapper.vm.$nextTick();
});
it('commits change to the server', () => {
expect(wrapper.vm.setActiveIssueLabels).toHaveBeenCalledWith({
expect(wrapper.vm.setActiveBoardItemLabels).toHaveBeenCalledWith({
addLabelIds: [5, 7],
removeLabelIds: [6],
projectPath: 'gitlab-org/test-subgroup/gitlab-test',
......@@ -114,13 +114,13 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
beforeEach(async () => {
createWrapper({ labels: [testLabel] });
jest.spyOn(wrapper.vm, 'setActiveIssueLabels').mockImplementation(() => {});
jest.spyOn(wrapper.vm, 'setActiveBoardItemLabels').mockImplementation(() => {});
});
it('commits change to the server', () => {
wrapper.find(GlLabel).vm.$emit('close', testLabel);
expect(wrapper.vm.setActiveIssueLabels).toHaveBeenCalledWith({
expect(wrapper.vm.setActiveBoardItemLabels).toHaveBeenCalledWith({
removeLabelIds: [getIdFromGraphQLId(testLabel.id)],
projectPath: 'gitlab-org/test-subgroup/gitlab-test',
});
......@@ -131,7 +131,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => {
beforeEach(async () => {
createWrapper({ labels: TEST_LABELS });
jest.spyOn(wrapper.vm, 'setActiveIssueLabels').mockImplementation(() => {
jest.spyOn(wrapper.vm, 'setActiveBoardItemLabels').mockImplementation(() => {
throw new Error(['failed mutation']);
});
findLabelsSelect().vm.$emit('updateSelectedLabels', [{ id: '?' }]);
......
......@@ -20,10 +20,10 @@ describe('~/boards/components/sidebar/board_sidebar_subscription_spec.vue', () =
const findToggle = () => wrapper.find(GlToggle);
const findGlLoadingIcon = () => wrapper.find(GlLoadingIcon);
const createComponent = (activeIssue = { ...mockActiveIssue }) => {
const createComponent = (activeBoardItem = { ...mockActiveIssue }) => {
store = createStore();
store.state.boardItems = { [activeIssue.id]: activeIssue };
store.state.activeId = activeIssue.id;
store.state.boardItems = { [activeBoardItem.id]: activeBoardItem };
store.state.activeId = activeBoardItem.id;
wrapper = mount(BoardSidebarSubscription, {
localVue,
......@@ -91,8 +91,8 @@ describe('~/boards/components/sidebar/board_sidebar_subscription_spec.vue', () =
describe('Board sidebar subscription component `behavior`', () => {
const mockSetActiveIssueSubscribed = (subscribedState) => {
jest.spyOn(wrapper.vm, 'setActiveIssueSubscribed').mockImplementation(async () => {
store.commit(types.UPDATE_ISSUE_BY_ID, {
issueId: mockActiveIssue.id,
store.commit(types.UPDATE_BOARD_ITEM_BY_ID, {
itemId: mockActiveIssue.id,
prop: 'subscribed',
value: subscribedState,
});
......
......@@ -802,11 +802,11 @@ describe('setAssignees', () => {
testAction(
actions.setAssignees,
[node],
{ activeIssue: { iid, referencePath: refPath }, commit: () => {} },
{ activeBoardItem: { iid, referencePath: refPath }, commit: () => {} },
[
{
type: 'UPDATE_ISSUE_BY_ID',
payload: { prop: 'assignees', issueId: undefined, value: [node] },
type: 'UPDATE_BOARD_ITEM_BY_ID',
payload: { prop: 'assignees', itemId: undefined, value: [node] },
},
],
[],
......@@ -949,7 +949,7 @@ describe('addListIssue', () => {
describe('setActiveIssueLabels', () => {
const state = { boardItems: { [mockIssue.id]: mockIssue } };
const getters = { activeIssue: mockIssue };
const getters = { activeBoardItem: mockIssue };
const testLabelIds = labels.map((label) => label.id);
const input = {
addLabelIds: testLabelIds,
......@@ -963,7 +963,7 @@ describe('setActiveIssueLabels', () => {
.mockResolvedValue({ data: { updateIssue: { issue: { labels: { nodes: labels } } } } });
const payload = {
issueId: getters.activeIssue.id,
itemId: getters.activeBoardItem.id,
prop: 'labels',
value: labels,
};
......@@ -974,7 +974,7 @@ describe('setActiveIssueLabels', () => {
{ ...state, ...getters },
[
{
type: types.UPDATE_ISSUE_BY_ID,
type: types.UPDATE_BOARD_ITEM_BY_ID,
payload,
},
],
......@@ -994,7 +994,7 @@ describe('setActiveIssueLabels', () => {
describe('setActiveIssueDueDate', () => {
const state = { boardItems: { [mockIssue.id]: mockIssue } };
const getters = { activeIssue: mockIssue };
const getters = { activeBoardItem: mockIssue };
const testDueDate = '2020-02-20';
const input = {
dueDate: testDueDate,
......@@ -1014,7 +1014,7 @@ describe('setActiveIssueDueDate', () => {
});
const payload = {
issueId: getters.activeIssue.id,
itemId: getters.activeBoardItem.id,
prop: 'dueDate',
value: testDueDate,
};
......@@ -1025,7 +1025,7 @@ describe('setActiveIssueDueDate', () => {
{ ...state, ...getters },
[
{
type: types.UPDATE_ISSUE_BY_ID,
type: types.UPDATE_BOARD_ITEM_BY_ID,
payload,
},
],
......@@ -1045,7 +1045,7 @@ describe('setActiveIssueDueDate', () => {
describe('setActiveIssueSubscribed', () => {
const state = { boardItems: { [mockActiveIssue.id]: mockActiveIssue } };
const getters = { activeIssue: mockActiveIssue };
const getters = { activeBoardItem: mockActiveIssue };
const subscribedState = true;
const input = {
subscribedState,
......@@ -1065,7 +1065,7 @@ describe('setActiveIssueSubscribed', () => {
});
const payload = {
issueId: getters.activeIssue.id,
itemId: getters.activeBoardItem.id,
prop: 'subscribed',
value: subscribedState,
};
......@@ -1076,7 +1076,7 @@ describe('setActiveIssueSubscribed', () => {
{ ...state, ...getters },
[
{
type: types.UPDATE_ISSUE_BY_ID,
type: types.UPDATE_BOARD_ITEM_BY_ID,
payload,
},
],
......@@ -1096,7 +1096,7 @@ describe('setActiveIssueSubscribed', () => {
describe('setActiveIssueMilestone', () => {
const state = { boardItems: { [mockIssue.id]: mockIssue } };
const getters = { activeIssue: mockIssue };
const getters = { activeBoardItem: mockIssue };
const testMilestone = {
...mockMilestone,
id: 'gid://gitlab/Milestone/1',
......@@ -1119,7 +1119,7 @@ describe('setActiveIssueMilestone', () => {
});
const payload = {
issueId: getters.activeIssue.id,
itemId: getters.activeBoardItem.id,
prop: 'milestone',
value: testMilestone,
};
......@@ -1130,7 +1130,7 @@ describe('setActiveIssueMilestone', () => {
{ ...state, ...getters },
[
{
type: types.UPDATE_ISSUE_BY_ID,
type: types.UPDATE_BOARD_ITEM_BY_ID,
payload,
},
],
......@@ -1150,7 +1150,7 @@ describe('setActiveIssueMilestone', () => {
describe('setActiveIssueTitle', () => {
const state = { boardItems: { [mockIssue.id]: mockIssue } };
const getters = { activeIssue: mockIssue };
const getters = { activeBoardItem: mockIssue };
const testTitle = 'Test Title';
const input = {
title: testTitle,
......@@ -1170,7 +1170,7 @@ describe('setActiveIssueTitle', () => {
});
const payload = {
issueId: getters.activeIssue.id,
itemId: getters.activeBoardItem.id,
prop: 'title',
value: testTitle,
};
......@@ -1181,7 +1181,7 @@ describe('setActiveIssueTitle', () => {
{ ...state, ...getters },
[
{
type: types.UPDATE_ISSUE_BY_ID,
type: types.UPDATE_BOARD_ITEM_BY_ID,
payload,
},
],
......@@ -1325,7 +1325,7 @@ describe('toggleBoardItemMultiSelection', () => {
testAction(
actions.toggleBoardItemMultiSelection,
boardItem2,
{ activeId: mockActiveIssue.id, activeIssue: mockActiveIssue, selectedBoardItems: [] },
{ activeId: mockActiveIssue.id, activeBoardItem: mockActiveIssue, selectedBoardItems: [] },
[
{
type: types.ADD_BOARD_ITEM_TO_SELECTION,
......
......@@ -88,7 +88,7 @@ describe('Boards - Getters', () => {
});
});
describe('activeIssue', () => {
describe('activeBoardItem', () => {
it.each`
id | expected
${'1'} | ${'issue'}
......@@ -96,7 +96,7 @@ describe('Boards - Getters', () => {
`('returns $expected when $id is passed to state', ({ id, expected }) => {
const state = { boardItems: { 1: 'issue' }, activeId: id };
expect(getters.activeIssue(state)).toEqual(expected);
expect(getters.activeBoardItem(state)).toEqual(expected);
});
});
......@@ -105,14 +105,14 @@ describe('Boards - Getters', () => {
const mockActiveIssue = {
referencePath: 'gitlab-org/gitlab-test#1',
};
expect(getters.groupPathForActiveIssue({}, { activeIssue: mockActiveIssue })).toEqual(
expect(getters.groupPathForActiveIssue({}, { activeBoardItem: mockActiveIssue })).toEqual(
'gitlab-org',
);
});
it('returns empty string as group path when active issue is an empty object', () => {
const mockActiveIssue = {};
expect(getters.groupPathForActiveIssue({}, { activeIssue: mockActiveIssue })).toEqual('');
expect(getters.groupPathForActiveIssue({}, { activeBoardItem: mockActiveIssue })).toEqual('');
});
});
......@@ -121,14 +121,16 @@ describe('Boards - Getters', () => {
const mockActiveIssue = {
referencePath: 'gitlab-org/gitlab-test#1',
};
expect(getters.projectPathForActiveIssue({}, { activeIssue: mockActiveIssue })).toEqual(
expect(getters.projectPathForActiveIssue({}, { activeBoardItem: mockActiveIssue })).toEqual(
'gitlab-org/gitlab-test',
);
});
it('returns empty string as project path when active issue is an empty object', () => {
const mockActiveIssue = {};
expect(getters.projectPathForActiveIssue({}, { activeIssue: mockActiveIssue })).toEqual('');
expect(getters.projectPathForActiveIssue({}, { activeBoardItem: mockActiveIssue })).toEqual(
'',
);
});
});
......
......@@ -335,7 +335,7 @@ describe('Board Store Mutations', () => {
expectNotImplemented(mutations.REQUEST_ADD_ISSUE);
});
describe('UPDATE_ISSUE_BY_ID', () => {
describe('UPDATE_BOARD_ITEM_BY_ID', () => {
const issueId = '1';
const prop = 'id';
const value = '2';
......@@ -353,8 +353,8 @@ describe('Board Store Mutations', () => {
describe('when the issue is in state', () => {
it('updates the property of the correct issue', () => {
mutations.UPDATE_ISSUE_BY_ID(state, {
issueId,
mutations.UPDATE_BOARD_ITEM_BY_ID(state, {
itemId: issueId,
prop,
value,
});
......@@ -366,8 +366,8 @@ describe('Board Store Mutations', () => {
describe('when the issue is not in state', () => {
it('throws an error', () => {
expect(() => {
mutations.UPDATE_ISSUE_BY_ID(state, {
issueId: '3',
mutations.UPDATE_BOARD_ITEM_BY_ID(state, {
itemId: '3',
prop,
value,
});
......
......@@ -8,19 +8,19 @@ RSpec.shared_examples 'issue boards sidebar' do
end
it 'shows sidebar when clicking issue' do
expect(page).to have_selector('.issue-boards-sidebar')
expect(page).to have_selector('[data-testid="issue-boards-sidebar"]')
end
it 'closes sidebar when clicking issue' do
expect(page).to have_selector('.issue-boards-sidebar')
expect(page).to have_selector('[data-testid="issue-boards-sidebar"]')
first_card.click
expect(page).not_to have_selector('.issue-boards-sidebar')
expect(page).not_to have_selector('[data-testid="issue-boards-sidebar"]')
end
it 'shows issue details when sidebar is open', :aggregate_failures do
page.within('.issue-boards-sidebar') do
page.within('[data-testid="issue-boards-sidebar"]') do
expect(page).to have_content(issue.title)
expect(page).to have_content(issue.to_reference)
end
......@@ -28,7 +28,7 @@ RSpec.shared_examples 'issue boards sidebar' do
context 'when clicking close button' do
before do
find("[data-testid='sidebar-drawer'] .gl-drawer-close-button").click
find('[data-testid="issue-boards-sidebar"] .gl-drawer-close-button').click
end
it 'unhighlights the active issue card' do
......@@ -37,7 +37,7 @@ RSpec.shared_examples 'issue boards sidebar' do
end
it 'closes sidebar when clicking close button' do
expect(page).not_to have_selector('.issue-boards-sidebar')
expect(page).not_to have_selector('[data-testid="issue-boards-sidebar"]')
end
end
......
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