diff options
Diffstat (limited to 'spec/frontend/sidebar/components/assignees')
6 files changed, 232 insertions, 5 deletions
diff --git a/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js b/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js index 03d1ac3ab8d..5a3a152d201 100644 --- a/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js +++ b/spec/frontend/sidebar/components/assignees/assignee_avatar_link_spec.js @@ -1,7 +1,7 @@ import { shallowMount } from '@vue/test-utils'; import { TEST_HOST } from 'helpers/test_constants'; -import AssigneeAvatarLink from '~/sidebar/components/assignees/assignee_avatar_link.vue'; import AssigneeAvatar from '~/sidebar/components/assignees/assignee_avatar.vue'; +import AssigneeAvatarLink from '~/sidebar/components/assignees/assignee_avatar_link.vue'; import userDataMock from '../../user_data_mock'; const TOOLTIP_PLACEMENT = 'bottom'; @@ -79,4 +79,34 @@ describe('AssigneeAvatarLink component', () => { }); }, ); + + describe.each` + tooltipHasName | availability | canMerge | expected + ${true} | ${'Busy'} | ${false} | ${'Root (Busy) (cannot merge)'} + ${true} | ${'Busy'} | ${true} | ${'Root (Busy)'} + ${true} | ${''} | ${false} | ${'Root (cannot merge)'} + ${true} | ${''} | ${true} | ${'Root'} + ${false} | ${'Busy'} | ${false} | ${'Cannot merge'} + ${false} | ${'Busy'} | ${true} | ${''} + ${false} | ${''} | ${false} | ${'Cannot merge'} + ${false} | ${''} | ${true} | ${''} + `( + "with tooltipHasName=$tooltipHasName and availability='$availability' and canMerge=$canMerge", + ({ tooltipHasName, availability, canMerge, expected }) => { + beforeEach(() => { + createComponent({ + tooltipHasName, + user: { + ...userDataMock(), + can_merge: canMerge, + availability, + }, + }); + }); + + it('sets tooltip to $expected', () => { + expect(findTooltipText()).toBe(expected); + }); + }, + ); }); diff --git a/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js b/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js index 8e158c99971..5aa8264b98c 100644 --- a/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js +++ b/spec/frontend/sidebar/components/assignees/collapsed_assignee_list_spec.js @@ -1,8 +1,8 @@ -import { shallowMount } from '@vue/test-utils'; import { GlIcon } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; import UsersMockHelper from 'helpers/user_mock_data_helper'; -import CollapsedAssigneeList from '~/sidebar/components/assignees/collapsed_assignee_list.vue'; import CollapsedAssignee from '~/sidebar/components/assignees/collapsed_assignee.vue'; +import CollapsedAssigneeList from '~/sidebar/components/assignees/collapsed_assignee_list.vue'; const DEFAULT_MAX_COUNTER = 99; @@ -187,4 +187,26 @@ describe('CollapsedAssigneeList component', () => { expect(findAvatarCounter().text()).toEqual(`${DEFAULT_MAX_COUNTER}+`); }); }); + + const [busyUser] = UsersMockHelper.createNumberRandomUsers(1); + const [canMergeUser] = UsersMockHelper.createNumberRandomUsers(1); + busyUser.availability = 'busy'; + canMergeUser.can_merge = true; + + describe.each` + users | busy | canMerge | expected + ${[busyUser, canMergeUser]} | ${1} | ${1} | ${`${busyUser.name} (Busy), ${canMergeUser.name} (1/2 can merge)`} + ${[busyUser]} | ${1} | ${0} | ${`${busyUser.name} (Busy) (cannot merge)`} + ${[canMergeUser]} | ${0} | ${1} | ${`${canMergeUser.name}`} + ${[]} | ${0} | ${0} | ${'Assignee(s)'} + `( + 'with $users.length users, $busy is busy and $canMerge that can merge', + ({ users, expected }) => { + it('generates the tooltip text', () => { + createComponent({ users }); + + expect(getTooltipTitle()).toEqual(expected); + }); + }, + ); }); diff --git a/spec/frontend/sidebar/components/assignees/collapsed_assignee_spec.js b/spec/frontend/sidebar/components/assignees/collapsed_assignee_spec.js index ee1f8ed8d2b..b49e6255923 100644 --- a/spec/frontend/sidebar/components/assignees/collapsed_assignee_spec.js +++ b/spec/frontend/sidebar/components/assignees/collapsed_assignee_spec.js @@ -1,6 +1,7 @@ import { shallowMount } from '@vue/test-utils'; -import CollapsedAssignee from '~/sidebar/components/assignees/collapsed_assignee.vue'; import AssigneeAvatar from '~/sidebar/components/assignees/assignee_avatar.vue'; +import CollapsedAssignee from '~/sidebar/components/assignees/collapsed_assignee.vue'; +import UserNameWithStatus from '~/sidebar/components/assignees/user_name_with_status.vue'; import userDataMock from '../../user_data_mock'; const TEST_USER = userDataMock(); @@ -18,6 +19,9 @@ describe('CollapsedAssignee assignee component', () => { wrapper = shallowMount(CollapsedAssignee, { propsData, + stubs: { + UserNameWithStatus, + }, }); } diff --git a/spec/frontend/sidebar/components/assignees/sidebar_editable_item_spec.js b/spec/frontend/sidebar/components/assignees/sidebar_editable_item_spec.js new file mode 100644 index 00000000000..4ee12838491 --- /dev/null +++ b/spec/frontend/sidebar/components/assignees/sidebar_editable_item_spec.js @@ -0,0 +1,120 @@ +import { GlLoadingIcon } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import SidebarEditableItem from '~/sidebar/components/sidebar_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(SidebarEditableItem, { + 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'); + + await wrapper.vm.$nextTick; + + expect(findCollapsed().isVisible()).toBe(false); + expect(findExpanded().isVisible()).toBe(true); + }); + }); + + 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 open when edit button is clicked and edit is initailized to false', async () => { + createComponent({ canUpdate: true }); + + findEditButton().vm.$emit('click'); + + await wrapper.vm.$nextTick(); + + expect(wrapper.emitted().open.length).toBe(1); + }); + + it('does not emits events when collapsing with false `emitEvent`', async () => { + createComponent({ canUpdate: true }); + + findEditButton().vm.$emit('click'); + + await wrapper.vm.$nextTick(); + + wrapper.vm.collapse({ emitEvent: false }); + + expect(wrapper.emitted().close).toBeUndefined(); + }); +}); diff --git a/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js b/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js index da69f56d442..7e81df1d7d2 100644 --- a/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js +++ b/spec/frontend/sidebar/components/assignees/uncollapsed_assignee_list_spec.js @@ -1,8 +1,8 @@ import { mount } from '@vue/test-utils'; import { TEST_HOST } from 'helpers/test_constants'; import UsersMockHelper from 'helpers/user_mock_data_helper'; -import UncollapsedAssigneeList from '~/sidebar/components/assignees/uncollapsed_assignee_list.vue'; import AssigneeAvatarLink from '~/sidebar/components/assignees/assignee_avatar_link.vue'; +import UncollapsedAssigneeList from '~/sidebar/components/assignees/uncollapsed_assignee_list.vue'; import userDataMock from '../../user_data_mock'; const DEFAULT_RENDER_COUNT = 5; diff --git a/spec/frontend/sidebar/components/assignees/user_name_with_status_spec.js b/spec/frontend/sidebar/components/assignees/user_name_with_status_spec.js new file mode 100644 index 00000000000..9483c6624c5 --- /dev/null +++ b/spec/frontend/sidebar/components/assignees/user_name_with_status_spec.js @@ -0,0 +1,51 @@ +import { GlSprintf } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import { AVAILABILITY_STATUS } from '~/set_status_modal/utils'; +import UserNameWithStatus from '~/sidebar/components/assignees/user_name_with_status.vue'; + +const name = 'Goku'; +const containerClasses = 'gl-cool-class gl-over-9000'; + +describe('UserNameWithStatus', () => { + let wrapper; + + function createComponent(props = {}) { + return shallowMount(UserNameWithStatus, { + propsData: { name, containerClasses, ...props }, + stubs: { + GlSprintf, + }, + }); + } + + beforeEach(() => { + wrapper = createComponent(); + }); + + afterEach(() => { + wrapper.destroy(); + }); + + it('will render the users name', () => { + expect(wrapper.html()).toContain(name); + }); + + it('will not render "Busy"', () => { + expect(wrapper.html()).not.toContain('Busy'); + }); + + it('will render all relevant containerClasses', () => { + const classes = wrapper.find('span').classes().join(' '); + expect(classes).toBe(containerClasses); + }); + + describe(`with availability="${AVAILABILITY_STATUS.BUSY}"`, () => { + beforeEach(() => { + wrapper = createComponent({ availability: AVAILABILITY_STATUS.BUSY }); + }); + + it('will render "Busy"', () => { + expect(wrapper.html()).toContain('Goku (Busy)'); + }); + }); +}); |