summaryrefslogtreecommitdiff
path: root/spec/frontend/boards/components
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/boards/components')
-rw-r--r--spec/frontend/boards/components/board_card_layout_spec.js95
-rw-r--r--spec/frontend/boards/components/board_card_spec.js220
-rw-r--r--spec/frontend/boards/components/board_column_spec.js5
-rw-r--r--spec/frontend/boards/components/board_content_spec.js64
-rw-r--r--spec/frontend/boards/components/board_form_spec.js2
-rw-r--r--spec/frontend/boards/components/board_list_header_spec.js8
-rw-r--r--spec/frontend/boards/components/board_settings_sidebar_spec.js174
-rw-r--r--spec/frontend/boards/components/boards_selector_spec.js2
-rw-r--r--spec/frontend/boards/components/issuable_title_spec.js33
-rw-r--r--spec/frontend/boards/components/issue_count_spec.js2
-rw-r--r--spec/frontend/boards/components/sidebar/board_editable_item_spec.js107
11 files changed, 620 insertions, 92 deletions
diff --git a/spec/frontend/boards/components/board_card_layout_spec.js b/spec/frontend/boards/components/board_card_layout_spec.js
new file mode 100644
index 00000000000..80f649a1a96
--- /dev/null
+++ b/spec/frontend/boards/components/board_card_layout_spec.js
@@ -0,0 +1,95 @@
+/* global List */
+/* global ListLabel */
+
+import { shallowMount } from '@vue/test-utils';
+
+import MockAdapter from 'axios-mock-adapter';
+import waitForPromises from 'helpers/wait_for_promises';
+import axios from '~/lib/utils/axios_utils';
+
+import '~/boards/models/label';
+import '~/boards/models/assignee';
+import '~/boards/models/list';
+import store from '~/boards/stores';
+import boardsStore from '~/boards/stores/boards_store';
+import BoardCardLayout from '~/boards/components/board_card_layout.vue';
+import issueCardInner from '~/boards/components/issue_card_inner.vue';
+import { listObj, boardsMockInterceptor, setMockEndpoints } from '../mock_data';
+
+describe('Board card layout', () => {
+ let wrapper;
+ let mock;
+ let list;
+
+ // this particular mount component needs to be used after the root beforeEach because it depends on list being initialized
+ const mountComponent = propsData => {
+ wrapper = shallowMount(BoardCardLayout, {
+ stubs: {
+ issueCardInner,
+ },
+ store,
+ propsData: {
+ list,
+ issue: list.issues[0],
+ disabled: false,
+ index: 0,
+ ...propsData,
+ },
+ provide: {
+ groupId: null,
+ rootPath: '/',
+ },
+ });
+ };
+
+ const setupData = () => {
+ list = new List(listObj);
+ boardsStore.create();
+ boardsStore.detail.issue = {};
+ const label1 = new ListLabel({
+ id: 3,
+ title: 'testing 123',
+ color: '#000cff',
+ text_color: 'white',
+ description: 'test',
+ });
+ return waitForPromises().then(() => {
+ list.issues[0].labels.push(label1);
+ });
+ };
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ mock.onAny().reply(boardsMockInterceptor);
+ setMockEndpoints();
+ return setupData();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ list = null;
+ mock.restore();
+ });
+
+ describe('mouse events', () => {
+ it('sets showDetail to true on mousedown', async () => {
+ mountComponent();
+
+ wrapper.trigger('mousedown');
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.vm.showDetail).toBe(true);
+ });
+
+ it('sets showDetail to false on mousemove', async () => {
+ mountComponent();
+ wrapper.trigger('mousedown');
+ await wrapper.vm.$nextTick();
+ expect(wrapper.vm.showDetail).toBe(true);
+ wrapper.trigger('mousemove');
+ await wrapper.vm.$nextTick();
+ expect(wrapper.vm.showDetail).toBe(false);
+ });
+ });
+});
diff --git a/spec/frontend/boards/components/board_card_spec.js b/spec/frontend/boards/components/board_card_spec.js
new file mode 100644
index 00000000000..a3ddcdf01b7
--- /dev/null
+++ b/spec/frontend/boards/components/board_card_spec.js
@@ -0,0 +1,220 @@
+/* global List */
+/* global ListAssignee */
+/* global ListLabel */
+
+import { mount } from '@vue/test-utils';
+
+import MockAdapter from 'axios-mock-adapter';
+import waitForPromises from 'helpers/wait_for_promises';
+import axios from '~/lib/utils/axios_utils';
+
+import eventHub from '~/boards/eventhub';
+import sidebarEventHub from '~/sidebar/event_hub';
+import '~/boards/models/label';
+import '~/boards/models/assignee';
+import '~/boards/models/list';
+import store from '~/boards/stores';
+import boardsStore from '~/boards/stores/boards_store';
+import BoardCard from '~/boards/components/board_card.vue';
+import issueCardInner from '~/boards/components/issue_card_inner.vue';
+import userAvatarLink from '~/vue_shared/components/user_avatar/user_avatar_link.vue';
+import { listObj, boardsMockInterceptor, setMockEndpoints } from '../mock_data';
+
+describe('BoardCard', () => {
+ let wrapper;
+ let mock;
+ let list;
+
+ const findIssueCardInner = () => wrapper.find(issueCardInner);
+ const findUserAvatarLink = () => wrapper.find(userAvatarLink);
+
+ // this particular mount component needs to be used after the root beforeEach because it depends on list being initialized
+ const mountComponent = propsData => {
+ wrapper = mount(BoardCard, {
+ stubs: {
+ issueCardInner,
+ },
+ store,
+ propsData: {
+ list,
+ issue: list.issues[0],
+ disabled: false,
+ index: 0,
+ ...propsData,
+ },
+ provide: {
+ groupId: null,
+ rootPath: '/',
+ },
+ });
+ };
+
+ const setupData = async () => {
+ list = new List(listObj);
+ boardsStore.create();
+ boardsStore.detail.issue = {};
+ const label1 = new ListLabel({
+ id: 3,
+ title: 'testing 123',
+ color: '#000cff',
+ text_color: 'white',
+ description: 'test',
+ });
+ await waitForPromises();
+
+ list.issues[0].labels.push(label1);
+ };
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ mock.onAny().reply(boardsMockInterceptor);
+ setMockEndpoints();
+ return setupData();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ list = null;
+ mock.restore();
+ });
+
+ it('when details issue is empty does not show the element', () => {
+ mountComponent();
+ expect(wrapper.find('[data-testid="board_card"').classes()).not.toContain('is-active');
+ });
+
+ it('when detailIssue is equal to card issue shows the element', () => {
+ [boardsStore.detail.issue] = list.issues;
+ mountComponent();
+
+ expect(wrapper.classes()).toContain('is-active');
+ });
+
+ it('when multiSelect does not contain issue removes multi select class', () => {
+ mountComponent();
+ expect(wrapper.classes()).not.toContain('multi-select');
+ });
+
+ it('when multiSelect contain issue add multi select class', () => {
+ boardsStore.multiSelect.list = [list.issues[0]];
+ mountComponent();
+
+ expect(wrapper.classes()).toContain('multi-select');
+ });
+
+ it('adds user-can-drag class if not disabled', () => {
+ mountComponent();
+ expect(wrapper.classes()).toContain('user-can-drag');
+ });
+
+ it('does not add user-can-drag class disabled', () => {
+ mountComponent({ disabled: true });
+
+ expect(wrapper.classes()).not.toContain('user-can-drag');
+ });
+
+ it('does not add disabled class', () => {
+ mountComponent();
+ expect(wrapper.classes()).not.toContain('is-disabled');
+ });
+
+ it('adds disabled class is disabled is true', () => {
+ mountComponent({ disabled: true });
+
+ expect(wrapper.classes()).toContain('is-disabled');
+ });
+
+ describe('mouse events', () => {
+ it('does not set detail issue if showDetail is false', () => {
+ mountComponent();
+ expect(boardsStore.detail.issue).toEqual({});
+ });
+
+ it('does not set detail issue if link is clicked', () => {
+ mountComponent();
+ findIssueCardInner()
+ .find('a')
+ .trigger('mouseup');
+
+ expect(boardsStore.detail.issue).toEqual({});
+ });
+
+ it('does not set detail issue if img is clicked', () => {
+ mountComponent({
+ issue: {
+ ...list.issues[0],
+ assignees: [
+ new ListAssignee({
+ id: 1,
+ name: 'testing 123',
+ username: 'test',
+ avatar: 'test_image',
+ }),
+ ],
+ },
+ });
+
+ findUserAvatarLink().trigger('mouseup');
+
+ expect(boardsStore.detail.issue).toEqual({});
+ });
+
+ it('does not set detail issue if showDetail is false after mouseup', () => {
+ mountComponent();
+ wrapper.trigger('mouseup');
+
+ expect(boardsStore.detail.issue).toEqual({});
+ });
+
+ it('sets detail issue to card issue on mouse up', () => {
+ jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
+
+ mountComponent();
+
+ wrapper.trigger('mousedown');
+ wrapper.trigger('mouseup');
+
+ expect(eventHub.$emit).toHaveBeenCalledWith('newDetailIssue', wrapper.vm.issue, undefined);
+ expect(boardsStore.detail.list).toEqual(wrapper.vm.list);
+ });
+
+ it('resets detail issue to empty if already set', () => {
+ jest.spyOn(eventHub, '$emit').mockImplementation(() => {});
+ const [issue] = list.issues;
+ boardsStore.detail.issue = issue;
+ mountComponent();
+
+ wrapper.trigger('mousedown');
+ wrapper.trigger('mouseup');
+
+ expect(eventHub.$emit).toHaveBeenCalledWith('clearDetailIssue', undefined);
+ });
+ });
+
+ describe('sidebarHub events', () => {
+ it('closes all sidebars before showing an issue if no issues are opened', () => {
+ jest.spyOn(sidebarEventHub, '$emit').mockImplementation(() => {});
+ boardsStore.detail.issue = {};
+ mountComponent();
+
+ // sets conditional so that event is emitted.
+ wrapper.trigger('mousedown');
+
+ wrapper.trigger('mouseup');
+
+ expect(sidebarEventHub.$emit).toHaveBeenCalledWith('sidebar.closeAll');
+ });
+
+ it('it does not closes all sidebars before showing an issue if an issue is opened', () => {
+ jest.spyOn(sidebarEventHub, '$emit').mockImplementation(() => {});
+ const [issue] = list.issues;
+ boardsStore.detail.issue = issue;
+ mountComponent();
+
+ wrapper.trigger('mousedown');
+
+ expect(sidebarEventHub.$emit).not.toHaveBeenCalledWith('sidebar.closeAll');
+ });
+ });
+});
diff --git a/spec/frontend/boards/components/board_column_spec.js b/spec/frontend/boards/components/board_column_spec.js
index c06b7aceaad..2a4dbbb989e 100644
--- a/spec/frontend/boards/components/board_column_spec.js
+++ b/spec/frontend/boards/components/board_column_spec.js
@@ -59,10 +59,11 @@ describe('Board Column Component', () => {
propsData: {
boardId,
disabled: false,
- issueLinkBase: '/',
- rootPath: '/',
list,
},
+ provide: {
+ boardId,
+ },
});
};
diff --git a/spec/frontend/boards/components/board_content_spec.js b/spec/frontend/boards/components/board_content_spec.js
new file mode 100644
index 00000000000..df117d06cdf
--- /dev/null
+++ b/spec/frontend/boards/components/board_content_spec.js
@@ -0,0 +1,64 @@
+import Vuex from 'vuex';
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { GlAlert } from '@gitlab/ui';
+import EpicsSwimlanes from 'ee_component/boards/components/epics_swimlanes.vue';
+import BoardColumn from 'ee_else_ce/boards/components/board_column.vue';
+import getters from 'ee_else_ce/boards/stores/getters';
+import { mockListsWithModel } from '../mock_data';
+import BoardContent from '~/boards/components/board_content.vue';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('BoardContent', () => {
+ let wrapper;
+
+ const defaultState = {
+ isShowingEpicsSwimlanes: false,
+ boardLists: mockListsWithModel,
+ error: undefined,
+ };
+
+ const createStore = (state = defaultState) => {
+ return new Vuex.Store({
+ getters,
+ state,
+ actions: {
+ fetchIssuesForAllLists: () => {},
+ },
+ });
+ };
+
+ const createComponent = state => {
+ const store = createStore({
+ ...defaultState,
+ ...state,
+ });
+ wrapper = shallowMount(BoardContent, {
+ localVue,
+ propsData: {
+ lists: mockListsWithModel,
+ canAdminList: true,
+ disabled: false,
+ },
+ store,
+ });
+ };
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders a BoardColumn component per list', () => {
+ expect(wrapper.findAll(BoardColumn)).toHaveLength(mockListsWithModel.length);
+ });
+
+ it('does not display EpicsSwimlanes component', () => {
+ expect(wrapper.find(EpicsSwimlanes).exists()).toBe(false);
+ expect(wrapper.find(GlAlert).exists()).toBe(false);
+ });
+});
diff --git a/spec/frontend/boards/components/board_form_spec.js b/spec/frontend/boards/components/board_form_spec.js
index b1d277863e8..65d8070192c 100644
--- a/spec/frontend/boards/components/board_form_spec.js
+++ b/spec/frontend/boards/components/board_form_spec.js
@@ -11,7 +11,7 @@ describe('board_form.vue', () => {
const propsData = {
canAdminBoard: false,
labelsPath: `${TEST_HOST}/labels/path`,
- milestonePath: `${TEST_HOST}/milestone/path`,
+ labelsWebUrl: `${TEST_HOST}/-/labels`,
};
const findModal = () => wrapper.find(DeprecatedModal);
diff --git a/spec/frontend/boards/components/board_list_header_spec.js b/spec/frontend/boards/components/board_list_header_spec.js
index 76a3d5e71c8..2439c347bf0 100644
--- a/spec/frontend/boards/components/board_list_header_spec.js
+++ b/spec/frontend/boards/components/board_list_header_spec.js
@@ -57,12 +57,12 @@ describe('Board List Header Component', () => {
wrapper = shallowMount(BoardListHeader, {
propsData: {
- boardId,
disabled: false,
- issueLinkBase: '/',
- rootPath: '/',
list,
},
+ provide: {
+ boardId,
+ },
});
};
@@ -106,7 +106,7 @@ describe('Board List Header Component', () => {
createComponent();
expect(isCollapsed()).toBe(false);
- wrapper.find('[data-testid="board-list-header"]').vm.$emit('click');
+ wrapper.find('[data-testid="board-list-header"]').trigger('click');
return wrapper.vm.$nextTick().then(() => {
expect(isCollapsed()).toBe(false);
diff --git a/spec/frontend/boards/components/board_settings_sidebar_spec.js b/spec/frontend/boards/components/board_settings_sidebar_spec.js
index f39adc0fc49..12c9431f2d4 100644
--- a/spec/frontend/boards/components/board_settings_sidebar_spec.js
+++ b/spec/frontend/boards/components/board_settings_sidebar_spec.js
@@ -6,8 +6,9 @@ import { shallowMount, createLocalVue } from '@vue/test-utils';
import { GlDrawer, GlLabel } from '@gitlab/ui';
import BoardSettingsSidebar from '~/boards/components/board_settings_sidebar.vue';
import boardsStore from '~/boards/stores/boards_store';
+import { createStore } from '~/boards/stores';
import sidebarEventHub from '~/sidebar/event_hub';
-import { inactiveId } from '~/boards/constants';
+import { inactiveId, LIST } from '~/boards/constants';
const localVue = createLocalVue();
@@ -16,19 +17,12 @@ localVue.use(Vuex);
describe('BoardSettingsSidebar', () => {
let wrapper;
let mock;
- let storeActions;
+ let store;
const labelTitle = 'test';
const labelColor = '#FFFF';
const listId = 1;
- const createComponent = (state = { activeId: inactiveId }, actions = {}) => {
- storeActions = actions;
-
- const store = new Vuex.Store({
- state,
- actions: storeActions,
- });
-
+ const createComponent = () => {
wrapper = shallowMount(BoardSettingsSidebar, {
store,
localVue,
@@ -38,6 +32,9 @@ describe('BoardSettingsSidebar', () => {
const findDrawer = () => wrapper.find(GlDrawer);
beforeEach(() => {
+ store = createStore();
+ store.state.activeId = inactiveId;
+ store.state.sidebarType = LIST;
boardsStore.create();
});
@@ -46,114 +43,125 @@ describe('BoardSettingsSidebar', () => {
wrapper.destroy();
});
- it('finds a GlDrawer component', () => {
- createComponent();
+ describe('when sidebarType is "list"', () => {
+ it('finds a GlDrawer component', () => {
+ createComponent();
- expect(findDrawer().exists()).toBe(true);
- });
+ expect(findDrawer().exists()).toBe(true);
+ });
- describe('on close', () => {
- it('calls closeSidebar', async () => {
- const spy = jest.fn();
- createComponent({ activeId: inactiveId }, { setActiveId: spy });
+ describe('on close', () => {
+ it('closes the sidebar', async () => {
+ createComponent();
- findDrawer().vm.$emit('close');
+ findDrawer().vm.$emit('close');
- await wrapper.vm.$nextTick();
+ await wrapper.vm.$nextTick();
- expect(storeActions.setActiveId).toHaveBeenCalledWith(
- expect.anything(),
- inactiveId,
- undefined,
- );
- });
+ expect(wrapper.find(GlDrawer).exists()).toBe(false);
+ });
- it('calls closeSidebar on sidebar.closeAll event', async () => {
- createComponent({ activeId: inactiveId }, { setActiveId: jest.fn() });
+ it('closes the sidebar when emitting the correct event', async () => {
+ createComponent();
- sidebarEventHub.$emit('sidebar.closeAll');
+ sidebarEventHub.$emit('sidebar.closeAll');
- await wrapper.vm.$nextTick();
+ await wrapper.vm.$nextTick();
- expect(storeActions.setActiveId).toHaveBeenCalledWith(
- expect.anything(),
- inactiveId,
- undefined,
- );
+ expect(wrapper.find(GlDrawer).exists()).toBe(false);
+ });
});
- });
- describe('when activeId is zero', () => {
- it('renders GlDrawer with open false', () => {
- createComponent();
+ describe('when activeId is zero', () => {
+ it('renders GlDrawer with open false', () => {
+ createComponent();
- expect(findDrawer().props('open')).toBe(false);
+ expect(findDrawer().props('open')).toBe(false);
+ });
});
- });
- describe('when activeId is greater than zero', () => {
- beforeEach(() => {
- mock = new MockAdapter(axios);
+ describe('when activeId is greater than zero', () => {
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+
+ boardsStore.addList({
+ id: listId,
+ label: { title: labelTitle, color: labelColor },
+ list_type: 'label',
+ });
+ store.state.activeId = 1;
+ store.state.sidebarType = LIST;
+ });
- boardsStore.addList({
- id: listId,
- label: { title: labelTitle, color: labelColor },
- list_type: 'label',
+ afterEach(() => {
+ boardsStore.removeList(listId);
});
- });
- afterEach(() => {
- boardsStore.removeList(listId);
+ it('renders GlDrawer with open false', () => {
+ createComponent();
+
+ expect(findDrawer().props('open')).toBe(true);
+ });
});
- it('renders GlDrawer with open false', () => {
- createComponent({ activeId: 1 });
+ describe('when activeId is in boardsStore', () => {
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
- expect(findDrawer().props('open')).toBe(true);
- });
- });
+ boardsStore.addList({
+ id: listId,
+ label: { title: labelTitle, color: labelColor },
+ list_type: 'label',
+ });
- describe('when activeId is in boardsStore', () => {
- beforeEach(() => {
- mock = new MockAdapter(axios);
+ store.state.activeId = listId;
+ store.state.sidebarType = LIST;
- boardsStore.addList({
- id: listId,
- label: { title: labelTitle, color: labelColor },
- list_type: 'label',
+ createComponent();
});
- createComponent({ activeId: listId });
- });
+ afterEach(() => {
+ mock.restore();
+ });
- afterEach(() => {
- mock.restore();
- });
+ it('renders label title', () => {
+ expect(findLabel().props('title')).toBe(labelTitle);
+ });
- it('renders label title', () => {
- expect(findLabel().props('title')).toBe(labelTitle);
+ it('renders label background color', () => {
+ expect(findLabel().props('backgroundColor')).toBe(labelColor);
+ });
});
- it('renders label background color', () => {
- expect(findLabel().props('backgroundColor')).toBe(labelColor);
- });
- });
+ describe('when activeId is not in boardsStore', () => {
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
- describe('when activeId is not in boardsStore', () => {
- beforeEach(() => {
- mock = new MockAdapter(axios);
+ boardsStore.addList({ id: listId, label: { title: labelTitle, color: labelColor } });
+
+ store.state.activeId = inactiveId;
- boardsStore.addList({ id: listId, label: { title: labelTitle, color: labelColor } });
+ createComponent();
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
- createComponent({ activeId: inactiveId });
+ it('does not render GlLabel', () => {
+ expect(findLabel().exists()).toBe(false);
+ });
});
+ });
- afterEach(() => {
- mock.restore();
+ describe('when sidebarType is not List', () => {
+ beforeEach(() => {
+ store.state.sidebarType = '';
+ createComponent();
});
- it('does not render GlLabel', () => {
- expect(findLabel().exists()).toBe(false);
+ it('does not render GlDrawer', () => {
+ expect(findDrawer().exists()).toBe(false);
});
});
});
diff --git a/spec/frontend/boards/components/boards_selector_spec.js b/spec/frontend/boards/components/boards_selector_spec.js
index f2d4de238d1..2b7605a3f7c 100644
--- a/spec/frontend/boards/components/boards_selector_spec.js
+++ b/spec/frontend/boards/components/boards_selector_spec.js
@@ -81,12 +81,12 @@ describe('BoardsSelector', () => {
assignee_id: null,
labels: [],
},
- milestonePath: `${TEST_HOST}/milestone/path`,
boardBaseUrl: `${TEST_HOST}/board/base/url`,
hasMissingBoards: false,
canAdminBoard: true,
multipleIssueBoardsAvailable: true,
labelsPath: `${TEST_HOST}/labels/path`,
+ labelsWebUrl: `${TEST_HOST}/labels`,
projectId: 42,
groupId: 19,
scopedIssueBoardFeatureEnabled: true,
diff --git a/spec/frontend/boards/components/issuable_title_spec.js b/spec/frontend/boards/components/issuable_title_spec.js
new file mode 100644
index 00000000000..4b7f491b998
--- /dev/null
+++ b/spec/frontend/boards/components/issuable_title_spec.js
@@ -0,0 +1,33 @@
+import { shallowMount } from '@vue/test-utils';
+import IssuableTitle from '~/boards/components/issuable_title.vue';
+
+describe('IssuableTitle', () => {
+ let wrapper;
+ const defaultProps = {
+ title: 'One',
+ refPath: 'path',
+ };
+ const createComponent = () => {
+ wrapper = shallowMount(IssuableTitle, {
+ propsData: { ...defaultProps },
+ });
+ };
+ const findIssueContent = () => wrapper.find('[data-testid="issue-title"]');
+
+ beforeEach(() => {
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ it('renders a title of an issue in the sidebar', () => {
+ expect(findIssueContent().text()).toContain('One');
+ });
+
+ it('renders a referencePath of an issue in the sidebar', () => {
+ expect(findIssueContent().text()).toContain('path');
+ });
+});
diff --git a/spec/frontend/boards/components/issue_count_spec.js b/spec/frontend/boards/components/issue_count_spec.js
index 819d878f4e2..d1ff0bdbf88 100644
--- a/spec/frontend/boards/components/issue_count_spec.js
+++ b/spec/frontend/boards/components/issue_count_spec.js
@@ -29,7 +29,7 @@ describe('IssueCount', () => {
});
it('does not contains maxIssueCount in the template', () => {
- expect(vm.contains('.js-max-issue-size')).toBe(false);
+ expect(vm.find('.js-max-issue-size').exists()).toBe(false);
});
});
diff --git a/spec/frontend/boards/components/sidebar/board_editable_item_spec.js b/spec/frontend/boards/components/sidebar/board_editable_item_spec.js
new file mode 100644
index 00000000000..1dbcbd06407
--- /dev/null
+++ b/spec/frontend/boards/components/sidebar/board_editable_item_spec.js
@@ -0,0 +1,107 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlLoadingIcon } from '@gitlab/ui';
+import BoardSidebarItem from '~/boards/components/sidebar/board_editable_item.vue';
+
+describe('boards sidebar remove issue', () => {
+ let wrapper;
+
+ const findLoader = () => wrapper.find(GlLoadingIcon);
+ const findEditButton = () => wrapper.find('[data-testid="edit-button"]');
+ const findTitle = () => wrapper.find('[data-testid="title"]');
+ const findCollapsed = () => wrapper.find('[data-testid="collapsed-content"]');
+ const findExpanded = () => wrapper.find('[data-testid="expanded-content"]');
+
+ const createComponent = ({ props = {}, slots = {}, canUpdate = false } = {}) => {
+ wrapper = shallowMount(BoardSidebarItem, {
+ attachTo: document.body,
+ provide: { canUpdate },
+ propsData: props,
+ slots,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe('template', () => {
+ it('renders title', () => {
+ const title = 'Sidebar item title';
+ createComponent({ props: { title } });
+
+ expect(findTitle().text()).toBe(title);
+ });
+
+ it('hides edit button, loader and expanded content by default', () => {
+ createComponent();
+
+ expect(findEditButton().exists()).toBe(false);
+ expect(findLoader().exists()).toBe(false);
+ expect(findExpanded().isVisible()).toBe(false);
+ });
+
+ it('shows "None" if empty collapsed slot', () => {
+ createComponent({});
+
+ expect(findCollapsed().text()).toBe('None');
+ });
+
+ it('renders collapsed content by default', () => {
+ const slots = { collapsed: '<div>Collapsed content</div>' };
+ createComponent({ slots });
+
+ expect(findCollapsed().text()).toBe('Collapsed content');
+ });
+
+ it('shows edit button if can update', () => {
+ createComponent({ canUpdate: true });
+
+ expect(findEditButton().exists()).toBe(true);
+ });
+
+ it('shows loading icon if loading', () => {
+ createComponent({ props: { loading: true } });
+
+ expect(findLoader().exists()).toBe(true);
+ });
+
+ it('shows expanded content and hides collapsed content when clicking edit button', async () => {
+ const slots = { default: '<div>Select item</div>' };
+ createComponent({ canUpdate: true, slots });
+ findEditButton().vm.$emit('click');
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findCollapsed().isVisible()).toBe(false);
+ expect(findExpanded().isVisible()).toBe(true);
+ expect(findExpanded().text()).toBe('Select item');
+ });
+ });
+ });
+
+ describe('collapsing an item by offclicking', () => {
+ beforeEach(async () => {
+ createComponent({ canUpdate: true });
+ findEditButton().vm.$emit('click');
+ await wrapper.vm.$nextTick();
+ });
+
+ it('hides expanded section and displays collapsed section', async () => {
+ expect(findExpanded().isVisible()).toBe(true);
+ document.body.click();
+
+ await wrapper.vm.$nextTick();
+
+ expect(findCollapsed().isVisible()).toBe(true);
+ expect(findExpanded().isVisible()).toBe(false);
+ });
+
+ it('emits changed event', async () => {
+ document.body.click();
+
+ await wrapper.vm.$nextTick();
+
+ expect(wrapper.emitted().changed[1][0]).toBe(false);
+ });
+ });
+});