diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-08 18:09:34 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2022-11-08 18:09:34 +0300 |
commit | b5bdf6e5219b3b57107aee49ba7c103affb65dd9 (patch) | |
tree | 54c1ea8b3140d60af9a6c64867edc0a484ef7735 /spec/frontend | |
parent | 81f062b841f6062601662061850934a51e77ceea (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend')
-rw-r--r-- | spec/frontend/boards/board_card_inner_spec.js | 11 | ||||
-rw-r--r-- | spec/frontend/boards/board_list_spec.js | 6 | ||||
-rw-r--r-- | spec/frontend/boards/components/board_card_move_to_position_spec.js | 1 | ||||
-rw-r--r-- | spec/frontend/search/mock_data.js | 84 | ||||
-rw-r--r-- | spec/frontend/search/sidebar/components/app_spec.js | 109 | ||||
-rw-r--r-- | spec/frontend/search/sidebar/components/filters_spec.js | 132 | ||||
-rw-r--r-- | spec/frontend/search/sidebar/components/scope_navigation_spec.js | 80 | ||||
-rw-r--r-- | spec/frontend/search/store/actions_spec.js | 35 | ||||
-rw-r--r-- | spec/frontend/search/store/mutations_spec.js | 22 |
9 files changed, 377 insertions, 103 deletions
diff --git a/spec/frontend/boards/board_card_inner_spec.js b/spec/frontend/boards/board_card_inner_spec.js index 3ebc51c4bcb..3b77c999a9e 100644 --- a/spec/frontend/boards/board_card_inner_spec.js +++ b/spec/frontend/boards/board_card_inner_spec.js @@ -7,7 +7,6 @@ import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; import { mountExtended } from 'helpers/vue_test_utils_helper'; import IssuableBlockedIcon from '~/vue_shared/components/issuable_blocked_icon/issuable_blocked_icon.vue'; import BoardCardInner from '~/boards/components/board_card_inner.vue'; -import BoardCardMoveToPosition from '~/boards/components/board_card_move_to_position.vue'; import WorkItemTypeIcon from '~/work_items/components/work_item_type_icon.vue'; import { issuableTypes } from '~/boards/constants'; import eventHub from '~/boards/eventhub'; @@ -49,7 +48,6 @@ describe('Board card component', () => { const findEpicCountablesTotalWeight = () => wrapper.findByTestId('epic-countables-total-weight'); const findEpicProgressTooltip = () => wrapper.findByTestId('epic-progress-tooltip-content'); const findHiddenIssueIcon = () => wrapper.findByTestId('hidden-icon'); - const findMoveToPositionComponent = () => wrapper.findComponent(BoardCardMoveToPosition); const findWorkItemIcon = () => wrapper.findComponent(WorkItemTypeIcon); const performSearchMock = jest.fn(); @@ -143,10 +141,6 @@ describe('Board card component', () => { expect(findHiddenIssueIcon().exists()).toBe(false); }); - it('renders the move to position icon', () => { - expect(findMoveToPositionComponent().exists()).toBe(true); - }); - it('does not render the work type icon by default', () => { expect(findWorkItemIcon().exists()).toBe(false); }); @@ -595,10 +589,5 @@ describe('Board card component', () => { expect(findEpicCountablesTotalWeight().text()).toBe('15'); expect(findEpicProgressTooltip().text()).toBe('10 of 15 weight completed'); }); - - it('does not render the move to position icon', () => { - createWrapper(); - expect(findMoveToPositionComponent().exists()).toBe(false); - }); }); }); diff --git a/spec/frontend/boards/board_list_spec.js b/spec/frontend/boards/board_list_spec.js index 9b0c0b93ffb..3a2beb714e9 100644 --- a/spec/frontend/boards/board_list_spec.js +++ b/spec/frontend/boards/board_list_spec.js @@ -6,6 +6,7 @@ import waitForPromises from 'helpers/wait_for_promises'; import createComponent from 'jest/boards/board_list_helper'; import BoardCard from '~/boards/components/board_card.vue'; import eventHub from '~/boards/eventhub'; +import BoardCardMoveToPosition from '~/boards/components/board_card_move_to_position.vue'; import { mockIssues } from './mock_data'; @@ -15,6 +16,7 @@ describe('Board list component', () => { const findByTestId = (testId) => wrapper.find(`[data-testid="${testId}"]`); const findIssueCountLoadingIcon = () => wrapper.find('[data-testid="count-loading-icon"]'); const findDraggable = () => wrapper.findComponent(Draggable); + const findMoveToPositionComponent = () => wrapper.findComponent(BoardCardMoveToPosition); const startDrag = ( params = { @@ -99,6 +101,10 @@ describe('Board list component', () => { await nextTick(); expect(wrapper.find('.board-list-count').attributes('data-issue-id')).toBe('-1'); }); + + it('renders the move to position icon', () => { + expect(findMoveToPositionComponent().exists()).toBe(true); + }); }); describe('load more issues', () => { diff --git a/spec/frontend/boards/components/board_card_move_to_position_spec.js b/spec/frontend/boards/components/board_card_move_to_position_spec.js index 7254b9486ef..8dee3c77787 100644 --- a/spec/frontend/boards/components/board_card_move_to_position_spec.js +++ b/spec/frontend/boards/components/board_card_move_to_position_spec.js @@ -48,6 +48,7 @@ describe('Board Card Move to position', () => { propsData: { item: mockIssue2, list: mockList, + listItemsLength: 3, index: 0, ...propsData, }, diff --git a/spec/frontend/search/mock_data.js b/spec/frontend/search/mock_data.js index 0542e96c77c..fa5ccfeb478 100644 --- a/spec/frontend/search/mock_data.js +++ b/spec/frontend/search/mock_data.js @@ -107,3 +107,87 @@ export const PROMISE_ALL_EXPECTED_MUTATIONS = { payload: { key: PROJECTS_LOCAL_STORAGE_KEY, data: [MOCK_FRESH_DATA_RES, MOCK_FRESH_DATA_RES] }, }, }; + +export const MOCK_NAVIGATION = { + projects: { + label: 'Projects', + scope: 'projects', + link: '/search?scope=projects&search=et', + count_link: '/search/count?scope=projects&search=et', + }, + blobs: { + label: 'Code', + scope: 'blobs', + link: '/search?scope=blobs&search=et', + count_link: '/search/count?scope=blobs&search=et', + }, + issues: { + label: 'Issues', + scope: 'issues', + link: '/search?scope=issues&search=et', + active: true, + count: '2,430', + }, + merge_requests: { + label: 'Merge requests', + scope: 'merge_requests', + link: '/search?scope=merge_requests&search=et', + count_link: '/search/count?scope=merge_requests&search=et', + }, + wiki_blobs: { + label: 'Wiki', + scope: 'wiki_blobs', + link: '/search?scope=wiki_blobs&search=et', + count_link: '/search/count?scope=wiki_blobs&search=et', + }, + commits: { + label: 'Commits', + scope: 'commits', + link: '/search?scope=commits&search=et', + count_link: '/search/count?scope=commits&search=et', + }, + notes: { + label: 'Comments', + scope: 'notes', + link: '/search?scope=notes&search=et', + count_link: '/search/count?scope=notes&search=et', + }, + milestones: { + label: 'Milestones', + scope: 'milestones', + link: '/search?scope=milestones&search=et', + count_link: '/search/count?scope=milestones&search=et', + }, + users: { + label: 'Users', + scope: 'users', + link: '/search?scope=users&search=et', + count_link: '/search/count?scope=users&search=et', + }, +}; + +export const MOCK_NAVIGATION_DATA = { + projects: { + label: 'Projects', + scope: 'projects', + link: '/search?scope=projects&search=et', + count_link: '/search/count?scope=projects&search=et', + }, +}; + +export const MOCK_ENDPOINT_RESPONSE = { count: '13' }; + +export const MOCK_DATA_FOR_NAVIGATION_ACTION_MUTATION = { + projects: { + count: '13', + label: 'Projects', + scope: 'projects', + link: '/search?scope=projects&search=et', + count_link: '/search/count?scope=projects&search=et', + }, +}; + +export const MOCK_NAVIGATION_ACTION_MUTATION = { + type: types.RECEIVE_NAVIGATION_COUNT, + payload: { key: 'projects', count: '13' }, +}; diff --git a/spec/frontend/search/sidebar/components/app_spec.js b/spec/frontend/search/sidebar/components/app_spec.js index 89959feec39..b4e3388f067 100644 --- a/spec/frontend/search/sidebar/components/app_spec.js +++ b/spec/frontend/search/sidebar/components/app_spec.js @@ -1,11 +1,9 @@ -import { GlButton, GlLink } from '@gitlab/ui'; import { shallowMount } from '@vue/test-utils'; import Vue from 'vue'; import Vuex from 'vuex'; import { MOCK_QUERY } from 'jest/search/mock_data'; import GlobalSearchSidebar from '~/search/sidebar/components/app.vue'; -import ConfidentialityFilter from '~/search/sidebar/components/confidentiality_filter.vue'; -import StatusFilter from '~/search/sidebar/components/status_filter.vue'; +import ResultsFilters from '~/search/sidebar/components/results_filters.vue'; Vue.use(Vuex); @@ -35,118 +33,49 @@ describe('GlobalSearchSidebar', () => { wrapper.destroy(); }); - const findSidebarForm = () => wrapper.find('form'); - const findStatusFilter = () => wrapper.findComponent(StatusFilter); - const findConfidentialityFilter = () => wrapper.findComponent(ConfidentialityFilter); - const findApplyButton = () => wrapper.findComponent(GlButton); - const findResetLinkButton = () => wrapper.findComponent(GlLink); + const findSidebarSection = () => wrapper.find('section'); + const findFilters = () => wrapper.findComponent(ResultsFilters); - describe('template', () => { + describe('renders properly', () => { describe('scope=projects', () => { beforeEach(() => { createComponent({ urlQuery: { ...MOCK_QUERY, scope: 'projects' } }); }); - it("doesn't render StatusFilter", () => { - expect(findStatusFilter().exists()).toBe(false); + it('shows section', () => { + expect(findSidebarSection().exists()).toBe(true); }); - it("doesn't render ConfidentialityFilter", () => { - expect(findConfidentialityFilter().exists()).toBe(false); - }); - - it("doesn't render ApplyButton", () => { - expect(findApplyButton().exists()).toBe(false); - }); - }); - - describe('scope=issues', () => { - beforeEach(() => { - createComponent({ urlQuery: MOCK_QUERY }); - }); - it('renders StatusFilter', () => { - expect(findStatusFilter().exists()).toBe(true); - }); - - it('renders ConfidentialityFilter', () => { - expect(findConfidentialityFilter().exists()).toBe(true); - }); - - it('renders ApplyButton', () => { - expect(findApplyButton().exists()).toBe(true); - }); - }); - }); - - describe('ApplyButton', () => { - describe('when sidebarDirty is false', () => { - beforeEach(() => { - createComponent({ sidebarDirty: false }); - }); - - it('disables the button', () => { - expect(findApplyButton().attributes('disabled')).toBe('true'); + it("doesn't shows filters", () => { + expect(findFilters().exists()).toBe(false); }); }); - describe('when sidebarDirty is true', () => { + describe('scope=merge_requests', () => { beforeEach(() => { - createComponent({ sidebarDirty: true }); + createComponent({ urlQuery: { ...MOCK_QUERY, scope: 'merge_requests' } }); }); - it('enables the button', () => { - expect(findApplyButton().attributes('disabled')).toBe(undefined); - }); - }); - }); - - describe('ResetLinkButton', () => { - describe('with no filter selected', () => { - beforeEach(() => { - createComponent({ urlQuery: {} }); + it('shows section', () => { + expect(findSidebarSection().exists()).toBe(true); }); - it('does not render', () => { - expect(findResetLinkButton().exists()).toBe(false); + it('shows filters', () => { + expect(findFilters().exists()).toBe(true); }); }); - describe('with filter selected', () => { + describe('scope=issues', () => { beforeEach(() => { createComponent({ urlQuery: MOCK_QUERY }); }); - - it('does render', () => { - expect(findResetLinkButton().exists()).toBe(true); - }); - }); - - describe('with filter selected and user updated query back to default', () => { - beforeEach(() => { - createComponent({ urlQuery: MOCK_QUERY, query: {} }); + it('shows section', () => { + expect(findSidebarSection().exists()).toBe(true); }); - it('does render', () => { - expect(findResetLinkButton().exists()).toBe(true); + it('shows filters', () => { + expect(findFilters().exists()).toBe(true); }); }); }); - - describe('actions', () => { - beforeEach(() => { - createComponent({}); - }); - - it('clicking ApplyButton calls applyQuery', () => { - findSidebarForm().trigger('submit'); - - expect(actionSpies.applyQuery).toHaveBeenCalled(); - }); - - it('clicking ResetLinkButton calls resetQuery', () => { - findResetLinkButton().vm.$emit('click'); - - expect(actionSpies.resetQuery).toHaveBeenCalled(); - }); - }); }); diff --git a/spec/frontend/search/sidebar/components/filters_spec.js b/spec/frontend/search/sidebar/components/filters_spec.js new file mode 100644 index 00000000000..4f217709297 --- /dev/null +++ b/spec/frontend/search/sidebar/components/filters_spec.js @@ -0,0 +1,132 @@ +import { GlButton, GlLink } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import Vue from 'vue'; +import Vuex from 'vuex'; +import { MOCK_QUERY } from 'jest/search/mock_data'; +import ResultsFilters from '~/search/sidebar/components/results_filters.vue'; +import ConfidentialityFilter from '~/search/sidebar/components/confidentiality_filter.vue'; +import StatusFilter from '~/search/sidebar/components/status_filter.vue'; + +Vue.use(Vuex); + +describe('GlobalSearchSidebarFilters', () => { + let wrapper; + + const actionSpies = { + applyQuery: jest.fn(), + resetQuery: jest.fn(), + }; + + const createComponent = (initialState) => { + const store = new Vuex.Store({ + state: { + urlQuery: MOCK_QUERY, + ...initialState, + }, + actions: actionSpies, + }); + + wrapper = shallowMount(ResultsFilters, { + store, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + const findSidebarForm = () => wrapper.find('form'); + const findStatusFilter = () => wrapper.findComponent(StatusFilter); + const findConfidentialityFilter = () => wrapper.findComponent(ConfidentialityFilter); + const findApplyButton = () => wrapper.findComponent(GlButton); + const findResetLinkButton = () => wrapper.findComponent(GlLink); + + describe('Renders correctly', () => { + beforeEach(() => { + createComponent({ urlQuery: MOCK_QUERY }); + }); + it('renders StatusFilter', () => { + expect(findStatusFilter().exists()).toBe(true); + }); + + it('renders ConfidentialityFilter', () => { + expect(findConfidentialityFilter().exists()).toBe(true); + }); + + it('renders ApplyButton', () => { + expect(findApplyButton().exists()).toBe(true); + }); + }); + + describe('ApplyButton', () => { + describe('when sidebarDirty is false', () => { + beforeEach(() => { + createComponent({ sidebarDirty: false }); + }); + + it('disables the button', () => { + expect(findApplyButton().attributes('disabled')).toBe('true'); + }); + }); + + describe('when sidebarDirty is true', () => { + beforeEach(() => { + createComponent({ sidebarDirty: true }); + }); + + it('enables the button', () => { + expect(findApplyButton().attributes('disabled')).toBe(undefined); + }); + }); + }); + + describe('ResetLinkButton', () => { + describe('with no filter selected', () => { + beforeEach(() => { + createComponent({ urlQuery: {} }); + }); + + it('does not render', () => { + expect(findResetLinkButton().exists()).toBe(false); + }); + }); + + describe('with filter selected', () => { + beforeEach(() => { + createComponent({ urlQuery: MOCK_QUERY }); + }); + + it('does render', () => { + expect(findResetLinkButton().exists()).toBe(true); + }); + }); + + describe('with filter selected and user updated query back to default', () => { + beforeEach(() => { + createComponent({ urlQuery: MOCK_QUERY, query: {} }); + }); + + it('does render', () => { + expect(findResetLinkButton().exists()).toBe(true); + }); + }); + }); + + describe('actions', () => { + beforeEach(() => { + createComponent({}); + }); + + it('clicking ApplyButton calls applyQuery', () => { + findSidebarForm().trigger('submit'); + + expect(actionSpies.applyQuery).toHaveBeenCalled(); + }); + + it('clicking ResetLinkButton calls resetQuery', () => { + findResetLinkButton().vm.$emit('click'); + + expect(actionSpies.resetQuery).toHaveBeenCalled(); + }); + }); +}); diff --git a/spec/frontend/search/sidebar/components/scope_navigation_spec.js b/spec/frontend/search/sidebar/components/scope_navigation_spec.js new file mode 100644 index 00000000000..6262a52e01a --- /dev/null +++ b/spec/frontend/search/sidebar/components/scope_navigation_spec.js @@ -0,0 +1,80 @@ +import { GlNav, GlNavItem } from '@gitlab/ui'; +import { shallowMount } from '@vue/test-utils'; +import Vue from 'vue'; +import Vuex from 'vuex'; +import { MOCK_QUERY, MOCK_NAVIGATION } from 'jest/search/mock_data'; +import ScopeNavigation from '~/search/sidebar/components/scope_navigation.vue'; + +Vue.use(Vuex); + +describe('ScopeNavigation', () => { + let wrapper; + + const actionSpies = { + fetchSidebarCount: jest.fn(), + }; + + const createComponent = (initialState) => { + const store = new Vuex.Store({ + state: { + urlQuery: MOCK_QUERY, + navigation: MOCK_NAVIGATION, + ...initialState, + }, + actions: actionSpies, + }); + + wrapper = shallowMount(ScopeNavigation, { + store, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + const findNavElement = () => wrapper.find('nav'); + const findGlNav = () => wrapper.findComponent(GlNav); + const findGlNavItems = () => wrapper.findAllComponents(GlNavItem); + const findGlNavItemActive = () => findGlNavItems().wrappers.filter((w) => w.attributes('active')); + const findGlNavItemActiveCount = () => findGlNavItemActive().at(0).findAll('span').at(1); + + describe('scope navigation', () => { + beforeEach(() => { + createComponent(); + }); + + it('renders section', () => { + expect(findNavElement().exists()).toBe(true); + }); + + it('renders nav component', () => { + expect(findGlNav().exists()).toBe(true); + }); + + it('renders all nav item components', () => { + expect(findGlNavItems()).toHaveLength(9); + }); + + it('nav items have proper links', () => { + const linkAtPosition = 3; + const { link } = MOCK_NAVIGATION[Object.keys(MOCK_NAVIGATION)[linkAtPosition]]; + + expect(findGlNavItems().at(linkAtPosition).attributes('href')).toBe(link); + }); + }); + + describe('scope navigation sets proper state', () => { + beforeEach(() => { + createComponent(); + }); + + it('sets proper class to active item', () => { + expect(findGlNavItemActive()).toHaveLength(1); + }); + + it('active item', () => { + expect(findGlNavItemActiveCount().text()).toBe('2.4K'); + }); + }); +}); diff --git a/spec/frontend/search/store/actions_spec.js b/spec/frontend/search/store/actions_spec.js index c442ffa521d..3d19b27ff86 100644 --- a/spec/frontend/search/store/actions_spec.js +++ b/spec/frontend/search/store/actions_spec.js @@ -2,6 +2,7 @@ import MockAdapter from 'axios-mock-adapter'; import testAction from 'helpers/vuex_action_helper'; import Api from '~/api'; import { createAlert } from '~/flash'; +import * as logger from '~/lib/logger'; import axios from '~/lib/utils/axios_utils'; import * as urlUtils from '~/lib/utils/url_utility'; import * as actions from '~/search/store/actions'; @@ -23,6 +24,9 @@ import { MOCK_FRESH_DATA_RES, PRELOAD_EXPECTED_MUTATIONS, PROMISE_ALL_EXPECTED_MUTATIONS, + MOCK_NAVIGATION_DATA, + MOCK_NAVIGATION_ACTION_MUTATION, + MOCK_ENDPOINT_RESPONSE, } from '../mock_data'; jest.mock('~/flash'); @@ -31,6 +35,9 @@ jest.mock('~/lib/utils/url_utility', () => ({ joinPaths: jest.fn().mockReturnValue(''), visitUrl: jest.fn(), })); +jest.mock('~/lib/logger', () => ({ + logError: jest.fn(), +})); describe('Global Search Store Actions', () => { let mock; @@ -260,4 +267,32 @@ describe('Global Search Store Actions', () => { ); }); }); + + describe.each` + action | axiosMock | type | scope | expectedMutations | errorLogs + ${actions.fetchSidebarCount} | ${{ method: 'onGet', code: 200 }} | ${'success'} | ${'issues'} | ${[MOCK_NAVIGATION_ACTION_MUTATION]} | ${0} + ${actions.fetchSidebarCount} | ${{ method: null, code: 0 }} | ${'success'} | ${'projects'} | ${[]} | ${0} + ${actions.fetchSidebarCount} | ${{ method: 'onGet', code: 500 }} | ${'error'} | ${'issues'} | ${[]} | ${1} + `('fetchSidebarCount', ({ action, axiosMock, type, expectedMutations, scope, errorLogs }) => { + describe(`on ${type}`, () => { + beforeEach(() => { + state.navigation = MOCK_NAVIGATION_DATA; + state.urlQuery = { + scope, + }; + + if (axiosMock.method) { + mock[axiosMock.method]().reply(axiosMock.code, MOCK_ENDPOINT_RESPONSE); + } + }); + + it(`should ${expectedMutations.length === 0 ? 'NOT ' : ''}dispatch ${ + expectedMutations.length === 0 ? '' : 'the correct ' + }mutations for ${scope}`, () => { + return testAction({ action, state, expectedMutations }).then(() => { + expect(logger.logError).toHaveBeenCalledTimes(errorLogs); + }); + }); + }); + }); }); diff --git a/spec/frontend/search/store/mutations_spec.js b/spec/frontend/search/store/mutations_spec.js index 25f9b692955..a79ec8f70b0 100644 --- a/spec/frontend/search/store/mutations_spec.js +++ b/spec/frontend/search/store/mutations_spec.js @@ -1,13 +1,20 @@ import * as types from '~/search/store/mutation_types'; import mutations from '~/search/store/mutations'; import createState from '~/search/store/state'; -import { MOCK_QUERY, MOCK_GROUPS, MOCK_PROJECTS } from '../mock_data'; +import { + MOCK_QUERY, + MOCK_GROUPS, + MOCK_PROJECTS, + MOCK_NAVIGATION_DATA, + MOCK_NAVIGATION_ACTION_MUTATION, + MOCK_DATA_FOR_NAVIGATION_ACTION_MUTATION, +} from '../mock_data'; describe('Global Search Store Mutations', () => { let state; beforeEach(() => { - state = createState({ query: MOCK_QUERY }); + state = createState({ query: MOCK_QUERY, navigation: MOCK_NAVIGATION_DATA }); }); describe('REQUEST_GROUPS', () => { @@ -90,4 +97,15 @@ describe('Global Search Store Mutations', () => { expect(state.frequentItems[payload.key]).toStrictEqual(payload.data); }); }); + + describe('RECEIVE_NAVIGATION_COUNT', () => { + it('sets frequentItems[key] to data', () => { + const { payload } = MOCK_NAVIGATION_ACTION_MUTATION; + mutations[types.RECEIVE_NAVIGATION_COUNT](state, payload); + + expect(state.navigation[payload.key]).toStrictEqual( + MOCK_DATA_FOR_NAVIGATION_ACTION_MUTATION[payload.key], + ); + }); + }); }); |