diff options
Diffstat (limited to 'spec/frontend/boards/components')
4 files changed, 241 insertions, 67 deletions
diff --git a/spec/frontend/boards/components/board_card_spec.js b/spec/frontend/boards/components/board_card_spec.js index 022f8c05e1e..ceafa6ead94 100644 --- a/spec/frontend/boards/components/board_card_spec.js +++ b/spec/frontend/boards/components/board_card_spec.js @@ -1,4 +1,5 @@ -import { createLocalVue, shallowMount } from '@vue/test-utils'; +import { GlLabel } from '@gitlab/ui'; +import { createLocalVue, shallowMount, mount } from '@vue/test-utils'; import Vuex from 'vuex'; import BoardCard from '~/boards/components/board_card.vue'; @@ -14,10 +15,11 @@ describe('Board card', () => { const localVue = createLocalVue(); localVue.use(Vuex); - const createStore = ({ initialState = {}, isSwimlanesOn = false } = {}) => { + const createStore = ({ initialState = {} } = {}) => { mockActions = { toggleBoardItem: jest.fn(), toggleBoardItemMultiSelection: jest.fn(), + performSearch: jest.fn(), }; store = new Vuex.Store({ @@ -28,19 +30,21 @@ describe('Board card', () => { }, actions: mockActions, getters: { - isSwimlanesOn: () => isSwimlanesOn, isEpicBoard: () => false, }, }); }; // this particular mount component needs to be used after the root beforeEach because it depends on list being initialized - const mountComponent = ({ propsData = {}, provide = {} } = {}) => { - wrapper = shallowMount(BoardCard, { + const mountComponent = ({ + propsData = {}, + provide = {}, + mountFn = shallowMount, + stubs = { BoardCardInner }, + } = {}) => { + wrapper = mountFn(BoardCard, { localVue, - stubs: { - BoardCardInner, - }, + stubs, store, propsData: { list: mockLabelList, @@ -74,72 +78,76 @@ describe('Board card', () => { store = null; }); - describe.each` - isSwimlanesOn - ${true} | ${false} - `('when isSwimlanesOn is $isSwimlanesOn', ({ isSwimlanesOn }) => { - it('should not highlight the card by default', async () => { - createStore({ isSwimlanesOn }); - mountComponent(); + describe('when GlLabel is clicked in BoardCardInner', () => { + it('doesnt call toggleBoardItem', () => { + createStore({ initialState: { isShowingLabels: true } }); + mountComponent({ mountFn: mount, stubs: {} }); + + wrapper.find(GlLabel).trigger('mouseup'); - expect(wrapper.classes()).not.toContain('is-active'); - expect(wrapper.classes()).not.toContain('multi-select'); + expect(mockActions.toggleBoardItem).toHaveBeenCalledTimes(0); }); + }); - it('should highlight the card with a correct style when selected', async () => { - createStore({ - initialState: { - activeId: mockIssue.id, - }, - isSwimlanesOn, - }); - mountComponent(); + it('should not highlight the card by default', async () => { + createStore(); + mountComponent(); - expect(wrapper.classes()).toContain('is-active'); - expect(wrapper.classes()).not.toContain('multi-select'); + expect(wrapper.classes()).not.toContain('is-active'); + expect(wrapper.classes()).not.toContain('multi-select'); + }); + + it('should highlight the card with a correct style when selected', async () => { + createStore({ + initialState: { + activeId: mockIssue.id, + }, }); + mountComponent(); - it('should highlight the card with a correct style when multi-selected', async () => { - createStore({ - initialState: { - activeId: inactiveId, - selectedBoardItems: [mockIssue], - }, - isSwimlanesOn, - }); - mountComponent(); + expect(wrapper.classes()).toContain('is-active'); + expect(wrapper.classes()).not.toContain('multi-select'); + }); - expect(wrapper.classes()).toContain('multi-select'); - expect(wrapper.classes()).not.toContain('is-active'); + it('should highlight the card with a correct style when multi-selected', async () => { + createStore({ + initialState: { + activeId: inactiveId, + selectedBoardItems: [mockIssue], + }, }); + mountComponent(); - describe('when mouseup event is called on the card', () => { - beforeEach(() => { - createStore({ isSwimlanesOn }); - mountComponent(); - }); + expect(wrapper.classes()).toContain('multi-select'); + expect(wrapper.classes()).not.toContain('is-active'); + }); - describe('when not using multi-select', () => { - it('should call vuex action "toggleBoardItem" with correct parameters', async () => { - await selectCard(); + describe('when mouseup event is called on the card', () => { + beforeEach(() => { + createStore(); + mountComponent(); + }); + + describe('when not using multi-select', () => { + it('should call vuex action "toggleBoardItem" with correct parameters', async () => { + await selectCard(); - expect(mockActions.toggleBoardItem).toHaveBeenCalledTimes(1); - expect(mockActions.toggleBoardItem).toHaveBeenCalledWith(expect.any(Object), { - boardItem: mockIssue, - }); + expect(mockActions.toggleBoardItem).toHaveBeenCalledTimes(1); + expect(mockActions.toggleBoardItem).toHaveBeenCalledWith(expect.any(Object), { + boardItem: mockIssue, }); }); + }); - describe('when using multi-select', () => { - it('should call vuex action "multiSelectBoardItem" with correct parameters', async () => { - await multiSelectCard(); + describe('when using multi-select', () => { + it('should call vuex action "multiSelectBoardItem" with correct parameters', async () => { + await multiSelectCard(); - expect(mockActions.toggleBoardItemMultiSelection).toHaveBeenCalledTimes(1); - expect(mockActions.toggleBoardItemMultiSelection).toHaveBeenCalledWith( - expect.any(Object), - mockIssue, - ); - }); + expect(mockActions.toggleBoardItemMultiSelection).toHaveBeenCalledTimes(1); + expect(mockActions.toggleBoardItemMultiSelection).toHaveBeenCalledWith( + expect.any(Object), + mockIssue, + ); }); }); }); diff --git a/spec/frontend/boards/components/board_content_sidebar_spec.js b/spec/frontend/boards/components/board_content_sidebar_spec.js index 7f949739891..01c99a02db2 100644 --- a/spec/frontend/boards/components/board_content_sidebar_spec.js +++ b/spec/frontend/boards/components/board_content_sidebar_spec.js @@ -6,9 +6,9 @@ import BoardContentSidebar from '~/boards/components/board_content_sidebar.vue'; import BoardSidebarDueDate from '~/boards/components/sidebar/board_sidebar_due_date.vue'; import BoardSidebarLabelsSelect from '~/boards/components/sidebar/board_sidebar_labels_select.vue'; import BoardSidebarMilestoneSelect from '~/boards/components/sidebar/board_sidebar_milestone_select.vue'; -import BoardSidebarSubscription from '~/boards/components/sidebar/board_sidebar_subscription.vue'; import BoardSidebarTitle from '~/boards/components/sidebar/board_sidebar_title.vue'; import { ISSUABLE } from '~/boards/constants'; +import SidebarSubscriptionsWidget from '~/sidebar/components/subscriptions/sidebar_subscriptions_widget.vue'; import { mockIssue, mockIssueGroupPath, mockIssueProjectPath } from '../mock_data'; describe('BoardContentSidebar', () => { @@ -111,7 +111,7 @@ describe('BoardContentSidebar', () => { }); it('renders BoardSidebarSubscription', () => { - expect(wrapper.find(BoardSidebarSubscription).exists()).toBe(true); + expect(wrapper.find(SidebarSubscriptionsWidget).exists()).toBe(true); }); it('renders BoardSidebarMilestoneSelect', () => { diff --git a/spec/frontend/boards/components/board_filtered_search_spec.js b/spec/frontend/boards/components/board_filtered_search_spec.js new file mode 100644 index 00000000000..e27badca9de --- /dev/null +++ b/spec/frontend/boards/components/board_filtered_search_spec.js @@ -0,0 +1,146 @@ +import { shallowMount } from '@vue/test-utils'; +import Vue from 'vue'; +import Vuex from 'vuex'; +import BoardFilteredSearch from '~/boards/components/board_filtered_search.vue'; +import { createStore } from '~/boards/stores'; +import * as urlUtility from '~/lib/utils/url_utility'; +import { __ } from '~/locale'; +import FilteredSearchBarRoot from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; +import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue'; +import LabelToken from '~/vue_shared/components/filtered_search_bar/tokens/label_token.vue'; + +Vue.use(Vuex); + +describe('BoardFilteredSearch', () => { + let wrapper; + let store; + const tokens = [ + { + icon: 'labels', + title: __('Label'), + type: 'label_name', + operators: [ + { value: '=', description: 'is' }, + { value: '!=', description: 'is not' }, + ], + token: LabelToken, + unique: false, + symbol: '~', + fetchLabels: () => new Promise(() => {}), + }, + { + icon: 'pencil', + title: __('Author'), + type: 'author_username', + operators: [ + { value: '=', description: 'is' }, + { value: '!=', description: 'is not' }, + ], + symbol: '@', + token: AuthorToken, + unique: true, + fetchAuthors: () => new Promise(() => {}), + }, + ]; + + const createComponent = ({ initialFilterParams = {} } = {}) => { + wrapper = shallowMount(BoardFilteredSearch, { + provide: { initialFilterParams, fullPath: '' }, + store, + propsData: { + tokens, + }, + }); + }; + + const findFilteredSearch = () => wrapper.findComponent(FilteredSearchBarRoot); + + beforeEach(() => { + // this needed for actions call for performSearch + window.gon = { features: {} }; + }); + + afterEach(() => { + wrapper.destroy(); + }); + + describe('default', () => { + beforeEach(() => { + store = createStore(); + + jest.spyOn(store, 'dispatch'); + + createComponent(); + }); + + it('renders FilteredSearch', () => { + expect(findFilteredSearch().exists()).toBe(true); + }); + + it('passes the correct tokens to FilteredSearch', () => { + expect(findFilteredSearch().props('tokens')).toEqual(tokens); + }); + + describe('when onFilter is emitted', () => { + it('calls performSearch', () => { + findFilteredSearch().vm.$emit('onFilter', [{ value: { data: '' } }]); + + expect(store.dispatch).toHaveBeenCalledWith('performSearch'); + }); + + it('calls historyPushState', () => { + jest.spyOn(urlUtility, 'updateHistory'); + findFilteredSearch().vm.$emit('onFilter', [{ value: { data: 'searchQuery' } }]); + + expect(urlUtility.updateHistory).toHaveBeenCalledWith({ + replace: true, + title: '', + url: 'http://test.host/', + }); + }); + }); + }); + + describe('when searching', () => { + beforeEach(() => { + store = createStore(); + + jest.spyOn(store, 'dispatch'); + + createComponent(); + }); + + it('sets the url params to the correct results', async () => { + const mockFilters = [ + { type: 'author_username', value: { data: 'root', operator: '=' } }, + { type: 'label_name', value: { data: 'label', operator: '=' } }, + { type: 'label_name', value: { data: 'label2', operator: '=' } }, + ]; + jest.spyOn(urlUtility, 'updateHistory'); + findFilteredSearch().vm.$emit('onFilter', mockFilters); + + expect(urlUtility.updateHistory).toHaveBeenCalledWith({ + title: '', + replace: true, + url: 'http://test.host/?author_username=root&label_name[]=label&label_name[]=label2', + }); + }); + }); + + describe('when url params are already set', () => { + beforeEach(() => { + store = createStore(); + + jest.spyOn(store, 'dispatch'); + + createComponent({ initialFilterParams: { authorUsername: 'root', labelName: ['label'] } }); + }); + + it('passes the correct props to FilterSearchBar', () => { + expect(findFilteredSearch().props('initialFilterValue')).toEqual([ + { type: 'author_username', value: { data: 'root', operator: '=' } }, + { type: 'label_name', value: { data: 'label', operator: '=' } }, + ]); + }); + }); +}); diff --git a/spec/frontend/boards/components/sidebar/board_sidebar_labels_select_spec.js b/spec/frontend/boards/components/sidebar/board_sidebar_labels_select_spec.js index 153d0640b23..ad682774ee6 100644 --- a/spec/frontend/boards/components/sidebar/board_sidebar_labels_select_spec.js +++ b/spec/frontend/boards/components/sidebar/board_sidebar_labels_select_spec.js @@ -1,7 +1,11 @@ import { GlLabel } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import { TEST_HOST } from 'helpers/test_constants'; -import { labels as TEST_LABELS, mockIssue as TEST_ISSUE } from 'jest/boards/mock_data'; +import { + labels as TEST_LABELS, + mockIssue as TEST_ISSUE, + mockIssueFullPath as TEST_ISSUE_FULLPATH, +} from 'jest/boards/mock_data'; import BoardEditableItem from '~/boards/components/sidebar/board_editable_item.vue'; import BoardSidebarLabelsSelect from '~/boards/components/sidebar/board_sidebar_labels_select.vue'; import { createStore } from '~/boards/stores'; @@ -23,7 +27,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => { wrapper = null; }); - const createWrapper = ({ labels = [] } = {}) => { + const createWrapper = ({ labels = [], providedValues = {} } = {}) => { store = createStore(); store.state.boardItems = { [TEST_ISSUE.id]: { ...TEST_ISSUE, labels } }; store.state.activeId = TEST_ISSUE.id; @@ -32,9 +36,9 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => { store, provide: { canUpdate: true, - labelsFetchPath: TEST_HOST, labelsManagePath: TEST_HOST, labelsFilterBasePath: TEST_HOST, + ...providedValues, }, stubs: { BoardEditableItem, @@ -48,6 +52,22 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => { wrapper.findAll(GlLabel).wrappers.map((item) => item.props('title')); const findCollapsed = () => wrapper.find('[data-testid="collapsed-content"]'); + describe('when labelsFetchPath is provided', () => { + it('uses injected labels fetch path', () => { + createWrapper({ providedValues: { labelsFetchPath: 'foobar' } }); + + expect(findLabelsSelect().props('labelsFetchPath')).toEqual('foobar'); + }); + }); + + it('uses the default project label endpoint', () => { + createWrapper(); + + expect(findLabelsSelect().props('labelsFetchPath')).toEqual( + `/${TEST_ISSUE_FULLPATH}/-/labels?include_ancestor_groups=true`, + ); + }); + it('renders "None" when no labels are selected', () => { createWrapper(); @@ -78,7 +98,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => { it('commits change to the server', () => { expect(wrapper.vm.setActiveBoardItemLabels).toHaveBeenCalledWith({ addLabelIds: TEST_LABELS.map((label) => label.id), - projectPath: 'gitlab-org/test-subgroup/gitlab-test', + projectPath: TEST_ISSUE_FULLPATH, removeLabelIds: [], }); }); @@ -103,7 +123,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => { expect(wrapper.vm.setActiveBoardItemLabels).toHaveBeenCalledWith({ addLabelIds: [5, 7], removeLabelIds: [6], - projectPath: 'gitlab-org/test-subgroup/gitlab-test', + projectPath: TEST_ISSUE_FULLPATH, }); }); }); @@ -122,7 +142,7 @@ describe('~/boards/components/sidebar/board_sidebar_labels_select.vue', () => { expect(wrapper.vm.setActiveBoardItemLabels).toHaveBeenCalledWith({ removeLabelIds: [getIdFromGraphQLId(testLabel.id)], - projectPath: 'gitlab-org/test-subgroup/gitlab-test', + projectPath: TEST_ISSUE_FULLPATH, }); }); }); |