Commit 3cd8e1ff authored by Florie Guibert's avatar Florie Guibert

Epic boards sidebar - Edit epic title

Add ability to edit epic title from epic board sidebar
parent 09580cb6
...@@ -2,11 +2,11 @@ ...@@ -2,11 +2,11 @@
import { GlDrawer } from '@gitlab/ui'; import { GlDrawer } from '@gitlab/ui';
import { mapState, mapActions, mapGetters } from 'vuex'; import { mapState, mapActions, mapGetters } from 'vuex';
import BoardSidebarDueDate from '~/boards/components/sidebar/board_sidebar_due_date.vue'; import BoardSidebarDueDate from '~/boards/components/sidebar/board_sidebar_due_date.vue';
import BoardSidebarIssueTitle from '~/boards/components/sidebar/board_sidebar_issue_title.vue';
import BoardSidebarLabelsSelect from '~/boards/components/sidebar/board_sidebar_labels_select.vue'; import BoardSidebarLabelsSelect from '~/boards/components/sidebar/board_sidebar_labels_select.vue';
import BoardSidebarMilestoneSelect from '~/boards/components/sidebar/board_sidebar_milestone_select.vue'; import BoardSidebarMilestoneSelect from '~/boards/components/sidebar/board_sidebar_milestone_select.vue';
import BoardSidebarSubscription from '~/boards/components/sidebar/board_sidebar_subscription.vue'; import BoardSidebarSubscription from '~/boards/components/sidebar/board_sidebar_subscription.vue';
import BoardSidebarTimeTracker from '~/boards/components/sidebar/board_sidebar_time_tracker.vue'; import BoardSidebarTimeTracker from '~/boards/components/sidebar/board_sidebar_time_tracker.vue';
import BoardSidebarTitle from '~/boards/components/sidebar/board_sidebar_title.vue';
import { ISSUABLE } from '~/boards/constants'; import { ISSUABLE } from '~/boards/constants';
import { contentTop } from '~/lib/utils/common_utils'; import { contentTop } from '~/lib/utils/common_utils';
import SidebarAssigneesWidget from '~/sidebar/components/assignees/sidebar_assignees_widget.vue'; import SidebarAssigneesWidget from '~/sidebar/components/assignees/sidebar_assignees_widget.vue';
...@@ -16,7 +16,7 @@ export default { ...@@ -16,7 +16,7 @@ export default {
headerHeight: `${contentTop()}px`, headerHeight: `${contentTop()}px`,
components: { components: {
GlDrawer, GlDrawer,
BoardSidebarIssueTitle, BoardSidebarTitle,
SidebarAssigneesWidget, SidebarAssigneesWidget,
BoardSidebarTimeTracker, BoardSidebarTimeTracker,
BoardSidebarLabelsSelect, BoardSidebarLabelsSelect,
...@@ -67,7 +67,7 @@ export default { ...@@ -67,7 +67,7 @@ export default {
> >
<template #header>{{ __('Issue details') }}</template> <template #header>{{ __('Issue details') }}</template>
<template #default> <template #default>
<board-sidebar-issue-title /> <board-sidebar-title />
<sidebar-assignees-widget <sidebar-assignees-widget
:iid="activeBoardItem.iid" :iid="activeBoardItem.iid"
:full-path="fullPath" :full-path="fullPath"
......
...@@ -27,12 +27,12 @@ export default { ...@@ -27,12 +27,12 @@ export default {
}; };
}, },
computed: { computed: {
...mapGetters({ issue: 'activeBoardItem' }), ...mapGetters({ item: 'activeBoardItem' }),
pendingChangesStorageKey() { pendingChangesStorageKey() {
return this.getPendingChangesKey(this.issue); return this.getPendingChangesKey(this.item);
}, },
projectPath() { projectPath() {
const referencePath = this.issue.referencePath || ''; const referencePath = this.item.referencePath || '';
return referencePath.slice(0, referencePath.indexOf('#')); return referencePath.slice(0, referencePath.indexOf('#'));
}, },
validationState() { validationState() {
...@@ -40,29 +40,29 @@ export default { ...@@ -40,29 +40,29 @@ export default {
}, },
}, },
watch: { watch: {
issue: { item: {
handler(updatedIssue, formerIssue) { handler(updatedItem, formerItem) {
if (formerIssue?.title !== this.title) { if (formerItem?.title !== this.title) {
localStorage.setItem(this.getPendingChangesKey(formerIssue), this.title); localStorage.setItem(this.getPendingChangesKey(formerItem), this.title);
} }
this.title = updatedIssue.title; this.title = updatedItem.title;
this.setPendingState(); this.setPendingState();
}, },
immediate: true, immediate: true,
}, },
}, },
methods: { methods: {
...mapActions(['setActiveIssueTitle']), ...mapActions(['setActiveItemTitle']),
getPendingChangesKey(issue) { getPendingChangesKey(item) {
if (!issue) { if (!item) {
return ''; return '';
} }
return joinPaths( return joinPaths(
window.location.pathname.slice(1), window.location.pathname.slice(1),
String(issue.id), String(item.id),
'issue-title-pending-changes', 'item-title-pending-changes',
); );
}, },
async setPendingState() { async setPendingState() {
...@@ -78,7 +78,7 @@ export default { ...@@ -78,7 +78,7 @@ export default {
} }
}, },
cancel() { cancel() {
this.title = this.issue.title; this.title = this.item.title;
this.$refs.sidebarItem.collapse(); this.$refs.sidebarItem.collapse();
this.showChangesAlert = false; this.showChangesAlert = false;
localStorage.removeItem(this.pendingChangesStorageKey); localStorage.removeItem(this.pendingChangesStorageKey);
...@@ -86,24 +86,24 @@ export default { ...@@ -86,24 +86,24 @@ export default {
async setTitle() { async setTitle() {
this.$refs.sidebarItem.collapse(); this.$refs.sidebarItem.collapse();
if (!this.title || this.title === this.issue.title) { if (!this.title || this.title === this.item.title) {
return; return;
} }
try { try {
this.loading = true; this.loading = true;
await this.setActiveIssueTitle({ title: this.title, projectPath: this.projectPath }); await this.setActiveItemTitle({ title: this.title, projectPath: this.projectPath });
localStorage.removeItem(this.pendingChangesStorageKey); localStorage.removeItem(this.pendingChangesStorageKey);
this.showChangesAlert = false; this.showChangesAlert = false;
} catch (e) { } catch (e) {
this.title = this.issue.title; this.title = this.item.title;
createFlash({ message: this.$options.i18n.updateTitleError }); createFlash({ message: this.$options.i18n.updateTitleError });
} finally { } finally {
this.loading = false; this.loading = false;
} }
}, },
handleOffClick() { handleOffClick() {
if (this.title !== this.issue.title) { if (this.title !== this.item.title) {
this.showChangesAlert = true; this.showChangesAlert = true;
localStorage.setItem(this.pendingChangesStorageKey, this.title); localStorage.setItem(this.pendingChangesStorageKey, this.title);
} else { } else {
...@@ -112,11 +112,11 @@ export default { ...@@ -112,11 +112,11 @@ export default {
}, },
}, },
i18n: { i18n: {
issueTitlePlaceholder: __('Issue title'), titlePlaceholder: __('Title'),
submitButton: __('Save changes'), submitButton: __('Save changes'),
cancelButton: __('Cancel'), cancelButton: __('Cancel'),
updateTitleError: __('An error occurred when updating the issue title'), updateTitleError: __('An error occurred when updating the title'),
invalidFeedback: __('An issue title is required'), invalidFeedback: __('A title is required'),
reviewYourChanges: __('Changes to the title have not been saved'), reviewYourChanges: __('Changes to the title have not been saved'),
}, },
}; };
...@@ -131,10 +131,10 @@ export default { ...@@ -131,10 +131,10 @@ export default {
@off-click="handleOffClick" @off-click="handleOffClick"
> >
<template #title> <template #title>
<span class="gl-font-weight-bold" data-testid="issue-title">{{ issue.title }}</span> <span class="gl-font-weight-bold" data-testid="item-title">{{ item.title }}</span>
</template> </template>
<template #collapsed> <template #collapsed>
<span class="gl-text-gray-800">{{ issue.referencePath }}</span> <span class="gl-text-gray-800">{{ item.referencePath }}</span>
</template> </template>
<gl-alert v-if="showChangesAlert" variant="warning" class="gl-mb-5" :dismissible="false"> <gl-alert v-if="showChangesAlert" variant="warning" class="gl-mb-5" :dismissible="false">
{{ $options.i18n.reviewYourChanges }} {{ $options.i18n.reviewYourChanges }}
...@@ -144,7 +144,7 @@ export default { ...@@ -144,7 +144,7 @@ export default {
<gl-form-input <gl-form-input
v-model="title" v-model="title"
v-autofocusonshow v-autofocusonshow
:placeholder="$options.i18n.issueTitlePlaceholder" :placeholder="$options.i18n.titlePlaceholder"
:state="validationState" :state="validationState"
/> />
</gl-form-group> </gl-form-group>
......
import { __ } from '~/locale'; import { __ } from '~/locale';
import updateEpicTitleMutation from '~/sidebar/queries/update_epic_title.mutation.graphql';
import boardBlockingIssuesQuery from './graphql/board_blocking_issues.query.graphql'; import boardBlockingIssuesQuery from './graphql/board_blocking_issues.query.graphql';
import issueSetTitleMutation from './graphql/issue_set_title.mutation.graphql';
export const issuableTypes = { export const issuableTypes = {
issue: 'issue', issue: 'issue',
...@@ -52,3 +54,12 @@ export const blockingIssuablesQueries = { ...@@ -52,3 +54,12 @@ export const blockingIssuablesQueries = {
query: boardBlockingIssuesQuery, query: boardBlockingIssuesQuery,
}, },
}; };
export const titleQueries = {
[issuableTypes.issue]: {
mutation: issueSetTitleMutation,
},
[issuableTypes.epic]: {
mutation: updateEpicTitleMutation,
},
};
mutation issueSetTitle($input: UpdateIssueInput!) { mutation issueSetTitle($input: UpdateIssueInput!) {
updateIssue(input: $input) { updateIssuableTitle: updateIssue(input: $input) {
issue { issue {
title title
} }
......
...@@ -8,6 +8,7 @@ import { ...@@ -8,6 +8,7 @@ import {
inactiveId, inactiveId,
flashAnimationDuration, flashAnimationDuration,
ISSUABLE, ISSUABLE,
titleQueries,
} from '~/boards/constants'; } from '~/boards/constants';
import { getIdFromGraphQLId } from '~/graphql_shared/utils'; import { getIdFromGraphQLId } from '~/graphql_shared/utils';
import createGqClient, { fetchPolicies } from '~/lib/graphql'; import createGqClient, { fetchPolicies } from '~/lib/graphql';
...@@ -33,7 +34,6 @@ import issueSetDueDateMutation from '../graphql/issue_set_due_date.mutation.grap ...@@ -33,7 +34,6 @@ import issueSetDueDateMutation from '../graphql/issue_set_due_date.mutation.grap
import issueSetLabelsMutation from '../graphql/issue_set_labels.mutation.graphql'; import issueSetLabelsMutation from '../graphql/issue_set_labels.mutation.graphql';
import issueSetMilestoneMutation from '../graphql/issue_set_milestone.mutation.graphql'; import issueSetMilestoneMutation from '../graphql/issue_set_milestone.mutation.graphql';
import issueSetSubscriptionMutation from '../graphql/issue_set_subscription.mutation.graphql'; import issueSetSubscriptionMutation from '../graphql/issue_set_subscription.mutation.graphql';
import issueSetTitleMutation from '../graphql/issue_set_title.mutation.graphql';
import listsIssuesQuery from '../graphql/lists_issues.query.graphql'; import listsIssuesQuery from '../graphql/lists_issues.query.graphql';
import * as types from './mutation_types'; import * as types from './mutation_types';
...@@ -526,27 +526,31 @@ export default { ...@@ -526,27 +526,31 @@ export default {
}); });
}, },
setActiveIssueTitle: async ({ commit, getters }, input) => { setActiveItemTitle: async ({ commit, getters, state }, input) => {
const { activeBoardItem } = getters; const { activeBoardItem, isEpicBoard } = getters;
const { fullPath, issuableType } = state;
const workspacePath = isEpicBoard
? { groupPath: fullPath }
: { projectPath: input.projectPath };
const { data } = await gqlClient.mutate({ const { data } = await gqlClient.mutate({
mutation: issueSetTitleMutation, mutation: titleQueries[issuableType].mutation,
variables: { variables: {
input: { input: {
...workspacePath,
iid: String(activeBoardItem.iid), iid: String(activeBoardItem.iid),
projectPath: input.projectPath,
title: input.title, title: input.title,
}, },
}, },
}); });
if (data.updateIssue?.errors?.length > 0) { if (data.updateIssuableTitle?.errors?.length > 0) {
throw new Error(data.updateIssue.errors); throw new Error(data.updateIssuableTitle.errors);
} }
commit(types.UPDATE_BOARD_ITEM_BY_ID, { commit(types.UPDATE_BOARD_ITEM_BY_ID, {
itemId: activeBoardItem.id, itemId: activeBoardItem.id,
prop: 'title', prop: 'title',
value: data.updateIssue.issue.title, value: data.updateIssuableTitle[issuableType].title,
}); });
}, },
......
mutation updateEpic($input: UpdateEpicInput!) {
updateIssuableTitle: updateEpic(input: $input) {
epic {
title
}
errors
}
}
...@@ -2,6 +2,7 @@ ...@@ -2,6 +2,7 @@
import { GlDrawer } from '@gitlab/ui'; import { GlDrawer } from '@gitlab/ui';
import { mapState, mapActions, mapGetters } from 'vuex'; import { mapState, mapActions, mapGetters } from 'vuex';
import BoardSidebarLabelsSelect from '~/boards/components/sidebar/board_sidebar_labels_select.vue'; import BoardSidebarLabelsSelect from '~/boards/components/sidebar/board_sidebar_labels_select.vue';
import BoardSidebarTitle from '~/boards/components/sidebar/board_sidebar_title.vue';
import { ISSUABLE } from '~/boards/constants'; import { ISSUABLE } from '~/boards/constants';
import { contentTop } from '~/lib/utils/common_utils'; import { contentTop } from '~/lib/utils/common_utils';
...@@ -10,6 +11,7 @@ export default { ...@@ -10,6 +11,7 @@ export default {
components: { components: {
GlDrawer, GlDrawer,
BoardSidebarLabelsSelect, BoardSidebarLabelsSelect,
BoardSidebarTitle,
}, },
computed: { computed: {
...mapGetters(['isSidebarOpen', 'activeBoardItem']), ...mapGetters(['isSidebarOpen', 'activeBoardItem']),
...@@ -39,6 +41,7 @@ export default { ...@@ -39,6 +41,7 @@ export default {
> >
<template #header>{{ __('Epic details') }}</template> <template #header>{{ __('Epic details') }}</template>
<template #default> <template #default>
<board-sidebar-title data-testid="sidebar-title" />
<board-sidebar-labels-select class="labels" /> <board-sidebar-labels-select class="labels" />
</template> </template>
</gl-drawer> </gl-drawer>
......
...@@ -50,6 +50,37 @@ RSpec.describe 'Epic boards sidebar', :js do ...@@ -50,6 +50,37 @@ RSpec.describe 'Epic boards sidebar', :js do
expect(page).not_to have_selector('[data-testid="epic-boards-sidebar"]') expect(page).not_to have_selector('[data-testid="epic-boards-sidebar"]')
end end
it 'shows epic details when sidebar is open', :aggregate_failures do
click_card(card)
page.within('[data-testid="epic-boards-sidebar"]') do
expect(page).to have_content(epic1.title)
expect(page).to have_content(epic1.to_reference)
end
end
context 'title' do
it 'edits epic title' do
click_card(card)
page.within('[data-testid="sidebar-title"]') do
click_button 'Edit'
wait_for_requests
find('input').set('Test title')
click_button 'Save changes'
wait_for_requests
expect(page).to have_content('Test title')
end
expect(card).to have_content('Test title')
end
end
context 'labels' do context 'labels' do
it 'adds a single label' do it 'adds a single label' do
click_card(card) click_card(card)
......
...@@ -3353,10 +3353,10 @@ msgstr "" ...@@ -3353,10 +3353,10 @@ msgstr ""
msgid "An error occurred when updating the issue due date" msgid "An error occurred when updating the issue due date"
msgstr "" msgstr ""
msgid "An error occurred when updating the issue title" msgid "An error occurred when updating the issue weight"
msgstr "" msgstr ""
msgid "An error occurred when updating the issue weight" msgid "An error occurred when updating the title"
msgstr "" msgstr ""
msgid "An error occurred while acknowledging the notification. Refresh the page and try again." msgid "An error occurred while acknowledging the notification. Refresh the page and try again."
...@@ -3686,9 +3686,6 @@ msgstr "" ...@@ -3686,9 +3686,6 @@ msgstr ""
msgid "An issue already exists" msgid "An issue already exists"
msgstr "" msgstr ""
msgid "An issue title is required"
msgstr ""
msgid "An unauthenticated user" msgid "An unauthenticated user"
msgstr "" msgstr ""
...@@ -17342,9 +17339,6 @@ msgstr "" ...@@ -17342,9 +17339,6 @@ msgstr ""
msgid "Issue published on status page." msgid "Issue published on status page."
msgstr "" msgstr ""
msgid "Issue title"
msgstr ""
msgid "Issue types" msgid "Issue types"
msgstr "" msgstr ""
......
...@@ -4,10 +4,10 @@ import Vuex from 'vuex'; ...@@ -4,10 +4,10 @@ import Vuex from 'vuex';
import { stubComponent } from 'helpers/stub_component'; import { stubComponent } from 'helpers/stub_component';
import BoardContentSidebar from '~/boards/components/board_content_sidebar.vue'; import BoardContentSidebar from '~/boards/components/board_content_sidebar.vue';
import BoardSidebarDueDate from '~/boards/components/sidebar/board_sidebar_due_date.vue'; import BoardSidebarDueDate from '~/boards/components/sidebar/board_sidebar_due_date.vue';
import BoardSidebarIssueTitle from '~/boards/components/sidebar/board_sidebar_issue_title.vue';
import BoardSidebarLabelsSelect from '~/boards/components/sidebar/board_sidebar_labels_select.vue'; import BoardSidebarLabelsSelect from '~/boards/components/sidebar/board_sidebar_labels_select.vue';
import BoardSidebarMilestoneSelect from '~/boards/components/sidebar/board_sidebar_milestone_select.vue'; import BoardSidebarMilestoneSelect from '~/boards/components/sidebar/board_sidebar_milestone_select.vue';
import BoardSidebarSubscription from '~/boards/components/sidebar/board_sidebar_subscription.vue'; import BoardSidebarSubscription from '~/boards/components/sidebar/board_sidebar_subscription.vue';
import BoardSidebarTitle from '~/boards/components/sidebar/board_sidebar_title.vue';
import { ISSUABLE } from '~/boards/constants'; import { ISSUABLE } from '~/boards/constants';
import { mockIssue, mockIssueGroupPath, mockIssueProjectPath } from '../mock_data'; import { mockIssue, mockIssueGroupPath, mockIssueProjectPath } from '../mock_data';
...@@ -102,8 +102,8 @@ describe('BoardContentSidebar', () => { ...@@ -102,8 +102,8 @@ describe('BoardContentSidebar', () => {
expect(wrapper.find(BoardSidebarLabelsSelect).exists()).toBe(true); expect(wrapper.find(BoardSidebarLabelsSelect).exists()).toBe(true);
}); });
it('renders BoardSidebarIssueTitle', () => { it('renders BoardSidebarTitle', () => {
expect(wrapper.find(BoardSidebarIssueTitle).exists()).toBe(true); expect(wrapper.find(BoardSidebarTitle).exists()).toBe(true);
}); });
it('renders BoardSidebarDueDate', () => { it('renders BoardSidebarDueDate', () => {
......
import { GlAlert, GlFormInput, GlForm } from '@gitlab/ui'; import { GlAlert, GlFormInput, GlForm } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue'; import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue';
import BoardSidebarIssueTitle from '~/boards/components/sidebar/board_sidebar_issue_title.vue'; import BoardSidebarTitle from '~/boards/components/sidebar/board_sidebar_title.vue';
import { createStore } from '~/boards/stores'; import { createStore } from '~/boards/stores';
import createFlash from '~/flash'; import createFlash from '~/flash';
const TEST_TITLE = 'New issue title'; const TEST_TITLE = 'New item title';
const TEST_ISSUE_A = { const TEST_ISSUE_A = {
id: 'gid://gitlab/Issue/1', id: 'gid://gitlab/Issue/1',
iid: 8, iid: 8,
...@@ -21,7 +21,7 @@ const TEST_ISSUE_B = { ...@@ -21,7 +21,7 @@ const TEST_ISSUE_B = {
jest.mock('~/flash'); jest.mock('~/flash');
describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => { describe('~/boards/components/sidebar/board_sidebar_title.vue', () => {
let wrapper; let wrapper;
let store; let store;
...@@ -32,12 +32,12 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => { ...@@ -32,12 +32,12 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => {
wrapper = null; wrapper = null;
}); });
const createWrapper = (issue = TEST_ISSUE_A) => { const createWrapper = (item = TEST_ISSUE_A) => {
store = createStore(); store = createStore();
store.state.boardItems = { [issue.id]: { ...issue } }; store.state.boardItems = { [item.id]: { ...item } };
store.dispatch('setActiveId', { id: issue.id }); store.dispatch('setActiveId', { id: item.id });
wrapper = shallowMount(BoardSidebarIssueTitle, { wrapper = shallowMount(BoardSidebarTitle, {
store, store,
provide: { provide: {
canUpdate: true, canUpdate: true,
...@@ -53,7 +53,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => { ...@@ -53,7 +53,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => {
const findFormInput = () => wrapper.find(GlFormInput); const findFormInput = () => wrapper.find(GlFormInput);
const findEditableItem = () => wrapper.find(BoardEditableItem); const findEditableItem = () => wrapper.find(BoardEditableItem);
const findCancelButton = () => wrapper.find('[data-testid="cancel-button"]'); const findCancelButton = () => wrapper.find('[data-testid="cancel-button"]');
const findTitle = () => wrapper.find('[data-testid="issue-title"]'); const findTitle = () => wrapper.find('[data-testid="item-title"]');
const findCollapsed = () => wrapper.find('[data-testid="collapsed-content"]'); const findCollapsed = () => wrapper.find('[data-testid="collapsed-content"]');
it('renders title and reference', () => { it('renders title and reference', () => {
...@@ -73,7 +73,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => { ...@@ -73,7 +73,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => {
beforeEach(async () => { beforeEach(async () => {
createWrapper(); createWrapper();
jest.spyOn(wrapper.vm, 'setActiveIssueTitle').mockImplementation(() => { jest.spyOn(wrapper.vm, 'setActiveItemTitle').mockImplementation(() => {
store.state.boardItems[TEST_ISSUE_A.id].title = TEST_TITLE; store.state.boardItems[TEST_ISSUE_A.id].title = TEST_TITLE;
}); });
findFormInput().vm.$emit('input', TEST_TITLE); findFormInput().vm.$emit('input', TEST_TITLE);
...@@ -87,7 +87,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => { ...@@ -87,7 +87,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => {
}); });
it('commits change to the server', () => { it('commits change to the server', () => {
expect(wrapper.vm.setActiveIssueTitle).toHaveBeenCalledWith({ expect(wrapper.vm.setActiveItemTitle).toHaveBeenCalledWith({
title: TEST_TITLE, title: TEST_TITLE,
projectPath: 'h/b', projectPath: 'h/b',
}); });
...@@ -98,14 +98,14 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => { ...@@ -98,14 +98,14 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => {
beforeEach(async () => { beforeEach(async () => {
createWrapper(); createWrapper();
jest.spyOn(wrapper.vm, 'setActiveIssueTitle').mockImplementation(() => {}); jest.spyOn(wrapper.vm, 'setActiveItemTitle').mockImplementation(() => {});
findFormInput().vm.$emit('input', ''); findFormInput().vm.$emit('input', '');
findForm().vm.$emit('submit', { preventDefault: () => {} }); findForm().vm.$emit('submit', { preventDefault: () => {} });
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
}); });
it('commits change to the server', () => { it('commits change to the server', () => {
expect(wrapper.vm.setActiveIssueTitle).not.toHaveBeenCalled(); expect(wrapper.vm.setActiveItemTitle).not.toHaveBeenCalled();
}); });
}); });
...@@ -122,7 +122,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => { ...@@ -122,7 +122,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => {
it('does not collapses sidebar and shows alert', () => { it('does not collapses sidebar and shows alert', () => {
expect(findCollapsed().isVisible()).toBe(false); expect(findCollapsed().isVisible()).toBe(false);
expect(findAlert().exists()).toBe(true); expect(findAlert().exists()).toBe(true);
expect(localStorage.getItem(`${TEST_ISSUE_A.id}/issue-title-pending-changes`)).toBe( expect(localStorage.getItem(`${TEST_ISSUE_A.id}/item-title-pending-changes`)).toBe(
TEST_TITLE, TEST_TITLE,
); );
}); });
...@@ -130,7 +130,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => { ...@@ -130,7 +130,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => {
describe('when accessing the form with pending changes', () => { describe('when accessing the form with pending changes', () => {
beforeAll(() => { beforeAll(() => {
localStorage.setItem(`${TEST_ISSUE_A.id}/issue-title-pending-changes`, TEST_TITLE); localStorage.setItem(`${TEST_ISSUE_A.id}/item-title-pending-changes`, TEST_TITLE);
createWrapper(); createWrapper();
}); });
...@@ -146,7 +146,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => { ...@@ -146,7 +146,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => {
beforeEach(async () => { beforeEach(async () => {
createWrapper(TEST_ISSUE_B); createWrapper(TEST_ISSUE_B);
jest.spyOn(wrapper.vm, 'setActiveIssueTitle').mockImplementation(() => { jest.spyOn(wrapper.vm, 'setActiveItemTitle').mockImplementation(() => {
store.state.boardItems[TEST_ISSUE_B.id].title = TEST_TITLE; store.state.boardItems[TEST_ISSUE_B.id].title = TEST_TITLE;
}); });
findFormInput().vm.$emit('input', TEST_TITLE); findFormInput().vm.$emit('input', TEST_TITLE);
...@@ -155,7 +155,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => { ...@@ -155,7 +155,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => {
}); });
it('collapses sidebar and render former title', () => { it('collapses sidebar and render former title', () => {
expect(wrapper.vm.setActiveIssueTitle).not.toHaveBeenCalled(); expect(wrapper.vm.setActiveItemTitle).not.toHaveBeenCalled();
expect(findCollapsed().isVisible()).toBe(true); expect(findCollapsed().isVisible()).toBe(true);
expect(findTitle().text()).toBe(TEST_ISSUE_B.title); expect(findTitle().text()).toBe(TEST_ISSUE_B.title);
}); });
...@@ -165,7 +165,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => { ...@@ -165,7 +165,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => {
beforeEach(async () => { beforeEach(async () => {
createWrapper(TEST_ISSUE_B); createWrapper(TEST_ISSUE_B);
jest.spyOn(wrapper.vm, 'setActiveIssueTitle').mockImplementation(() => { jest.spyOn(wrapper.vm, 'setActiveItemTitle').mockImplementation(() => {
throw new Error(['failed mutation']); throw new Error(['failed mutation']);
}); });
findFormInput().vm.$emit('input', 'Invalid title'); findFormInput().vm.$emit('input', 'Invalid title');
...@@ -173,7 +173,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => { ...@@ -173,7 +173,7 @@ describe('~/boards/components/sidebar/board_sidebar_issue_title.vue', () => {
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
}); });
it('collapses sidebar and renders former issue title', () => { it('collapses sidebar and renders former item title', () => {
expect(findCollapsed().isVisible()).toBe(true); expect(findCollapsed().isVisible()).toBe(true);
expect(findTitle().text()).toContain(TEST_ISSUE_B.title); expect(findTitle().text()).toContain(TEST_ISSUE_B.title);
expect(createFlash).toHaveBeenCalled(); expect(createFlash).toHaveBeenCalled();
......
...@@ -1223,9 +1223,13 @@ describe('setActiveIssueMilestone', () => { ...@@ -1223,9 +1223,13 @@ describe('setActiveIssueMilestone', () => {
}); });
}); });
describe('setActiveIssueTitle', () => { describe('setActiveItemTitle', () => {
const state = { boardItems: { [mockIssue.id]: mockIssue } }; const state = {
const getters = { activeBoardItem: mockIssue }; boardItems: { [mockIssue.id]: mockIssue },
issuableType: 'issue',
fullPath: 'path/f',
};
const getters = { activeBoardItem: mockIssue, isEpicBoard: false };
const testTitle = 'Test Title'; const testTitle = 'Test Title';
const input = { const input = {
title: testTitle, title: testTitle,
...@@ -1235,7 +1239,7 @@ describe('setActiveIssueTitle', () => { ...@@ -1235,7 +1239,7 @@ describe('setActiveIssueTitle', () => {
it('should commit title after setting the issue', (done) => { it('should commit title after setting the issue', (done) => {
jest.spyOn(gqlClient, 'mutate').mockResolvedValue({ jest.spyOn(gqlClient, 'mutate').mockResolvedValue({
data: { data: {
updateIssue: { updateIssuableTitle: {
issue: { issue: {
title: testTitle, title: testTitle,
}, },
...@@ -1251,7 +1255,7 @@ describe('setActiveIssueTitle', () => { ...@@ -1251,7 +1255,7 @@ describe('setActiveIssueTitle', () => {
}; };
testAction( testAction(
actions.setActiveIssueTitle, actions.setActiveItemTitle,
input, input,
{ ...state, ...getters }, { ...state, ...getters },
[ [
...@@ -1270,7 +1274,7 @@ describe('setActiveIssueTitle', () => { ...@@ -1270,7 +1274,7 @@ describe('setActiveIssueTitle', () => {
.spyOn(gqlClient, 'mutate') .spyOn(gqlClient, 'mutate')
.mockResolvedValue({ data: { updateIssue: { errors: ['failed mutation'] } } }); .mockResolvedValue({ data: { updateIssue: { errors: ['failed mutation'] } } });
await expect(actions.setActiveIssueTitle({ getters }, input)).rejects.toThrow(Error); await expect(actions.setActiveItemTitle({ getters }, input)).rejects.toThrow(Error);
}); });
}); });
......
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