Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/boards/components/board_assignee_dropdown_spec.js')
-rw-r--r--spec/frontend/boards/components/board_assignee_dropdown_spec.js308
1 files changed, 308 insertions, 0 deletions
diff --git a/spec/frontend/boards/components/board_assignee_dropdown_spec.js b/spec/frontend/boards/components/board_assignee_dropdown_spec.js
new file mode 100644
index 00000000000..e185a6d5419
--- /dev/null
+++ b/spec/frontend/boards/components/board_assignee_dropdown_spec.js
@@ -0,0 +1,308 @@
+import { mount, createLocalVue } from '@vue/test-utils';
+import { GlDropdownItem, GlAvatarLink, GlAvatarLabeled, GlSearchBoxByType } from '@gitlab/ui';
+import createMockApollo from 'jest/helpers/mock_apollo_helper';
+import VueApollo from 'vue-apollo';
+import BoardAssigneeDropdown from '~/boards/components/board_assignee_dropdown.vue';
+import IssuableAssignees from '~/sidebar/components/assignees/issuable_assignees.vue';
+import MultiSelectDropdown from '~/vue_shared/components/sidebar/multiselect_dropdown.vue';
+import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue';
+import store from '~/boards/stores';
+import getIssueParticipants from '~/vue_shared/components/sidebar/queries/getIssueParticipants.query.graphql';
+import searchUsers from '~/boards/queries/users_search.query.graphql';
+import { participants } from '../mock_data';
+
+const localVue = createLocalVue();
+
+localVue.use(VueApollo);
+
+describe('BoardCardAssigneeDropdown', () => {
+ let wrapper;
+ let fakeApollo;
+ let getIssueParticipantsSpy;
+ let getSearchUsersSpy;
+
+ const iid = '111';
+ const activeIssueName = 'test';
+ const anotherIssueName = 'hello';
+
+ const createComponent = (search = '') => {
+ wrapper = mount(BoardAssigneeDropdown, {
+ data() {
+ return {
+ search,
+ selected: store.getters.activeIssue.assignees,
+ participants,
+ };
+ },
+ store,
+ provide: {
+ canUpdate: true,
+ rootPath: '',
+ },
+ });
+ };
+
+ const createComponentWithApollo = (search = '') => {
+ fakeApollo = createMockApollo([
+ [getIssueParticipants, getIssueParticipantsSpy],
+ [searchUsers, getSearchUsersSpy],
+ ]);
+
+ wrapper = mount(BoardAssigneeDropdown, {
+ localVue,
+ apolloProvider: fakeApollo,
+ data() {
+ return {
+ search,
+ selected: store.getters.activeIssue.assignees,
+ participants,
+ };
+ },
+ store,
+ provide: {
+ canUpdate: true,
+ rootPath: '',
+ },
+ });
+ };
+
+ const unassign = async () => {
+ wrapper.find('[data-testid="unassign"]').trigger('click');
+
+ await wrapper.vm.$nextTick();
+ };
+
+ const openDropdown = async () => {
+ wrapper.find('[data-testid="edit-button"]').trigger('click');
+
+ await wrapper.vm.$nextTick();
+ };
+
+ const findByText = text => {
+ return wrapper.findAll(GlDropdownItem).wrappers.find(node => node.text().indexOf(text) === 0);
+ };
+
+ beforeEach(() => {
+ store.state.activeId = '1';
+ store.state.issues = {
+ '1': {
+ iid,
+ assignees: [{ username: activeIssueName, name: activeIssueName, id: activeIssueName }],
+ },
+ };
+
+ jest.spyOn(store, 'dispatch').mockResolvedValue();
+ });
+
+ afterEach(() => {
+ jest.restoreAllMocks();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ describe('when mounted', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it.each`
+ text
+ ${anotherIssueName}
+ ${activeIssueName}
+ `('finds item with $text', ({ text }) => {
+ const item = findByText(text);
+
+ expect(item.exists()).toBe(true);
+ });
+
+ it('renders gl-avatar-link in gl-dropdown-item', () => {
+ const item = findByText('hello');
+
+ expect(item.find(GlAvatarLink).exists()).toBe(true);
+ });
+
+ it('renders gl-avatar-labeled in gl-avatar-link', () => {
+ const item = findByText('hello');
+
+ expect(
+ item
+ .find(GlAvatarLink)
+ .find(GlAvatarLabeled)
+ .exists(),
+ ).toBe(true);
+ });
+ });
+
+ describe('when selected users are present', () => {
+ it('renders a divider', () => {
+ createComponent();
+
+ expect(wrapper.find('[data-testid="selected-user-divider"]').exists()).toBe(true);
+ });
+ });
+
+ describe('when collapsed', () => {
+ it('renders IssuableAssignees', () => {
+ createComponent();
+
+ expect(wrapper.find(IssuableAssignees).isVisible()).toBe(true);
+ expect(wrapper.find(MultiSelectDropdown).isVisible()).toBe(false);
+ });
+ });
+
+ describe('when dropdown is open', () => {
+ beforeEach(async () => {
+ createComponent();
+
+ await openDropdown();
+ });
+
+ it('shows assignees dropdown', async () => {
+ expect(wrapper.find(IssuableAssignees).isVisible()).toBe(false);
+ expect(wrapper.find(MultiSelectDropdown).isVisible()).toBe(true);
+ });
+
+ it('shows the issue returned as the activeIssue', async () => {
+ expect(findByText(activeIssueName).props('isChecked')).toBe(true);
+ });
+
+ describe('when "Unassign" is clicked', () => {
+ it('unassigns assignees', async () => {
+ await unassign();
+
+ expect(findByText('Unassign').props('isChecked')).toBe(true);
+ });
+ });
+
+ describe('when an unselected item is clicked', () => {
+ beforeEach(async () => {
+ await unassign();
+ });
+
+ it('assigns assignee in the dropdown', async () => {
+ wrapper.find('[data-testid="item_test"]').trigger('click');
+
+ await wrapper.vm.$nextTick();
+
+ expect(findByText(activeIssueName).props('isChecked')).toBe(true);
+ });
+
+ it('calls setAssignees with username list', async () => {
+ wrapper.find('[data-testid="item_test"]').trigger('click');
+
+ await wrapper.vm.$nextTick();
+
+ document.body.click();
+
+ await wrapper.vm.$nextTick();
+
+ expect(store.dispatch).toHaveBeenCalledWith('setAssignees', [activeIssueName]);
+ });
+ });
+
+ describe('when the user off clicks', () => {
+ beforeEach(async () => {
+ await unassign();
+
+ document.body.click();
+
+ await wrapper.vm.$nextTick();
+ });
+
+ it('calls setAssignees with username list', async () => {
+ expect(store.dispatch).toHaveBeenCalledWith('setAssignees', []);
+ });
+
+ it('closes the dropdown', async () => {
+ expect(wrapper.find(IssuableAssignees).isVisible()).toBe(true);
+ });
+ });
+ });
+
+ it('renders divider after unassign', () => {
+ createComponent();
+
+ expect(wrapper.find('[data-testid="unassign-divider"]').exists()).toBe(true);
+ });
+
+ it.each`
+ assignees | expected
+ ${[{ id: 5, username: '', name: '' }]} | ${'Assignee'}
+ ${[{ id: 6, username: '', name: '' }, { id: 7, username: '', name: '' }]} | ${'2 Assignees'}
+ `(
+ 'when assignees have a length of $assignees.length, it renders $expected',
+ ({ assignees, expected }) => {
+ store.state.issues['1'].assignees = assignees;
+
+ createComponent();
+
+ expect(wrapper.find(BoardEditableItem).props('title')).toBe(expected);
+ },
+ );
+
+ describe('Apollo', () => {
+ beforeEach(() => {
+ getIssueParticipantsSpy = jest.fn().mockResolvedValue({
+ data: {
+ issue: {
+ participants: {
+ nodes: [
+ {
+ username: 'participant',
+ name: 'participant',
+ webUrl: '',
+ avatarUrl: '',
+ id: '',
+ },
+ ],
+ },
+ },
+ },
+ });
+ getSearchUsersSpy = jest.fn().mockResolvedValue({
+ data: {
+ users: {
+ nodes: [{ username: 'root', name: 'root', webUrl: '', avatarUrl: '', id: '' }],
+ },
+ },
+ });
+ });
+
+ describe('when search is empty', () => {
+ beforeEach(() => {
+ createComponentWithApollo();
+ });
+
+ it('calls getIssueParticipants', async () => {
+ jest.runOnlyPendingTimers();
+ await wrapper.vm.$nextTick();
+
+ expect(getIssueParticipantsSpy).toHaveBeenCalledWith({ id: 'gid://gitlab/Issue/111' });
+ });
+ });
+
+ describe('when search is not empty', () => {
+ beforeEach(() => {
+ createComponentWithApollo('search term');
+ });
+
+ it('calls searchUsers', async () => {
+ jest.runOnlyPendingTimers();
+ await wrapper.vm.$nextTick();
+
+ expect(getSearchUsersSpy).toHaveBeenCalledWith({ search: 'search term' });
+ });
+ });
+ });
+
+ it('finds GlSearchBoxByType', async () => {
+ createComponent();
+
+ await openDropdown();
+
+ expect(wrapper.find(GlSearchBoxByType).exists()).toBe(true);
+ });
+});