Commit c1e5774a authored by Andrew Fontaine's avatar Andrew Fontaine

Merge branch '233568-unify-boards-issue-epic-create' into 'master'

Create Form for Issue and Epic in Boards

See merge request gitlab-org/gitlab!65048
parents 0edb65c0 7e3d5d0b
<script> <script>
import { GlButton } from '@gitlab/ui';
import { mapActions, mapGetters, mapState } from 'vuex'; import { mapActions, mapGetters, mapState } from 'vuex';
import { getMilestone } from 'ee_else_ce/boards/boards_util'; import { getMilestone } from 'ee_else_ce/boards/boards_util';
import BoardNewIssueMixin from 'ee_else_ce/boards/mixins/board_new_issue'; import BoardNewIssueMixin from 'ee_else_ce/boards/mixins/board_new_issue';
import { __ } from '~/locale';
import { toggleFormEventPrefix } from '../constants'; import { toggleFormEventPrefix } from '../constants';
import eventHub from '../eventhub'; import eventHub from '../eventhub';
import BoardNewItem from './board_new_item.vue';
import ProjectSelect from './project_select.vue'; import ProjectSelect from './project_select.vue';
export default { export default {
name: 'BoardNewIssue', name: 'BoardNewIssue',
i18n: {
cancel: __('Cancel'),
},
components: { components: {
BoardNewItem,
ProjectSelect, ProjectSelect,
GlButton,
}, },
mixins: [BoardNewIssueMixin], mixins: [BoardNewIssueMixin],
inject: ['groupId'], inject: ['groupId'],
...@@ -25,106 +23,55 @@ export default { ...@@ -25,106 +23,55 @@ export default {
required: true, required: true,
}, },
}, },
data() {
return {
title: '',
};
},
computed: { computed: {
...mapState(['selectedProject']), ...mapState(['selectedProject', 'fullPath']),
...mapGetters(['isGroupBoard', 'isEpicBoard']), ...mapGetters(['isGroupBoard']),
/** formEventPrefix() {
* We've extended this component in EE where return toggleFormEventPrefix.issue;
* submitButtonTitle returns a different string
* hence this is kept as a computed prop.
*/
submitButtonTitle() {
return __('Create issue');
}, },
disabled() { disableSubmit() {
if (this.isGroupBoard) { return this.isGroupBoard ? !this.selectedProject.name : false;
return this.title === '' || !this.selectedProject.name;
}
return this.title === '';
}, },
inputFieldId() { projectPath() {
// eslint-disable-next-line @gitlab/require-i18n-strings return this.isGroupBoard ? this.selectedProject.fullPath : this.fullPath;
return `${this.list.id}-title`;
}, },
}, },
mounted() {
this.$refs.input.focus();
eventHub.$on('setSelectedProject', this.setSelectedProject);
},
methods: { methods: {
...mapActions(['addListNewIssue']), ...mapActions(['addListNewIssue']),
submit() { submit({ title }) {
const { title } = this;
const labels = this.list.label ? [this.list.label] : []; const labels = this.list.label ? [this.list.label] : [];
const assignees = this.list.assignee ? [this.list.assignee] : []; const assignees = this.list.assignee ? [this.list.assignee] : [];
const milestone = getMilestone(this.list); const milestone = getMilestone(this.list);
eventHub.$emit(`scroll-board-list-${this.list.id}`);
return this.addListNewIssue({ return this.addListNewIssue({
list: this.list,
issueInput: { issueInput: {
title, title,
labelIds: labels?.map((l) => l.id), labelIds: labels?.map((l) => l.id),
assigneeIds: assignees?.map((a) => a?.id), assigneeIds: assignees?.map((a) => a?.id),
milestoneId: milestone?.id, milestoneId: milestone?.id,
projectPath: this.selectedProject.fullPath, projectPath: this.projectPath,
...this.extraIssueInput(),
}, },
list: this.list,
}).then(() => { }).then(() => {
this.reset(); this.cancel();
}); });
}, },
reset() { cancel() {
this.title = ''; eventHub.$emit(`${this.formEventPrefix}${this.list.id}`);
eventHub.$emit(`${toggleFormEventPrefix.issue}${this.list.id}`);
}, },
}, },
}; };
</script> </script>
<template> <template>
<div class="board-new-issue-form"> <board-new-item
<div class="board-card position-relative p-3 rounded"> :list="list"
<form ref="submitForm" @submit.prevent="submit"> :form-event-prefix="formEventPrefix"
<label :for="inputFieldId" class="label-bold">{{ __('Title') }}</label> :submit-button-title="__('Create issue')"
<input :disable-submit="disableSubmit"
:id="inputFieldId" @form-submit="submit"
ref="input" @form-cancel="cancel"
v-model="title" >
class="form-control" <project-select v-if="isGroupBoard" :group-id="groupId" :list="list" />
type="text" </board-new-item>
name="issue_title"
autocomplete="off"
/>
<project-select v-if="isGroupBoard && !isEpicBoard" :group-id="groupId" :list="list" />
<div class="clearfix gl-mt-3">
<gl-button
ref="submitButton"
:disabled="disabled"
class="float-left js-no-auto-disable"
variant="confirm"
category="primary"
type="submit"
>
{{ submitButtonTitle }}
</gl-button>
<gl-button
ref="cancelButton"
class="float-right"
type="button"
variant="default"
@click="reset"
>
{{ $options.i18n.cancel }}
</gl-button>
</div>
</form>
</div>
</div>
</template> </template>
...@@ -11,7 +11,7 @@ import ProjectSelect from './project_select_deprecated.vue'; ...@@ -11,7 +11,7 @@ import ProjectSelect from './project_select_deprecated.vue';
// This component is being replaced in favor of './board_new_issue.vue' for GraphQL boards // This component is being replaced in favor of './board_new_issue.vue' for GraphQL boards
export default { export default {
name: 'BoardNewIssue', name: 'BoardNewIssueDeprecated',
components: { components: {
ProjectSelect, ProjectSelect,
GlButton, GlButton,
......
<script>
import { GlForm, GlFormInput, GlButton } from '@gitlab/ui';
import { __ } from '~/locale';
import eventHub from '../eventhub';
export default {
i18n: {
cancel: __('Cancel'),
},
components: {
GlForm,
GlFormInput,
GlButton,
},
props: {
list: {
type: Object,
required: true,
},
formEventPrefix: {
type: String,
required: true,
},
disableSubmit: {
type: Boolean,
required: false,
default: false,
},
submitButtonTitle: {
type: String,
required: false,
default: __('Create issue'),
},
},
data() {
return {
title: '',
};
},
computed: {
inputFieldId() {
// eslint-disable-next-line @gitlab/require-i18n-strings
return `${this.list.id}-title`;
},
},
methods: {
handleFormCancel() {
this.title = '';
this.$emit('form-cancel');
},
handleFormSubmit() {
const { title, list } = this;
eventHub.$emit(`scroll-board-list-${this.list.id}`);
this.$emit('form-submit', {
title,
list,
});
},
},
};
</script>
<template>
<div class="board-new-issue-form">
<div class="board-card position-relative gl-p-5 rounded">
<gl-form @submit.prevent="handleFormSubmit" @reset="handleFormCancel">
<label :for="inputFieldId" class="gl-font-weight-bold">{{ __('Title') }}</label>
<gl-form-input
:id="inputFieldId"
v-model.trim="title"
:autofocus="true"
autocomplete="off"
type="text"
name="issue_title"
/>
<slot></slot>
<div class="gl-clearfix gl-mt-4">
<gl-button
:disabled="!title || disableSubmit"
class="gl-float-left js-no-auto-disable"
variant="confirm"
type="submit"
>
{{ submitButtonTitle }}
</gl-button>
<gl-button class="gl-float-right js-no-auto-disable" type="reset">
{{ $options.i18n.cancel }}
</gl-button>
</div>
</gl-form>
</div>
</div>
</template>
<script> <script>
// This is a false violation of @gitlab/no-runtime-template-compiler, since it
// extends a valid Vue single file component.
/* eslint-disable @gitlab/no-runtime-template-compiler */
import { mapActions, mapGetters } from 'vuex'; import { mapActions, mapGetters } from 'vuex';
import BoardNewIssueFoss from '~/boards/components/board_new_issue.vue'; import BoardNewItem from '~/boards/components/board_new_item.vue';
import { toggleFormEventPrefix } from '~/boards/constants'; import { toggleFormEventPrefix } from '~/boards/constants';
import eventHub from '~/boards/eventhub'; import eventHub from '~/boards/eventhub';
import createFlash from '~/flash';
import { __, s__ } from '~/locale';
import { fullEpicBoardId } from '../boards_util'; import { fullEpicBoardId } from '../boards_util';
export default { export default {
extends: BoardNewIssueFoss, components: {
inject: { BoardNewItem,
boardId: { },
default: '', inject: ['boardId'],
props: {
list: {
type: Object,
required: true,
}, },
}, },
computed: { computed: {
...mapGetters(['isGroupBoard']), ...mapGetters(['isGroupBoard']),
submitButtonTitle() { formEventPrefix() {
return __('Create epic'); return toggleFormEventPrefix.epic;
}, },
disabled() { formEvent() {
return this.title === ''; return `${this.formEventPrefix}${this.list.id}`;
}, },
}, },
methods: { methods: {
...mapActions(['addListNewEpic']), ...mapActions(['addListNewEpic']),
submit() { submit({ title }) {
const { return this.addListNewEpic({
title,
boardId,
list: { id },
} = this;
eventHub.$emit(`scroll-board-list-${id}`);
this.addListNewEpic({
epicInput: { epicInput: {
title, title,
boardId: fullEpicBoardId(boardId), boardId: fullEpicBoardId(this.boardId),
listId: id, listId: this.list.id,
}, },
list: this.list, list: this.list,
}) }).then(() => {
.then(() => { eventHub.$emit(this.formEvent);
this.reset(); });
})
.catch((error) => {
createFlash({
message: s__('Board|Failed to create epic. Please try again.'),
captureError: true,
error,
});
});
}, },
reset() { cancel() {
this.title = ''; eventHub.$emit(this.formEvent);
eventHub.$emit(`${toggleFormEventPrefix.epic}${this.list.id}`);
}, },
}, },
}; };
</script> </script>
<template>
<board-new-item
:list="list"
:form-event-prefix="formEventPrefix"
:submit-button-title="__('Create epic')"
@form-submit="submit"
@form-cancel="cancel"
/>
</template>
...@@ -26,7 +26,8 @@ RSpec.describe 'Issue Boards new issue', :js do ...@@ -26,7 +26,8 @@ RSpec.describe 'Issue Boards new issue', :js do
end end
page.within(first('.board-new-issue-form')) do page.within(first('.board-new-issue-form')) do
find('.form-control').set('new issue') fill_in 'issue_title', with: 'new issue'
click_button 'Create issue' click_button 'Create issue'
end end
......
...@@ -4,8 +4,6 @@ import createComponent from 'jest/boards/board_list_helper'; ...@@ -4,8 +4,6 @@ import createComponent from 'jest/boards/board_list_helper';
import BoardCard from '~/boards/components/board_card.vue'; import BoardCard from '~/boards/components/board_card.vue';
import BoardCardInner from '~/boards/components/board_card_inner.vue'; import BoardCardInner from '~/boards/components/board_card_inner.vue';
import { issuableTypes } from '~/boards/constants'; import { issuableTypes } from '~/boards/constants';
import eventHub from '~/boards/eventhub';
import createFlash from '~/flash';
jest.mock('~/flash'); jest.mock('~/flash');
...@@ -63,64 +61,4 @@ describe('BoardList Component', () => { ...@@ -63,64 +61,4 @@ describe('BoardList Component', () => {
':project_path', ':project_path',
); );
}); });
describe('board-new-epic component', () => {
const submitForm = async (w) => {
const newEpicForm = w.findComponent(BoardNewEpic);
newEpicForm.find('input').setValue('Foo');
newEpicForm.find('form').trigger('submit');
await wrapper.vm.$nextTick();
};
beforeEach(async () => {
eventHub.$emit(`toggle-epic-form-${wrapper.vm.list.id}`);
await wrapper.vm.$nextTick();
});
it('renders component', () => {
expect(wrapper.findComponent(BoardNewEpic).exists()).toBe(true);
});
it('calls action `addListNewEpic` when "Create epic" button is clicked', async () => {
await submitForm(wrapper);
expect(actions.addListNewEpic).toHaveBeenCalledWith(
expect.any(Object),
expect.objectContaining({
epicInput: {
title: 'Foo',
boardId: 'gid://gitlab/Boards::EpicBoard/',
listId: 'gid://gitlab/List/1',
},
}),
);
});
it('calls `createFlash` when form submission fails', async () => {
const mockActions = {
addListNewEpic: jest.fn().mockRejectedValue(),
};
wrapper = createComponent({
...componentConfig,
actions: mockActions,
});
eventHub.$emit(`toggle-epic-form-${wrapper.vm.list.id}`);
await wrapper.vm.$nextTick();
await submitForm(wrapper);
return mockActions.addListNewEpic().catch((error) => {
expect(createFlash).toHaveBeenCalledWith({
message: 'Failed to create epic. Please try again.',
captureError: true,
error,
});
});
});
});
}); });
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex';
import BoardNewEpic from 'ee/boards/components/board_new_epic.vue';
import { mockList } from 'jest/boards/mock_data';
import BoardNewItem from '~/boards/components/board_new_item.vue';
import eventHub from '~/boards/eventhub';
const localVue = createLocalVue();
localVue.use(Vuex);
const addListNewEpicSpy = jest.fn().mockResolvedValue();
const mockActions = { addListNewEpic: addListNewEpicSpy };
const createComponent = ({ actions = mockActions, getters = { isGroupBoard: () => true } } = {}) =>
shallowMount(BoardNewEpic, {
localVue,
store: new Vuex.Store({
actions,
getters,
}),
propsData: {
list: mockList,
},
provide: {
boardId: 1,
},
stubs: {
BoardNewItem,
},
});
describe('Epic boards new epic form', () => {
let wrapper;
const findBoardNewItem = () => wrapper.findComponent(BoardNewItem);
const submitForm = async (w) => {
const boardNewItem = w.findComponent(BoardNewItem);
boardNewItem.vm.$emit('form-submit', { title: 'Foo' });
await wrapper.vm.$nextTick();
};
beforeEach(async () => {
wrapper = createComponent();
await wrapper.vm.$nextTick();
});
afterEach(() => {
wrapper.destroy();
});
it('renders board-new-item component', () => {
const boardNewItem = findBoardNewItem();
expect(boardNewItem.exists()).toBe(true);
expect(boardNewItem.props()).toEqual({
list: mockList,
formEventPrefix: 'toggle-epic-form-',
submitButtonTitle: 'Create epic',
disableSubmit: false,
});
});
it('calls action `addListNewEpic` when "Create epic" button is clicked', async () => {
await submitForm(wrapper);
expect(addListNewEpicSpy).toHaveBeenCalledWith(expect.any(Object), {
list: expect.any(Object),
epicInput: {
title: 'Foo',
boardId: 'gid://gitlab/Boards::EpicBoard/1',
listId: 'gid://gitlab/List/1',
},
});
});
it('emits event `toggle-epic-form` with current list Id suffix on eventHub when `board-new-item` emits form-cancel event', async () => {
jest.spyOn(eventHub, '$emit').mockImplementation();
findBoardNewItem().vm.$emit('form-cancel');
await wrapper.vm.$nextTick();
expect(eventHub.$emit).toHaveBeenCalledWith(`toggle-epic-form-${mockList.id}`);
});
});
...@@ -5384,9 +5384,6 @@ msgstr "" ...@@ -5384,9 +5384,6 @@ msgstr ""
msgid "Board|Enter board name" msgid "Board|Enter board name"
msgstr "" msgstr ""
msgid "Board|Failed to create epic. Please try again."
msgstr ""
msgid "Board|Failed to delete board. Please try again." msgid "Board|Failed to delete board. Please try again."
msgstr "" msgstr ""
......
...@@ -4,8 +4,9 @@ import Vuex from 'vuex'; ...@@ -4,8 +4,9 @@ import Vuex from 'vuex';
import BoardCard from '~/boards/components/board_card.vue'; import BoardCard from '~/boards/components/board_card.vue';
import BoardList from '~/boards/components/board_list.vue'; import BoardList from '~/boards/components/board_list.vue';
import BoardNewIssue from '~/boards/components/board_new_issue.vue'; import BoardNewIssue from '~/boards/components/board_new_issue.vue';
import BoardNewItem from '~/boards/components/board_new_item.vue';
import defaultState from '~/boards/stores/state'; import defaultState from '~/boards/stores/state';
import { mockList, mockIssuesByListId, issues } from './mock_data'; import { mockList, mockIssuesByListId, issues, mockGroupProjects } from './mock_data';
export default function createComponent({ export default function createComponent({
listIssueProps = {}, listIssueProps = {},
...@@ -17,6 +18,7 @@ export default function createComponent({ ...@@ -17,6 +18,7 @@ export default function createComponent({
state = defaultState, state = defaultState,
stubs = { stubs = {
BoardNewIssue, BoardNewIssue,
BoardNewItem,
BoardCard, BoardCard,
}, },
} = {}) { } = {}) {
...@@ -25,6 +27,7 @@ export default function createComponent({ ...@@ -25,6 +27,7 @@ export default function createComponent({
const store = new Vuex.Store({ const store = new Vuex.Store({
state: { state: {
selectedProject: mockGroupProjects[0],
boardItemsByListId: mockIssuesByListId, boardItemsByListId: mockIssuesByListId,
boardItems: issues, boardItems: issues,
pageInfoByListId: { pageInfoByListId: {
...@@ -77,6 +80,7 @@ export default function createComponent({ ...@@ -77,6 +80,7 @@ export default function createComponent({
provide: { provide: {
groupId: null, groupId: null,
rootPath: '/', rootPath: '/',
boardId: '1',
weightFeatureAvailable: false, weightFeatureAvailable: false,
boardWeight: null, boardWeight: null,
canAdminList: true, canAdminList: true,
......
import { shallowMount, createLocalVue } from '@vue/test-utils'; import { shallowMount, createLocalVue } from '@vue/test-utils';
import Vuex from 'vuex'; import Vuex from 'vuex';
import BoardNewIssue from '~/boards/components/board_new_issue.vue'; import BoardNewIssue from '~/boards/components/board_new_issue.vue';
import BoardNewItem from '~/boards/components/board_new_item.vue';
import ProjectSelect from '~/boards/components/project_select.vue';
import eventHub from '~/boards/eventhub';
import { mockList, mockGroupProjects } from '../mock_data'; import { mockList, mockGroupProjects } from '../mock_data';
...@@ -8,107 +11,104 @@ const localVue = createLocalVue(); ...@@ -8,107 +11,104 @@ const localVue = createLocalVue();
localVue.use(Vuex); localVue.use(Vuex);
const addListNewIssuesSpy = jest.fn().mockResolvedValue();
const mockActions = { addListNewIssue: addListNewIssuesSpy };
const createComponent = ({
state = { selectedProject: mockGroupProjects[0], fullPath: mockGroupProjects[0].fullPath },
actions = mockActions,
getters = { isGroupBoard: () => true, isProjectBoard: () => false },
} = {}) =>
shallowMount(BoardNewIssue, {
localVue,
store: new Vuex.Store({
state,
actions,
getters,
}),
propsData: {
list: mockList,
},
provide: {
groupId: 1,
weightFeatureAvailable: false,
boardWeight: null,
},
stubs: {
BoardNewItem,
},
});
describe('Issue boards new issue form', () => { describe('Issue boards new issue form', () => {
let wrapper; let wrapper;
let vm;
const addListNewIssuesSpy = jest.fn();
const findSubmitButton = () => wrapper.find({ ref: 'submitButton' });
const findCancelButton = () => wrapper.find({ ref: 'cancelButton' });
const findSubmitForm = () => wrapper.find({ ref: 'submitForm' });
const submitIssue = () => {
const dummySubmitEvent = {
preventDefault() {},
};
return findSubmitForm().trigger('submit', dummySubmitEvent); const findBoardNewItem = () => wrapper.findComponent(BoardNewItem);
};
beforeEach(() => {
const store = new Vuex.Store({
state: { selectedProject: mockGroupProjects[0] },
actions: { addListNewIssue: addListNewIssuesSpy },
getters: { isGroupBoard: () => false, isProjectBoard: () => true },
});
wrapper = shallowMount(BoardNewIssue, {
propsData: {
disabled: false,
list: mockList,
},
store,
localVue,
provide: {
groupId: null,
weightFeatureAvailable: false,
boardWeight: null,
},
});
vm = wrapper.vm; beforeEach(async () => {
wrapper = createComponent();
return vm.$nextTick(); await wrapper.vm.$nextTick();
}); });
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
}); });
it('calls submit if submit button is clicked', async () => { it('renders board-new-item component', () => {
jest.spyOn(wrapper.vm, 'submit').mockImplementation(); const boardNewItem = findBoardNewItem();
wrapper.setData({ title: 'Testing Title' }); expect(boardNewItem.exists()).toBe(true);
expect(boardNewItem.props()).toEqual({
await vm.$nextTick(); list: mockList,
await submitIssue(); formEventPrefix: 'toggle-issue-form-',
expect(wrapper.vm.submit).toHaveBeenCalled(); submitButtonTitle: 'Create issue',
}); disableSubmit: false,
});
it('disables submit button if title is empty', () => {
expect(findSubmitButton().props().disabled).toBe(true);
}); });
it('enables submit button if title is not empty', async () => { it('calls addListNewIssue action when `board-new-item` emits form-submit event', async () => {
wrapper.setData({ title: 'Testing Title' }); findBoardNewItem().vm.$emit('form-submit', { title: 'Foo' });
await vm.$nextTick(); await wrapper.vm.$nextTick();
expect(wrapper.find({ ref: 'input' }).element.value).toBe('Testing Title'); expect(addListNewIssuesSpy).toHaveBeenCalledWith(expect.any(Object), {
expect(findSubmitButton().props().disabled).toBe(false); list: mockList,
issueInput: {
title: 'Foo',
labelIds: [],
assigneeIds: [],
milestoneId: undefined,
projectPath: mockGroupProjects[0].fullPath,
},
});
}); });
it('clears title after clicking cancel', async () => { it('emits event `toggle-issue-form` with current list Id suffix on eventHub when `board-new-item` emits form-cancel event', async () => {
findCancelButton().trigger('click'); jest.spyOn(eventHub, '$emit').mockImplementation();
findBoardNewItem().vm.$emit('form-cancel');
await vm.$nextTick(); await wrapper.vm.$nextTick();
expect(vm.title).toBe(''); expect(eventHub.$emit).toHaveBeenCalledWith(`toggle-issue-form-${mockList.id}`);
}); });
describe('submit success', () => { describe('when in group issue board', () => {
it('creates new issue', async () => { it('renders project-select component within board-new-item component', () => {
wrapper.setData({ title: 'create issue' }); const projectSelect = findBoardNewItem().findComponent(ProjectSelect);
await vm.$nextTick(); expect(projectSelect.exists()).toBe(true);
await submitIssue(); expect(projectSelect.props('list')).toEqual(mockList);
expect(addListNewIssuesSpy).toHaveBeenCalled();
}); });
});
it('enables button after submit', async () => { describe('when in project issue board', () => {
jest.spyOn(wrapper.vm, 'submit').mockImplementation(); beforeEach(() => {
wrapper.setData({ title: 'create issue' }); wrapper = createComponent({
getters: { isGroupBoard: () => false, isProjectBoard: () => true },
await vm.$nextTick(); });
await submitIssue();
expect(findSubmitButton().props().disabled).toBe(false);
}); });
it('clears title after submit', async () => { it('does not render project-select component within board-new-item component', () => {
wrapper.setData({ title: 'create issue' }); const projectSelect = findBoardNewItem().findComponent(ProjectSelect);
await vm.$nextTick(); expect(projectSelect.exists()).toBe(false);
await submitIssue();
await vm.$nextTick();
expect(vm.title).toBe('');
}); });
}); });
}); });
import { GlForm, GlFormInput, GlButton } from '@gitlab/ui';
import { mountExtended } from 'helpers/vue_test_utils_helper';
import BoardNewItem from '~/boards/components/board_new_item.vue';
import eventHub from '~/boards/eventhub';
import { mockList } from '../mock_data';
const createComponent = ({
list = mockList,
formEventPrefix = 'toggle-issue-form-',
disabledSubmit = false,
submitButtonTitle = 'Create item',
} = {}) =>
mountExtended(BoardNewItem, {
propsData: {
list,
formEventPrefix,
disabledSubmit,
submitButtonTitle,
},
slots: {
default: '<div id="default-slot"></div>',
},
stubs: {
GlForm,
},
});
describe('BoardNewItem', () => {
let wrapper;
beforeEach(() => {
wrapper = createComponent();
});
afterEach(() => {
wrapper.destroy();
});
describe('template', () => {
it('renders gl-form component', () => {
expect(wrapper.findComponent(GlForm).exists()).toBe(true);
});
it('renders field label', () => {
expect(wrapper.find('label').exists()).toBe(true);
expect(wrapper.find('label').text()).toBe('Title');
});
it('renders gl-form-input field', () => {
expect(wrapper.findComponent(GlFormInput).exists()).toBe(true);
});
it('renders default slot contents', () => {
expect(wrapper.find('#default-slot').exists()).toBe(true);
});
it('renders submit and cancel buttons', () => {
const buttons = wrapper.findAllComponents(GlButton);
expect(buttons).toHaveLength(2);
expect(buttons.at(0).text()).toBe('Create item');
expect(buttons.at(1).text()).toBe('Cancel');
});
describe('events', () => {
const glForm = () => wrapper.findComponent(GlForm);
const titleInput = () => wrapper.find('input[name="issue_title"]');
it('emits `form-submit` event with title value when `submit` is triggered on gl-form', async () => {
titleInput().setValue('Foo');
await glForm().trigger('submit');
expect(wrapper.emitted('form-submit')).toBeTruthy();
expect(wrapper.emitted('form-submit')[0]).toEqual([
{
title: 'Foo',
list: mockList,
},
]);
});
it('emits `scroll-board-list-` event with list.id on eventHub when `submit` is triggered on gl-form', async () => {
jest.spyOn(eventHub, '$emit').mockImplementation();
await glForm().trigger('submit');
expect(eventHub.$emit).toHaveBeenCalledWith(`scroll-board-list-${mockList.id}`);
});
it('emits `form-cancel` event and clears title value when `reset` is triggered on gl-form', async () => {
titleInput().setValue('Foo');
await wrapper.vm.$nextTick();
expect(titleInput().element.value).toBe('Foo');
await glForm().trigger('reset');
expect(titleInput().element.value).toBe('');
expect(wrapper.emitted('form-cancel')).toBeTruthy();
});
});
});
});
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