diff options
Diffstat (limited to 'spec/frontend/boards/components')
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); + }); + }); +}); |