diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-16 12:09:20 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2023-06-16 12:09:20 +0300 |
commit | 8ae36d93f1a63874b584f0488fde88c1fee999c4 (patch) | |
tree | f1788ba1a7fb00248ff008f817f6feea89304339 /spec/frontend/search | |
parent | b394e58cc2e52e17e7991e3d7b705aa383c362ee (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/search')
-rw-r--r-- | spec/frontend/search/mock_data.js | 1 | ||||
-rw-r--r-- | spec/frontend/search/sidebar/components/label_dropdown_items_spec.js | 57 | ||||
-rw-r--r-- | spec/frontend/search/sidebar/components/label_filter_spec.js | 322 | ||||
-rw-r--r-- | spec/frontend/search/store/actions_spec.js | 2 | ||||
-rw-r--r-- | spec/frontend/search/store/getters_spec.js | 4 |
5 files changed, 381 insertions, 5 deletions
diff --git a/spec/frontend/search/mock_data.js b/spec/frontend/search/mock_data.js index 58824f8023d..7cf8633d749 100644 --- a/spec/frontend/search/mock_data.js +++ b/spec/frontend/search/mock_data.js @@ -8,6 +8,7 @@ export const MOCK_QUERY = { group_id: 1, language: ['C', 'JavaScript'], labels: ['60', '37'], + search: '*', }; export const MOCK_GROUP = { diff --git a/spec/frontend/search/sidebar/components/label_dropdown_items_spec.js b/spec/frontend/search/sidebar/components/label_dropdown_items_spec.js new file mode 100644 index 00000000000..135b12956b2 --- /dev/null +++ b/spec/frontend/search/sidebar/components/label_dropdown_items_spec.js @@ -0,0 +1,57 @@ +import { GlFormCheckbox } from '@gitlab/ui'; +import Vue from 'vue'; +import Vuex from 'vuex'; +import { shallowMount } from '@vue/test-utils'; +import { PROCESS_LABELS_DATA } from 'jest/search/mock_data'; +import LabelDropdownItems from '~/search/sidebar/components/label_filter/label_dropdown_items.vue'; + +Vue.use(Vuex); + +describe('LabelDropdownItems', () => { + let wrapper; + + const defaultProps = { + labels: PROCESS_LABELS_DATA, + }; + + const createComponent = (Props = defaultProps) => { + wrapper = shallowMount(LabelDropdownItems, { + propsData: { + ...Props, + }, + }); + }; + + const findAllLabelItems = () => wrapper.findAll('.label-filter-menu-item'); + const findFirstLabelCheckbox = () => findAllLabelItems().at(0).findComponent(GlFormCheckbox); + const findFirstLabelTitle = () => findAllLabelItems().at(0).findComponent('.label-title'); + const findFirstLabelColor = () => + findAllLabelItems().at(0).findComponent('[data-testid="label-color-indicator"]'); + + describe('Renders correctly', () => { + beforeEach(() => { + createComponent(); + }); + + it('renders items', () => { + expect(findAllLabelItems().exists()).toBe(true); + expect(findAllLabelItems()).toHaveLength(defaultProps.labels.length); + }); + + it('renders items checkbox', () => { + expect(findFirstLabelCheckbox().exists()).toBe(true); + }); + + it('renders label title', () => { + expect(findFirstLabelTitle().exists()).toBe(true); + expect(findFirstLabelTitle().text()).toBe(defaultProps.labels[0].title); + }); + + it('renders label color', () => { + expect(findFirstLabelColor().exists()).toBe(true); + expect(findFirstLabelColor().attributes('style')).toBe( + `background-color: ${defaultProps.labels[0].color};`, + ); + }); + }); +}); diff --git a/spec/frontend/search/sidebar/components/label_filter_spec.js b/spec/frontend/search/sidebar/components/label_filter_spec.js new file mode 100644 index 00000000000..c5df374d4ef --- /dev/null +++ b/spec/frontend/search/sidebar/components/label_filter_spec.js @@ -0,0 +1,322 @@ +import { + GlAlert, + GlLoadingIcon, + GlSearchBoxByType, + GlLabel, + GlDropdownForm, + GlFormCheckboxGroup, + GlDropdownSectionHeader, + GlDropdownDivider, +} from '@gitlab/ui'; +import Vue from 'vue'; +import Vuex from 'vuex'; +import { mockTracking, unmockTracking } from 'helpers/tracking_helper'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import { MOCK_QUERY, MOCK_LABEL_AGGREGATIONS } from 'jest/search/mock_data'; +import LabelFilter from '~/search/sidebar/components/label_filter/index.vue'; +import LabelDropdownItems from '~/search/sidebar/components/label_filter/label_dropdown_items.vue'; + +import * as actions from '~/search/store/actions'; +import * as getters from '~/search/store/getters'; +import mutations from '~/search/store/mutations'; +import createState from '~/search/store/state'; + +import { + TRACKING_LABEL_FILTER, + TRACKING_LABEL_DROPDOWN, + TRACKING_LABEL_CHECKBOX, + TRACKING_ACTION_SELECT, + TRACKING_ACTION_SHOW, +} from '~/search/sidebar/components/label_filter/tracking'; + +import { labelFilterData } from '~/search/sidebar/components/label_filter/data'; + +import { + RECEIVE_AGGREGATIONS_SUCCESS, + REQUEST_AGGREGATIONS, + RECEIVE_AGGREGATIONS_ERROR, +} from '~/search/store/mutation_types'; + +Vue.use(Vuex); + +const actionSpies = { + fetchAllAggregation: jest.fn(), + setQuery: jest.fn(), + closeLabel: jest.fn(), + setLabelFilterSearch: jest.fn(), +}; + +describe('GlobalSearchSidebarLabelFilter', () => { + let wrapper; + let trackingSpy; + let config; + let store; + + const createComponent = (initialState) => { + config = { + actions: { + ...actions, + fetchAllAggregation: actionSpies.fetchAllAggregation, + closeLabel: actionSpies.closeLabel, + setLabelFilterSearch: actionSpies.setLabelFilterSearch, + setQuery: actionSpies.setQuery, + }, + getters, + mutations, + state: createState({ + query: MOCK_QUERY, + aggregations: MOCK_LABEL_AGGREGATIONS, + ...initialState, + }), + }; + + store = new Vuex.Store(config); + + wrapper = mountExtended(LabelFilter, { + store, + provide: { + glFeatures: { + searchIssueLabelAggregation: true, + }, + }, + }); + }; + + const findComponentTitle = () => wrapper.findComponentByTestId('label-filter-title'); + const findAllSelectedLabelsAbove = () => wrapper.findAllComponents(GlLabel); + const findSearchBox = () => wrapper.findComponent(GlSearchBoxByType); + const findDropdownForm = () => wrapper.findComponent(GlDropdownForm); + const findCheckboxGroup = () => wrapper.findComponent(GlFormCheckboxGroup); + const findDropdownSectionHeader = () => wrapper.findComponent(GlDropdownSectionHeader); + const findDivider = () => wrapper.findComponent(GlDropdownDivider); + const findCheckboxFilter = () => wrapper.findAllComponents(LabelDropdownItems); + const findAlert = () => wrapper.findComponent(GlAlert); + const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon); + + describe('Renders correctly closed', () => { + beforeEach(async () => { + createComponent(); + store.commit(RECEIVE_AGGREGATIONS_SUCCESS, MOCK_LABEL_AGGREGATIONS.data); + + await Vue.nextTick(); + }); + + it('renders component title', () => { + expect(findComponentTitle().exists()).toBe(true); + }); + + it('renders selected labels above search box', () => { + expect(findAllSelectedLabelsAbove().exists()).toBe(true); + expect(findAllSelectedLabelsAbove()).toHaveLength(2); + }); + + it('renders search box', () => { + expect(findSearchBox().exists()).toBe(true); + }); + + it("doesn't render dropdown form", () => { + expect(findDropdownForm().exists()).toBe(false); + }); + + it("doesn't render checkbox group", () => { + expect(findCheckboxGroup().exists()).toBe(false); + }); + + it("doesn't render dropdown section header", () => { + expect(findDropdownSectionHeader().exists()).toBe(false); + }); + + it("doesn't render divider", () => { + expect(findDivider().exists()).toBe(false); + }); + + it("doesn't render checkbox filter", () => { + expect(findCheckboxFilter().exists()).toBe(false); + }); + + it("doesn't render alert", () => { + expect(findAlert().exists()).toBe(false); + }); + + it("doesn't render loading icon", () => { + expect(findLoadingIcon().exists()).toBe(false); + }); + }); + + describe('Renders correctly opened', () => { + beforeEach(async () => { + createComponent(); + store.commit(RECEIVE_AGGREGATIONS_SUCCESS, MOCK_LABEL_AGGREGATIONS.data); + + await Vue.nextTick(); + trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn); + findSearchBox().vm.$emit('focusin'); + }); + + afterEach(() => { + unmockTracking(); + }); + + it('renders component title', () => { + expect(findComponentTitle().exists()).toBe(true); + }); + + it('renders selected labels above search box', () => { + // default data need to provide at least two selected labels + expect(findAllSelectedLabelsAbove().exists()).toBe(true); + expect(findAllSelectedLabelsAbove()).toHaveLength(2); + }); + + it('renders search box', () => { + expect(findSearchBox().exists()).toBe(true); + }); + + it('renders dropdown form', () => { + expect(findDropdownForm().exists()).toBe(true); + }); + + it('renders checkbox group', () => { + expect(findCheckboxGroup().exists()).toBe(true); + }); + + it('renders dropdown section header', () => { + expect(findDropdownSectionHeader().exists()).toBe(true); + }); + + it('renders divider', () => { + expect(findDivider().exists()).toBe(true); + }); + + it('renders checkbox filter', () => { + expect(findCheckboxFilter().exists()).toBe(true); + }); + + it("doesn't render alert", () => { + expect(findAlert().exists()).toBe(false); + }); + + it("doesn't render loading icon", () => { + expect(findLoadingIcon().exists()).toBe(false); + }); + + it('sends tracking information when dropdown is opened', () => { + expect(trackingSpy).toHaveBeenCalledWith(TRACKING_ACTION_SHOW, TRACKING_LABEL_DROPDOWN, { + label: TRACKING_LABEL_DROPDOWN, + }); + }); + }); + + describe('Renders loading state correctly', () => { + beforeEach(async () => { + createComponent(); + store.commit(REQUEST_AGGREGATIONS); + await Vue.nextTick(); + + findSearchBox().vm.$emit('focusin'); + }); + + it('renders checkbox filter', () => { + expect(findCheckboxFilter().exists()).toBe(false); + }); + + it("doesn't render alert", () => { + expect(findAlert().exists()).toBe(false); + }); + + it('renders loading icon', () => { + expect(findLoadingIcon().exists()).toBe(true); + }); + }); + + describe('Renders error state correctly', () => { + beforeEach(async () => { + createComponent(); + store.commit(RECEIVE_AGGREGATIONS_ERROR); + await Vue.nextTick(); + + findSearchBox().vm.$emit('focusin'); + }); + + it("doesn't render checkbox filter", () => { + expect(findCheckboxFilter().exists()).toBe(false); + }); + + it('renders alert', () => { + expect(findAlert().exists()).toBe(true); + }); + + it("doesn't render loading icon", () => { + expect(findLoadingIcon().exists()).toBe(false); + }); + }); + + describe('Actions', () => { + describe('dispatch action when component is created', () => { + beforeEach(() => { + createComponent(); + }); + + it('renders checkbox filter', async () => { + await Vue.nextTick(); + expect(actionSpies.fetchAllAggregation).toHaveBeenCalled(); + }); + }); + + describe('Closing label works correctly', () => { + beforeEach(async () => { + createComponent(); + store.commit(RECEIVE_AGGREGATIONS_SUCCESS, MOCK_LABEL_AGGREGATIONS.data); + await Vue.nextTick(); + }); + + it('renders checkbox filter', async () => { + await findAllSelectedLabelsAbove().at(0).find('.btn-reset').trigger('click'); + expect(actionSpies.closeLabel).toHaveBeenCalled(); + }); + }); + + describe('label search input box works properly', () => { + beforeEach(() => { + createComponent(); + }); + + it('renders checkbox filter', () => { + findSearchBox().find('input').setValue('test'); + expect(actionSpies.setLabelFilterSearch).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ + value: 'test', + }), + ); + }); + }); + + describe('dropdown checkboxes work', () => { + beforeEach(async () => { + createComponent(); + + await findSearchBox().vm.$emit('focusin'); + await Vue.nextTick(); + + trackingSpy = mockTracking(undefined, wrapper.element, jest.spyOn); + + await findCheckboxGroup().vm.$emit('input', 6); + await Vue.nextTick(); + }); + + it('trigger event', () => { + expect(actionSpies.setQuery).toHaveBeenCalledWith( + expect.anything(), + expect.objectContaining({ key: labelFilterData?.filterParam, value: 6 }), + ); + }); + + it('sends tracking information when checkbox is selected', () => { + expect(trackingSpy).toHaveBeenCalledWith(TRACKING_ACTION_SELECT, TRACKING_LABEL_CHECKBOX, { + label: TRACKING_LABEL_FILTER, + property: 6, + }); + }); + }); + }); +}); diff --git a/spec/frontend/search/store/actions_spec.js b/spec/frontend/search/store/actions_spec.js index 18f7e1ce21c..2051e731647 100644 --- a/spec/frontend/search/store/actions_spec.js +++ b/spec/frontend/search/store/actions_spec.js @@ -133,7 +133,7 @@ describe('Global Search Store Actions', () => { describe('when groupId is set', () => { it('calls Api.groupProjects with expected parameters', () => { - actions.fetchProjects({ commit: mockCommit, state }, undefined); + actions.fetchProjects({ commit: mockCommit, state }, MOCK_QUERY.search); expect(Api.groupProjects).toHaveBeenCalledWith(state.query.group_id, state.query.search, { order_by: 'similarity', include_subgroups: true, diff --git a/spec/frontend/search/store/getters_spec.js b/spec/frontend/search/store/getters_spec.js index 51692cb1ab4..772acb39a57 100644 --- a/spec/frontend/search/store/getters_spec.js +++ b/spec/frontend/search/store/getters_spec.js @@ -33,10 +33,6 @@ describe('Global Search Store Getters', () => { useMockLocationHelper(); }); - afterEach(() => { - state = cloneDeep(defaultState); - }); - describe('frequentGroups', () => { it('returns the correct data', () => { state.frequentItems[GROUPS_LOCAL_STORAGE_KEY] = MOCK_GROUPS; |