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/search')
-rw-r--r--spec/frontend/search/sidebar/components/all_scopes_start_filters_spec.js28
-rw-r--r--spec/frontend/search/sidebar/components/app_spec.js121
-rw-r--r--spec/frontend/search/sidebar/components/archived_filter_spec.js10
-rw-r--r--spec/frontend/search/sidebar/components/blobs_filters_spec.js34
-rw-r--r--spec/frontend/search/sidebar/components/confidentiality_filter_spec.js20
-rw-r--r--spec/frontend/search/sidebar/components/filters_template_spec.js5
-rw-r--r--spec/frontend/search/sidebar/components/group_filter_spec.js (renamed from spec/frontend/search/topbar/components/group_filter_spec.js)34
-rw-r--r--spec/frontend/search/sidebar/components/issues_filters_spec.js71
-rw-r--r--spec/frontend/search/sidebar/components/label_filter_spec.js5
-rw-r--r--spec/frontend/search/sidebar/components/merge_requests_filters_spec.js34
-rw-r--r--spec/frontend/search/sidebar/components/project_filter_spec.js (renamed from spec/frontend/search/topbar/components/project_filter_spec.js)36
-rw-r--r--spec/frontend/search/sidebar/components/scope_legacy_navigation_spec.js145
-rw-r--r--spec/frontend/search/sidebar/components/scope_sidebar_navigation_spec.js7
-rw-r--r--spec/frontend/search/sidebar/components/searchable_dropdown_spec.js117
-rw-r--r--spec/frontend/search/sidebar/components/small_screen_drawer_navigation_spec.js68
-rw-r--r--spec/frontend/search/sidebar/components/status_filter_spec.js20
-rw-r--r--spec/frontend/search/store/mutations_spec.js4
-rw-r--r--spec/frontend/search/topbar/components/app_spec.js63
-rw-r--r--spec/frontend/search/topbar/components/search_type_indicator_spec.js128
-rw-r--r--spec/frontend/search/topbar/components/searchable_dropdown_item_spec.js93
-rw-r--r--spec/frontend/search/topbar/components/searchable_dropdown_spec.js220
21 files changed, 414 insertions, 849 deletions
diff --git a/spec/frontend/search/sidebar/components/all_scopes_start_filters_spec.js b/spec/frontend/search/sidebar/components/all_scopes_start_filters_spec.js
new file mode 100644
index 00000000000..cd43214ed38
--- /dev/null
+++ b/spec/frontend/search/sidebar/components/all_scopes_start_filters_spec.js
@@ -0,0 +1,28 @@
+import { shallowMount } from '@vue/test-utils';
+import GroupFilter from '~/search/sidebar/components/group_filter.vue';
+import ProjectFilter from '~/search/sidebar/components/project_filter.vue';
+import AllScopesStartFilters from '~/search/sidebar/components/all_scopes_start_filters.vue';
+
+describe('GlobalSearch AllScopesStartFilters', () => {
+ let wrapper;
+
+ const findGroupFilter = () => wrapper.findComponent(GroupFilter);
+ const findProjectFilter = () => wrapper.findComponent(ProjectFilter);
+
+ const createComponent = () => {
+ wrapper = shallowMount(AllScopesStartFilters);
+ };
+
+ describe('Renders correctly', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+ it('renders ArchivedFilter', () => {
+ expect(findGroupFilter().exists()).toBe(true);
+ });
+
+ it('renders FiltersTemplate', () => {
+ expect(findProjectFilter().exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/search/sidebar/components/app_spec.js b/spec/frontend/search/sidebar/components/app_spec.js
index c2d88493d71..3ff6bbf7666 100644
--- a/spec/frontend/search/sidebar/components/app_spec.js
+++ b/spec/frontend/search/sidebar/components/app_spec.js
@@ -18,10 +18,9 @@ import NotesFilters from '~/search/sidebar/components/notes_filters.vue';
import CommitsFilters from '~/search/sidebar/components/commits_filters.vue';
import MilestonesFilters from '~/search/sidebar/components/milestones_filters.vue';
import WikiBlobsFilters from '~/search/sidebar/components/wiki_blobs_filters.vue';
-import ScopeLegacyNavigation from '~/search/sidebar/components/scope_legacy_navigation.vue';
-import SmallScreenDrawerNavigation from '~/search/sidebar/components/small_screen_drawer_navigation.vue';
import ScopeSidebarNavigation from '~/search/sidebar/components/scope_sidebar_navigation.vue';
import DomElementListener from '~/vue_shared/components/dom_element_listener.vue';
+import AllScopesStartFilters from '~/search/sidebar/components/all_scopes_start_filters.vue';
jest.mock('~/super_sidebar/super_sidebar_collapsed_state_manager');
@@ -45,11 +44,6 @@ describe('GlobalSearchSidebar', () => {
wrapper = shallowMount(GlobalSearchSidebar, {
store,
- provide: {
- glFeatures: {
- searchProjectWikisHideArchivedProjects: true,
- },
- },
});
};
@@ -62,10 +56,9 @@ describe('GlobalSearchSidebar', () => {
const findCommitsFilters = () => wrapper.findComponent(CommitsFilters);
const findMilestonesFilters = () => wrapper.findComponent(MilestonesFilters);
const findWikiBlobsFilters = () => wrapper.findComponent(WikiBlobsFilters);
- const findScopeLegacyNavigation = () => wrapper.findComponent(ScopeLegacyNavigation);
- const findSmallScreenDrawerNavigation = () => wrapper.findComponent(SmallScreenDrawerNavigation);
const findScopeSidebarNavigation = () => wrapper.findComponent(ScopeSidebarNavigation);
const findDomElementListener = () => wrapper.findComponent(DomElementListener);
+ const findAllScopesStartFilters = () => wrapper.findComponent(AllScopesStartFilters);
describe('renders properly', () => {
describe('always', () => {
@@ -79,31 +72,50 @@ describe('GlobalSearchSidebar', () => {
});
describe.each`
- scope | filter | searchType | isShown
- ${'issues'} | ${findIssuesFilters} | ${SEARCH_TYPE_BASIC} | ${true}
- ${'merge_requests'} | ${findMergeRequestsFilters} | ${SEARCH_TYPE_BASIC} | ${true}
- ${'projects'} | ${findProjectsFilters} | ${SEARCH_TYPE_BASIC} | ${true}
- ${'blobs'} | ${findBlobsFilters} | ${SEARCH_TYPE_BASIC} | ${false}
- ${'blobs'} | ${findBlobsFilters} | ${SEARCH_TYPE_ADVANCED} | ${true}
- ${'blobs'} | ${findBlobsFilters} | ${SEARCH_TYPE_ZOEKT} | ${false}
- ${'notes'} | ${findNotesFilters} | ${SEARCH_TYPE_BASIC} | ${true}
- ${'notes'} | ${findNotesFilters} | ${SEARCH_TYPE_ADVANCED} | ${true}
- ${'commits'} | ${findCommitsFilters} | ${SEARCH_TYPE_BASIC} | ${true}
- ${'commits'} | ${findCommitsFilters} | ${SEARCH_TYPE_ADVANCED} | ${true}
- ${'milestones'} | ${findMilestonesFilters} | ${SEARCH_TYPE_BASIC} | ${true}
- ${'milestones'} | ${findMilestonesFilters} | ${SEARCH_TYPE_ADVANCED} | ${true}
- ${'wiki_blobs'} | ${findWikiBlobsFilters} | ${SEARCH_TYPE_BASIC} | ${true}
- ${'wiki_blobs'} | ${findWikiBlobsFilters} | ${SEARCH_TYPE_ADVANCED} | ${true}
- `('with sidebar $scope scope:', ({ scope, filter, searchType, isShown }) => {
+ scope | filter
+ ${'issues'} | ${findIssuesFilters}
+ ${'issues'} | ${findAllScopesStartFilters}
+ ${'merge_requests'} | ${findMergeRequestsFilters}
+ ${'merge_requests'} | ${findAllScopesStartFilters}
+ ${'projects'} | ${findProjectsFilters}
+ ${'projects'} | ${findAllScopesStartFilters}
+ ${'blobs'} | ${findAllScopesStartFilters}
+ ${'notes'} | ${findNotesFilters}
+ ${'notes'} | ${findAllScopesStartFilters}
+ ${'commits'} | ${findCommitsFilters}
+ ${'commits'} | ${findAllScopesStartFilters}
+ ${'milestones'} | ${findMilestonesFilters}
+ ${'milestones'} | ${findAllScopesStartFilters}
+ ${'wiki_blobs'} | ${findWikiBlobsFilters}
+ ${'wiki_blobs'} | ${findAllScopesStartFilters}
+ `('with sidebar scope: $scope', ({ scope, filter }) => {
+ describe.each([SEARCH_TYPE_BASIC, SEARCH_TYPE_ADVANCED])(
+ 'with search_type %s',
+ (searchType) => {
+ beforeEach(() => {
+ getterSpies.currentScope = jest.fn(() => scope);
+ createComponent({ urlQuery: { scope }, searchType });
+ });
+
+ it(`renders correctly ${filter.name.replace('find', '')}`, () => {
+ expect(filter().exists()).toBe(true);
+ });
+ },
+ );
+ });
+
+ describe.each`
+ scope | filter | searchType | isShown
+ ${'blobs'} | ${findBlobsFilters} | ${SEARCH_TYPE_BASIC} | ${false}
+ ${'blobs'} | ${findBlobsFilters} | ${SEARCH_TYPE_ADVANCED} | ${true}
+ ${'blobs'} | ${findBlobsFilters} | ${SEARCH_TYPE_ZOEKT} | ${false}
+ `('sidebar blobs scope:', ({ scope, filter, searchType, isShown }) => {
beforeEach(() => {
getterSpies.currentScope = jest.fn(() => scope);
createComponent({ urlQuery: { scope }, searchType });
});
- it(`renders correctly filter ${filter.name.replace(
- 'find',
- '',
- )} when search_type ${searchType}`, () => {
+ it(`renders correctly filter BlobsFilters when search_type ${searchType}`, () => {
expect(filter().exists()).toBe(isShown);
});
});
@@ -129,46 +141,27 @@ describe('GlobalSearchSidebar', () => {
});
});
- describe.each`
- currentScope | sidebarNavShown | legacyNavShown
- ${'issues'} | ${false} | ${true}
- ${'test'} | ${false} | ${true}
- ${'issues'} | ${true} | ${false}
- ${'test'} | ${true} | ${false}
- `(
- 'renders navigation for scope $currentScope',
- ({ currentScope, sidebarNavShown, legacyNavShown }) => {
- beforeEach(() => {
- getterSpies.currentScope = jest.fn(() => currentScope);
- createComponent({ useSidebarNavigation: sidebarNavShown });
- });
-
- it(`renders navigation correctly with legacyNavShown ${legacyNavShown}`, () => {
- expect(findScopeLegacyNavigation().exists()).toBe(legacyNavShown);
- expect(findSmallScreenDrawerNavigation().exists()).toBe(legacyNavShown);
- });
-
- it(`renders navigation correctly with sidebarNavShown ${sidebarNavShown}`, () => {
- expect(findScopeSidebarNavigation().exists()).toBe(sidebarNavShown);
- });
- },
- );
- });
+ describe.each(['issues', 'test'])('for scope %p', (currentScope) => {
+ beforeEach(() => {
+ getterSpies.currentScope = jest.fn(() => currentScope);
+ createComponent();
+ });
- describe('when useSidebarNavigation=true', () => {
- beforeEach(() => {
- createComponent({ useSidebarNavigation: true });
+ it(`renders navigation correctly`, () => {
+ expect(findScopeSidebarNavigation().exists()).toBe(true);
+ });
});
+ });
- it('toggles super sidebar when button is clicked', () => {
- const elListener = findDomElementListener();
+ it('toggles super sidebar when button is clicked', () => {
+ createComponent();
+ const elListener = findDomElementListener();
- expect(toggleSuperSidebarCollapsed).not.toHaveBeenCalled();
+ expect(toggleSuperSidebarCollapsed).not.toHaveBeenCalled();
- elListener.vm.$emit('click');
+ elListener.vm.$emit('click');
- expect(toggleSuperSidebarCollapsed).toHaveBeenCalledTimes(1);
- expect(elListener.props('selector')).toBe('#js-open-mobile-filters');
- });
+ expect(toggleSuperSidebarCollapsed).toHaveBeenCalledTimes(1);
+ expect(elListener.props('selector')).toBe('#js-open-mobile-filters');
});
});
diff --git a/spec/frontend/search/sidebar/components/archived_filter_spec.js b/spec/frontend/search/sidebar/components/archived_filter_spec.js
index 9ed677ca297..9e8ababa5da 100644
--- a/spec/frontend/search/sidebar/components/archived_filter_spec.js
+++ b/spec/frontend/search/sidebar/components/archived_filter_spec.js
@@ -33,7 +33,7 @@ describe('ArchivedFilter', () => {
const findCheckboxFilter = () => wrapper.findComponent(GlFormCheckboxGroup);
const findCheckboxFilterLabel = () => wrapper.findByTestId('label');
- const findH5 = () => wrapper.findComponent('h5');
+ const findTitle = () => wrapper.findByTestId('archived-filter-title');
describe('old sidebar', () => {
beforeEach(() => {
@@ -45,8 +45,8 @@ describe('ArchivedFilter', () => {
});
it('renders the divider', () => {
- expect(findH5().exists()).toBe(true);
- expect(findH5().text()).toBe(archivedFilterData.headerLabel);
+ expect(findTitle().exists()).toBe(true);
+ expect(findTitle().text()).toBe(archivedFilterData.headerLabel);
});
it('wraps the label element with a tooltip', () => {
@@ -66,8 +66,8 @@ describe('ArchivedFilter', () => {
});
it("doesn't render the divider", () => {
- expect(findH5().exists()).toBe(true);
- expect(findH5().text()).toBe(archivedFilterData.headerLabel);
+ expect(findTitle().exists()).toBe(true);
+ expect(findTitle().text()).toBe(archivedFilterData.headerLabel);
});
it('wraps the label element with a tooltip', () => {
diff --git a/spec/frontend/search/sidebar/components/blobs_filters_spec.js b/spec/frontend/search/sidebar/components/blobs_filters_spec.js
index 245ddb8f8bb..3f1feae8527 100644
--- a/spec/frontend/search/sidebar/components/blobs_filters_spec.js
+++ b/spec/frontend/search/sidebar/components/blobs_filters_spec.js
@@ -17,13 +17,11 @@ describe('GlobalSearch BlobsFilters', () => {
currentScope: () => 'blobs',
};
- const createComponent = ({ initialState = {} } = {}) => {
+ const createComponent = () => {
const store = new Vuex.Store({
state: {
urlQuery: MOCK_QUERY,
- useSidebarNavigation: false,
searchType: SEARCH_TYPE_ADVANCED,
- ...initialState,
},
getters: defaultGetters,
});
@@ -35,10 +33,9 @@ describe('GlobalSearch BlobsFilters', () => {
const findLanguageFilter = () => wrapper.findComponent(LanguageFilter);
const findArchivedFilter = () => wrapper.findComponent(ArchivedFilter);
- const findDividers = () => wrapper.findAll('hr');
beforeEach(() => {
- createComponent({});
+ createComponent();
});
it('renders LanguageFilter', () => {
@@ -48,31 +45,4 @@ describe('GlobalSearch BlobsFilters', () => {
it('renders ArchivedFilter', () => {
expect(findArchivedFilter().exists()).toBe(true);
});
-
- it('renders divider correctly', () => {
- expect(findDividers()).toHaveLength(1);
- });
-
- describe('Renders correctly in new nav', () => {
- beforeEach(() => {
- createComponent({
- initialState: {
- searchType: SEARCH_TYPE_ADVANCED,
- useSidebarNavigation: true,
- },
- });
- });
-
- it('renders correctly LanguageFilter', () => {
- expect(findLanguageFilter().exists()).toBe(true);
- });
-
- it('renders correctly ArchivedFilter', () => {
- expect(findArchivedFilter().exists()).toBe(true);
- });
-
- it("doesn't render dividers", () => {
- expect(findDividers()).toHaveLength(0);
- });
- });
});
diff --git a/spec/frontend/search/sidebar/components/confidentiality_filter_spec.js b/spec/frontend/search/sidebar/components/confidentiality_filter_spec.js
index 6444ec10466..fedbd407b0b 100644
--- a/spec/frontend/search/sidebar/components/confidentiality_filter_spec.js
+++ b/spec/frontend/search/sidebar/components/confidentiality_filter_spec.js
@@ -22,23 +22,11 @@ describe('ConfidentialityFilter', () => {
const findRadioFilter = () => wrapper.findComponent(RadioFilter);
- describe('old sidebar', () => {
- beforeEach(() => {
- createComponent({ useSidebarNavigation: false });
- });
-
- it('renders the component', () => {
- expect(findRadioFilter().exists()).toBe(true);
- });
+ beforeEach(() => {
+ createComponent();
});
- describe('new sidebar', () => {
- beforeEach(() => {
- createComponent({ useSidebarNavigation: true });
- });
-
- it('renders the component', () => {
- expect(findRadioFilter().exists()).toBe(true);
- });
+ it('renders the component', () => {
+ expect(findRadioFilter().exists()).toBe(true);
});
});
diff --git a/spec/frontend/search/sidebar/components/filters_template_spec.js b/spec/frontend/search/sidebar/components/filters_template_spec.js
index f1a807c5ceb..18144e25ac3 100644
--- a/spec/frontend/search/sidebar/components/filters_template_spec.js
+++ b/spec/frontend/search/sidebar/components/filters_template_spec.js
@@ -52,7 +52,6 @@ describe('GlobalSearchSidebarLanguageFilter', () => {
};
const findForm = () => wrapper.findComponent(GlForm);
- const findDividers = () => wrapper.findAll('hr');
const findApplyButton = () => wrapper.findComponent(GlButton);
const findResetButton = () => wrapper.findComponent(GlLink);
const findSlotContent = () => wrapper.findByText('Filters Content');
@@ -66,10 +65,6 @@ describe('GlobalSearchSidebarLanguageFilter', () => {
expect(findForm().exists()).toBe(true);
});
- it('renders dividers', () => {
- expect(findDividers()).toHaveLength(2);
- });
-
it('renders slot content', () => {
expect(findSlotContent().exists()).toBe(true);
});
diff --git a/spec/frontend/search/topbar/components/group_filter_spec.js b/spec/frontend/search/sidebar/components/group_filter_spec.js
index fa8036a7f97..a90a8a38267 100644
--- a/spec/frontend/search/topbar/components/group_filter_spec.js
+++ b/spec/frontend/search/sidebar/components/group_filter_spec.js
@@ -1,13 +1,14 @@
import { shallowMount } from '@vue/test-utils';
+import { cloneDeep } from 'lodash';
import Vue from 'vue';
// eslint-disable-next-line no-restricted-imports
import Vuex from 'vuex';
import { MOCK_GROUP, MOCK_QUERY, CURRENT_SCOPE } from 'jest/search/mock_data';
import { visitUrl, setUrlParams } from '~/lib/utils/url_utility';
import { GROUPS_LOCAL_STORAGE_KEY } from '~/search/store/constants';
-import GroupFilter from '~/search/topbar/components/group_filter.vue';
-import SearchableDropdown from '~/search/topbar/components/searchable_dropdown.vue';
-import { ANY_OPTION, GROUP_DATA, PROJECT_DATA } from '~/search/topbar/constants';
+import GroupFilter from '~/search/sidebar/components/group_filter.vue';
+import SearchableDropdown from '~/search/sidebar/components/searchable_dropdown.vue';
+import { ANY_OPTION, GROUP_DATA, PROJECT_DATA } from '~/search/sidebar/constants';
Vue.use(Vuex);
@@ -27,6 +28,7 @@ describe('GroupFilter', () => {
const defaultProps = {
initialData: null,
+ searchHandler: jest.fn(),
};
const createComponent = (initialState, props) => {
@@ -68,19 +70,6 @@ describe('GroupFilter', () => {
createComponent();
});
- describe('when @search is emitted', () => {
- const search = 'test';
-
- beforeEach(() => {
- findSearchableDropdown().vm.$emit('search', search);
- });
-
- it('calls fetchGroups with the search paramter', () => {
- expect(actionSpies.fetchGroups).toHaveBeenCalledTimes(1);
- expect(actionSpies.fetchGroups).toHaveBeenCalledWith(expect.any(Object), search);
- });
- });
-
describe('when @change is emitted with Any', () => {
beforeEach(() => {
findSearchableDropdown().vm.$emit('change', ANY_OPTION);
@@ -148,11 +137,12 @@ describe('GroupFilter', () => {
describe('when initialData is set', () => {
beforeEach(() => {
- createComponent({}, { initialData: MOCK_GROUP });
+ createComponent({ groupInitialJson: { ...MOCK_GROUP } }, {});
});
it('sets selectedGroup to ANY_OPTION', () => {
- expect(wrapper.vm.selectedGroup).toBe(MOCK_GROUP);
+ // cloneDeep to fix Property or method `nodeType` is not defined bug
+ expect(cloneDeep(wrapper.vm.selectedGroup)).toStrictEqual(MOCK_GROUP);
});
});
});
@@ -169,7 +159,13 @@ describe('GroupFilter', () => {
initialData ? 'has' : 'does not have'
} an initial group`, () => {
beforeEach(() => {
- createComponent({ query: { ...MOCK_QUERY, nav_source: navSource } }, { initialData });
+ createComponent(
+ {
+ query: { ...MOCK_QUERY, nav_source: navSource },
+ groupInitialJson: { ...initialData },
+ },
+ {},
+ );
});
it(`${callMethod ? 'does' : 'does not'} call setFrequentGroup`, () => {
diff --git a/spec/frontend/search/sidebar/components/issues_filters_spec.js b/spec/frontend/search/sidebar/components/issues_filters_spec.js
index 860c5c147a6..ce9c6c2bb0c 100644
--- a/spec/frontend/search/sidebar/components/issues_filters_spec.js
+++ b/spec/frontend/search/sidebar/components/issues_filters_spec.js
@@ -19,11 +19,10 @@ describe('GlobalSearch IssuesFilters', () => {
currentScope: () => 'issues',
};
- const createComponent = ({ initialState = {}, searchIssueLabelAggregation = true } = {}) => {
+ const createComponent = ({ initialState = {} } = {}) => {
const store = new Vuex.Store({
state: {
urlQuery: MOCK_QUERY,
- useSidebarNavigation: false,
searchType: SEARCH_TYPE_ADVANCED,
...initialState,
},
@@ -32,11 +31,6 @@ describe('GlobalSearch IssuesFilters', () => {
wrapper = shallowMount(IssuesFilters, {
store,
- provide: {
- glFeatures: {
- searchIssueLabelAggregation,
- },
- },
});
};
@@ -44,17 +38,10 @@ describe('GlobalSearch IssuesFilters', () => {
const findConfidentialityFilter = () => wrapper.findComponent(ConfidentialityFilter);
const findLabelFilter = () => wrapper.findComponent(LabelFilter);
const findArchivedFilter = () => wrapper.findComponent(ArchivedFilter);
- const findDividers = () => wrapper.findAll('hr');
- describe.each`
- description | searchIssueLabelAggregation
- ${'Renders correctly with Label Filter disabled'} | ${false}
- ${'Renders correctly with Label Filter enabled'} | ${true}
- `('$description', ({ searchIssueLabelAggregation }) => {
+ describe('Renders filters correctly with advanced search', () => {
beforeEach(() => {
- createComponent({
- searchIssueLabelAggregation,
- });
+ createComponent();
});
it('renders StatusFilter', () => {
@@ -69,17 +56,8 @@ describe('GlobalSearch IssuesFilters', () => {
expect(findArchivedFilter().exists()).toBe(true);
});
- it(`renders correctly LabelFilter when searchIssueLabelAggregation is ${searchIssueLabelAggregation}`, () => {
- expect(findLabelFilter().exists()).toBe(searchIssueLabelAggregation);
- });
-
- it('renders divider correctly', () => {
- // two dividers can't be disabled
- let dividersCount = 2;
- if (searchIssueLabelAggregation) {
- dividersCount += 1;
- }
- expect(findDividers()).toHaveLength(dividersCount);
+ it('renders correctly LabelFilter', () => {
+ expect(findLabelFilter().exists()).toBe(true);
});
});
@@ -102,41 +80,6 @@ describe('GlobalSearch IssuesFilters', () => {
it("doesn't render ArchivedFilter", () => {
expect(findArchivedFilter().exists()).toBe(true);
});
-
- it('renders 1 divider', () => {
- expect(findDividers()).toHaveLength(2);
- });
- });
-
- describe('Renders correctly in new nav', () => {
- beforeEach(() => {
- createComponent({
- initialState: {
- searchType: SEARCH_TYPE_ADVANCED,
- useSidebarNavigation: true,
- },
- searchIssueLabelAggregation: true,
- });
- });
- it('renders StatusFilter', () => {
- expect(findStatusFilter().exists()).toBe(true);
- });
-
- it('renders ConfidentialityFilter', () => {
- expect(findConfidentialityFilter().exists()).toBe(true);
- });
-
- it('renders LabelFilter', () => {
- expect(findLabelFilter().exists()).toBe(true);
- });
-
- it('renders ArchivedFilter', () => {
- expect(findArchivedFilter().exists()).toBe(true);
- });
-
- it("doesn't render dividers", () => {
- expect(findDividers()).toHaveLength(0);
- });
});
describe('Renders correctly with wrong scope', () => {
@@ -159,9 +102,5 @@ describe('GlobalSearch IssuesFilters', () => {
it("doesn't render ArchivedFilter", () => {
expect(findArchivedFilter().exists()).toBe(false);
});
-
- it("doesn't render dividers", () => {
- expect(findDividers()).toHaveLength(0);
- });
});
});
diff --git a/spec/frontend/search/sidebar/components/label_filter_spec.js b/spec/frontend/search/sidebar/components/label_filter_spec.js
index 9d2a0c5e739..7641036b9f6 100644
--- a/spec/frontend/search/sidebar/components/label_filter_spec.js
+++ b/spec/frontend/search/sidebar/components/label_filter_spec.js
@@ -85,11 +85,6 @@ describe('GlobalSearchSidebarLabelFilter', () => {
wrapper = mountExtended(LabelFilter, {
store,
- provide: {
- glFeatures: {
- searchIssueLabelAggregation: true,
- },
- },
});
};
diff --git a/spec/frontend/search/sidebar/components/merge_requests_filters_spec.js b/spec/frontend/search/sidebar/components/merge_requests_filters_spec.js
index b02228a418f..8cd3cb45a20 100644
--- a/spec/frontend/search/sidebar/components/merge_requests_filters_spec.js
+++ b/spec/frontend/search/sidebar/components/merge_requests_filters_spec.js
@@ -21,7 +21,6 @@ describe('GlobalSearch MergeRequestsFilters', () => {
const store = new Vuex.Store({
state: {
urlQuery: MOCK_QUERY,
- useSidebarNavigation: false,
searchType: SEARCH_TYPE_ADVANCED,
...initialState,
},
@@ -35,7 +34,6 @@ describe('GlobalSearch MergeRequestsFilters', () => {
const findStatusFilter = () => wrapper.findComponent(StatusFilter);
const findArchivedFilter = () => wrapper.findComponent(ArchivedFilter);
- const findDividers = () => wrapper.findAll('hr');
describe('Renders correctly with Archived Filter', () => {
beforeEach(() => {
@@ -46,8 +44,8 @@ describe('GlobalSearch MergeRequestsFilters', () => {
expect(findStatusFilter().exists()).toBe(true);
});
- it('renders divider correctly', () => {
- expect(findDividers()).toHaveLength(1);
+ it('renders ArchivedFilter', () => {
+ expect(findArchivedFilter().exists()).toBe(true);
});
});
@@ -60,33 +58,9 @@ describe('GlobalSearch MergeRequestsFilters', () => {
expect(findStatusFilter().exists()).toBe(true);
});
- it('renders render ArchivedFilter', () => {
- expect(findArchivedFilter().exists()).toBe(true);
- });
-
- it('renders 1 divider', () => {
- expect(findDividers()).toHaveLength(1);
- });
- });
-
- describe('Renders correctly in new nav', () => {
- beforeEach(() => {
- createComponent({
- searchType: SEARCH_TYPE_ADVANCED,
- useSidebarNavigation: true,
- });
- });
- it('renders StatusFilter', () => {
- expect(findStatusFilter().exists()).toBe(true);
- });
-
it('renders ArchivedFilter', () => {
expect(findArchivedFilter().exists()).toBe(true);
});
-
- it("doesn't render divider", () => {
- expect(findDividers()).toHaveLength(0);
- });
});
describe('Renders correctly with wrong scope', () => {
@@ -101,9 +75,5 @@ describe('GlobalSearch MergeRequestsFilters', () => {
it("doesn't render ArchivedFilter", () => {
expect(findArchivedFilter().exists()).toBe(false);
});
-
- it("doesn't render dividers", () => {
- expect(findDividers()).toHaveLength(0);
- });
});
});
diff --git a/spec/frontend/search/topbar/components/project_filter_spec.js b/spec/frontend/search/sidebar/components/project_filter_spec.js
index e7808370098..817ec77380f 100644
--- a/spec/frontend/search/topbar/components/project_filter_spec.js
+++ b/spec/frontend/search/sidebar/components/project_filter_spec.js
@@ -1,13 +1,14 @@
import { shallowMount } from '@vue/test-utils';
+import { cloneDeep } from 'lodash';
import Vue from 'vue';
// eslint-disable-next-line no-restricted-imports
import Vuex from 'vuex';
import { MOCK_PROJECT, MOCK_QUERY, CURRENT_SCOPE } from 'jest/search/mock_data';
import { visitUrl, setUrlParams } from '~/lib/utils/url_utility';
import { PROJECTS_LOCAL_STORAGE_KEY } from '~/search/store/constants';
-import ProjectFilter from '~/search/topbar/components/project_filter.vue';
-import SearchableDropdown from '~/search/topbar/components/searchable_dropdown.vue';
-import { ANY_OPTION, GROUP_DATA, PROJECT_DATA } from '~/search/topbar/constants';
+import ProjectFilter from '~/search/sidebar/components/project_filter.vue';
+import SearchableDropdown from '~/search/sidebar/components/searchable_dropdown.vue';
+import { ANY_OPTION, GROUP_DATA, PROJECT_DATA } from '~/search/sidebar/constants';
Vue.use(Vuex);
@@ -27,12 +28,15 @@ describe('ProjectFilter', () => {
const defaultProps = {
initialData: null,
+ projectInitialJson: MOCK_PROJECT,
+ searchHandler: jest.fn(),
};
const createComponent = (initialState, props) => {
const store = new Vuex.Store({
state: {
query: MOCK_QUERY,
+ projectInitialJson: MOCK_PROJECT,
...initialState,
},
actions: actionSpies,
@@ -68,18 +72,6 @@ describe('ProjectFilter', () => {
createComponent();
});
- describe('when @search is emitted', () => {
- const search = 'test';
-
- beforeEach(() => {
- findSearchableDropdown().vm.$emit('search', search);
- });
-
- it('calls fetchProjects with the search paramter', () => {
- expect(actionSpies.fetchProjects).toHaveBeenCalledWith(expect.any(Object), search);
- });
- });
-
describe('when @change is emitted', () => {
describe('with Any', () => {
beforeEach(() => {
@@ -139,17 +131,17 @@ describe('ProjectFilter', () => {
describe('selectedProject', () => {
describe('when initialData is null', () => {
beforeEach(() => {
- createComponent();
+ createComponent({ projectInitialJson: ANY_OPTION }, {});
});
it('sets selectedProject to ANY_OPTION', () => {
- expect(wrapper.vm.selectedProject).toBe(ANY_OPTION);
+ expect(cloneDeep(wrapper.vm.selectedProject)).toStrictEqual(ANY_OPTION);
});
});
describe('when initialData is set', () => {
beforeEach(() => {
- createComponent({}, { initialData: MOCK_PROJECT });
+ createComponent({ projectInitialJson: MOCK_PROJECT }, {});
});
it('sets selectedProject to the initialData', () => {
@@ -170,7 +162,13 @@ describe('ProjectFilter', () => {
initialData ? 'has' : 'does not have'
} an initial project`, () => {
beforeEach(() => {
- createComponent({ query: { ...MOCK_QUERY, nav_source: navSource } }, { initialData });
+ createComponent(
+ {
+ query: { ...MOCK_QUERY, nav_source: navSource },
+ projectInitialJson: { ...initialData },
+ },
+ {},
+ );
});
it(`${callMethod ? 'does' : 'does not'} call setFrequentProject`, () => {
diff --git a/spec/frontend/search/sidebar/components/scope_legacy_navigation_spec.js b/spec/frontend/search/sidebar/components/scope_legacy_navigation_spec.js
deleted file mode 100644
index 63d8b34fcf0..00000000000
--- a/spec/frontend/search/sidebar/components/scope_legacy_navigation_spec.js
+++ /dev/null
@@ -1,145 +0,0 @@
-import { GlNav, GlNavItem, GlIcon } from '@gitlab/ui';
-import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
-// eslint-disable-next-line no-restricted-imports
-import Vuex from 'vuex';
-import { MOCK_QUERY, MOCK_NAVIGATION } from 'jest/search/mock_data';
-import ScopeLegacyNavigation from '~/search/sidebar/components/scope_legacy_navigation.vue';
-
-Vue.use(Vuex);
-
-const MOCK_NAVIGATION_ENTRIES = Object.entries(MOCK_NAVIGATION);
-
-describe('ScopeLegacyNavigation', () => {
- let wrapper;
-
- const actionSpies = {
- fetchSidebarCount: jest.fn(),
- };
-
- const getterSpies = {
- currentScope: jest.fn(() => 'issues'),
- };
-
- const createComponent = (initialState) => {
- const store = new Vuex.Store({
- state: {
- urlQuery: MOCK_QUERY,
- navigation: MOCK_NAVIGATION,
- ...initialState,
- },
- actions: actionSpies,
- getters: getterSpies,
- });
-
- wrapper = shallowMount(ScopeLegacyNavigation, {
- store,
- });
- };
-
- const findNavElement = () => wrapper.find('nav');
- const findGlNav = () => wrapper.findComponent(GlNav);
- const findGlNavItems = () => wrapper.findAllComponents(GlNavItem);
- const findGlNavItemActive = () => wrapper.find('[active=true]');
- const findGlNavItemActiveLabel = () => findGlNavItemActive().find('[data-testid="label"]');
- const findGlNavItemActiveCount = () => findGlNavItemActive().find('[data-testid="count"]');
-
- 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(MOCK_NAVIGATION_ENTRIES.length);
- });
-
- it('has all proper links', () => {
- const linkAtPosition = 3;
- const { link } = MOCK_NAVIGATION_ENTRIES[linkAtPosition][1];
-
- expect(findGlNavItems().at(linkAtPosition).attributes('href')).toBe(link);
- });
- });
-
- describe('scope navigation sets proper state with url scope set', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('has correct active item', () => {
- expect(findGlNavItemActive().exists()).toBe(true);
- expect(findGlNavItemActiveLabel().text()).toBe('Issues');
- });
-
- it('has correct active item count', () => {
- expect(findGlNavItemActiveCount().text()).toBe('2.4K');
- });
-
- it('does not have plus sign after count text', () => {
- expect(findGlNavItemActive().findComponent(GlIcon).exists()).toBe(false);
- });
-
- it('has count is highlighted correctly', () => {
- expect(findGlNavItemActiveCount().classes('gl-text-gray-900')).toBe(true);
- });
- });
-
- describe('scope navigation sets proper state with NO url scope set', () => {
- beforeEach(() => {
- getterSpies.currentScope = jest.fn(() => 'projects');
- createComponent({
- urlQuery: {},
- navigation: {
- ...MOCK_NAVIGATION,
- projects: {
- ...MOCK_NAVIGATION.projects,
- active: true,
- },
- issues: {
- ...MOCK_NAVIGATION.issues,
- active: false,
- },
- },
- });
- });
-
- it('has correct active item', () => {
- expect(findGlNavItemActive().exists()).toBe(true);
- expect(findGlNavItemActiveLabel().text()).toBe('Projects');
- });
-
- it('has correct active item count', () => {
- expect(findGlNavItemActiveCount().text()).toBe('10K');
- });
-
- it('has correct active item count and over limit sign', () => {
- expect(findGlNavItemActive().findComponent(GlIcon).exists()).toBe(true);
- });
- });
-
- describe.each`
- searchTherm | hasBeenCalled
- ${null} | ${0}
- ${'test'} | ${1}
- `('fetchSidebarCount', ({ searchTherm, hasBeenCalled }) => {
- beforeEach(() => {
- createComponent({
- urlQuery: {
- search: searchTherm,
- },
- });
- });
-
- it('is only called when search term is set', () => {
- expect(actionSpies.fetchSidebarCount).toHaveBeenCalledTimes(hasBeenCalled);
- });
- });
-});
diff --git a/spec/frontend/search/sidebar/components/scope_sidebar_navigation_spec.js b/spec/frontend/search/sidebar/components/scope_sidebar_navigation_spec.js
index d85942b9634..44c243d15f7 100644
--- a/spec/frontend/search/sidebar/components/scope_sidebar_navigation_spec.js
+++ b/spec/frontend/search/sidebar/components/scope_sidebar_navigation_spec.js
@@ -2,6 +2,7 @@ import { mount } from '@vue/test-utils';
import Vue, { nextTick } from 'vue';
// eslint-disable-next-line no-restricted-imports
import Vuex from 'vuex';
+import sidebarEventHub from '~/super_sidebar/event_hub';
import ScopeSidebarNavigation from '~/search/sidebar/components/scope_sidebar_navigation.vue';
import NavItem from '~/super_sidebar/components/nav_item.vue';
import { MOCK_QUERY, MOCK_NAVIGATION, MOCK_NAVIGATION_ITEMS } from '../../mock_data';
@@ -49,6 +50,7 @@ describe('ScopeSidebarNavigation', () => {
describe('scope navigation', () => {
beforeEach(() => {
+ jest.spyOn(sidebarEventHub, '$emit');
createComponent({ urlQuery: { ...MOCK_QUERY, search: 'test' } });
});
@@ -71,6 +73,11 @@ describe('ScopeSidebarNavigation', () => {
expect(findNavItems().at(linkAtPosition).findComponent('a').attributes('href')).toBe(link);
});
+
+ it('always emits toggle-menu-header event', () => {
+ expect(sidebarEventHub.$emit).toHaveBeenCalledWith('toggle-menu-header', false);
+ expect(sidebarEventHub.$emit).toHaveBeenCalledTimes(1);
+ });
});
describe('scope navigation sets proper state with url scope set', () => {
diff --git a/spec/frontend/search/sidebar/components/searchable_dropdown_spec.js b/spec/frontend/search/sidebar/components/searchable_dropdown_spec.js
new file mode 100644
index 00000000000..c8f157e4fe4
--- /dev/null
+++ b/spec/frontend/search/sidebar/components/searchable_dropdown_spec.js
@@ -0,0 +1,117 @@
+import { GlCollapsibleListbox } from '@gitlab/ui';
+import { cloneDeep } from 'lodash';
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+// eslint-disable-next-line no-restricted-imports
+import Vuex from 'vuex';
+import waitForPromises from 'helpers/wait_for_promises';
+import { MOCK_GROUPS, MOCK_QUERY } from 'jest/search/mock_data';
+import SearchableDropdown from '~/search/sidebar/components/searchable_dropdown.vue';
+import { ANY_OPTION, GROUP_DATA } from '~/search/sidebar/constants';
+import { DEFAULT_DEBOUNCE_AND_THROTTLE_MS } from '~/lib/utils/constants';
+
+Vue.use(Vuex);
+
+describe('Global Search Searchable Dropdown', () => {
+ let wrapper;
+
+ const defaultProps = {
+ headerText: GROUP_DATA.headerText,
+ name: GROUP_DATA.name,
+ fullName: GROUP_DATA.fullName,
+ loading: false,
+ selectedItem: ANY_OPTION,
+ items: [],
+ frequentItems: [{ ...MOCK_GROUPS[0] }],
+ searchHandler: jest.fn(),
+ };
+
+ const createComponent = (initialState, props) => {
+ const store = new Vuex.Store({
+ state: {
+ query: MOCK_QUERY,
+ ...initialState,
+ },
+ });
+
+ wrapper = shallowMount(SearchableDropdown, {
+ store,
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ });
+ };
+
+ const findGlDropdown = () => wrapper.findComponent(GlCollapsibleListbox);
+
+ describe('template', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders GlDropdown', () => {
+ expect(findGlDropdown().exists()).toBe(true);
+ });
+
+ const propItems = [
+ { text: '', options: [{ value: ANY_OPTION.name, text: ANY_OPTION.name, ...ANY_OPTION }] },
+ {
+ text: 'Frequently searched',
+ options: [{ value: MOCK_GROUPS[0].id, text: MOCK_GROUPS[0].full_name, ...MOCK_GROUPS[0] }],
+ },
+ {
+ text: 'All available groups',
+ options: [{ value: MOCK_GROUPS[1].id, text: MOCK_GROUPS[1].full_name, ...MOCK_GROUPS[1] }],
+ },
+ ];
+
+ beforeEach(() => {
+ createComponent({}, { items: MOCK_GROUPS });
+ });
+
+ it('contains correct set of items', () => {
+ expect(findGlDropdown().props('items')).toStrictEqual(propItems);
+ });
+
+ it('renders searchable prop', () => {
+ expect(findGlDropdown().props('searchable')).toBe(true);
+ });
+
+ describe('events', () => {
+ it('emits select', () => {
+ findGlDropdown().vm.$emit('select', 1);
+ expect(cloneDeep(wrapper.emitted('change')[0][0])).toStrictEqual(MOCK_GROUPS[0]);
+ });
+
+ it('emits reset', () => {
+ findGlDropdown().vm.$emit('reset');
+ expect(cloneDeep(wrapper.emitted('change')[0][0])).toStrictEqual(ANY_OPTION);
+ });
+
+ it('emits first-open', () => {
+ findGlDropdown().vm.$emit('shown');
+ expect(wrapper.emitted('first-open')).toHaveLength(1);
+ findGlDropdown().vm.$emit('shown');
+ expect(wrapper.emitted('first-open')).toHaveLength(1);
+ });
+ });
+ });
+
+ describe('when @search is emitted', () => {
+ const search = 'test';
+
+ beforeEach(async () => {
+ createComponent();
+ findGlDropdown().vm.$emit('search', search);
+
+ jest.advanceTimersByTime(DEFAULT_DEBOUNCE_AND_THROTTLE_MS);
+ await waitForPromises();
+ });
+
+ it('calls fetchGroups with the search paramter', () => {
+ expect(defaultProps.searchHandler).toHaveBeenCalledTimes(1);
+ expect(defaultProps.searchHandler).toHaveBeenCalledWith(search);
+ });
+ });
+});
diff --git a/spec/frontend/search/sidebar/components/small_screen_drawer_navigation_spec.js b/spec/frontend/search/sidebar/components/small_screen_drawer_navigation_spec.js
deleted file mode 100644
index 5ab4afba7f0..00000000000
--- a/spec/frontend/search/sidebar/components/small_screen_drawer_navigation_spec.js
+++ /dev/null
@@ -1,68 +0,0 @@
-import { nextTick } from 'vue';
-import { GlDrawer } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import DomElementListener from '~/vue_shared/components/dom_element_listener.vue';
-import { DRAWER_Z_INDEX } from '~/lib/utils/constants';
-import SmallScreenDrawerNavigation from '~/search/sidebar/components/small_screen_drawer_navigation.vue';
-
-describe('ScopeLegacyNavigation', () => {
- let wrapper;
- let closeSpy;
- let toggleSpy;
-
- const createComponent = () => {
- wrapper = shallowMountExtended(SmallScreenDrawerNavigation, {
- slots: {
- default: '<div data-testid="default-slot-content">test</div>',
- },
- });
- };
-
- const findGlDrawer = () => wrapper.findComponent(GlDrawer);
- const findTitle = () => wrapper.findComponent('h2');
- const findSlot = () => wrapper.findByTestId('default-slot-content');
- const findDomElementListener = () => wrapper.findComponent(DomElementListener);
-
- describe('small screen navigation', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders drawer', () => {
- expect(findGlDrawer().exists()).toBe(true);
- expect(findGlDrawer().attributes('zindex')).toBe(DRAWER_Z_INDEX.toString());
- expect(findGlDrawer().attributes('headerheight')).toBe('0');
- });
-
- it('renders title', () => {
- expect(findTitle().exists()).toBe(true);
- });
-
- it('renders slots', () => {
- expect(findSlot().exists()).toBe(true);
- });
- });
-
- describe('actions', () => {
- beforeEach(() => {
- closeSpy = jest.spyOn(SmallScreenDrawerNavigation.methods, 'closeSmallScreenFilters');
- toggleSpy = jest.spyOn(SmallScreenDrawerNavigation.methods, 'toggleSmallScreenFilters');
- createComponent();
- });
-
- it('calls onClose', () => {
- findGlDrawer().vm.$emit('close');
- expect(closeSpy).toHaveBeenCalled();
- });
-
- it('calls toggleSmallScreenFilters', async () => {
- expect(findGlDrawer().props('open')).toBe(false);
-
- findDomElementListener().vm.$emit('click');
- await nextTick();
-
- expect(toggleSpy).toHaveBeenCalled();
- expect(findGlDrawer().props('open')).toBe(true);
- });
- });
-});
diff --git a/spec/frontend/search/sidebar/components/status_filter_spec.js b/spec/frontend/search/sidebar/components/status_filter_spec.js
index c230341c172..719932a79ef 100644
--- a/spec/frontend/search/sidebar/components/status_filter_spec.js
+++ b/spec/frontend/search/sidebar/components/status_filter_spec.js
@@ -22,23 +22,9 @@ describe('StatusFilter', () => {
const findRadioFilter = () => wrapper.findComponent(RadioFilter);
- describe('old sidebar', () => {
- beforeEach(() => {
- createComponent({ useSidebarNavigation: false });
- });
-
- it('renders the component', () => {
- expect(findRadioFilter().exists()).toBe(true);
- });
- });
+ it('renders the component', () => {
+ createComponent();
- describe('new sidebar', () => {
- beforeEach(() => {
- createComponent({ useSidebarNavigation: true });
- });
-
- it('renders the component', () => {
- expect(findRadioFilter().exists()).toBe(true);
- });
+ expect(findRadioFilter().exists()).toBe(true);
});
});
diff --git a/spec/frontend/search/store/mutations_spec.js b/spec/frontend/search/store/mutations_spec.js
index a517932b0eb..3462d4a326b 100644
--- a/spec/frontend/search/store/mutations_spec.js
+++ b/spec/frontend/search/store/mutations_spec.js
@@ -31,7 +31,7 @@ describe('Global Search Store Mutations', () => {
mutations[types.RECEIVE_GROUPS_SUCCESS](state, MOCK_GROUPS);
expect(state.fetchingGroups).toBe(false);
- expect(state.groups).toBe(MOCK_GROUPS);
+ expect(state.groups).toStrictEqual(MOCK_GROUPS);
});
});
@@ -57,7 +57,7 @@ describe('Global Search Store Mutations', () => {
mutations[types.RECEIVE_PROJECTS_SUCCESS](state, MOCK_PROJECTS);
expect(state.fetchingProjects).toBe(false);
- expect(state.projects).toBe(MOCK_PROJECTS);
+ expect(state.projects).toStrictEqual(MOCK_PROJECTS);
});
});
diff --git a/spec/frontend/search/topbar/components/app_spec.js b/spec/frontend/search/topbar/components/app_spec.js
index 9704277c86b..d17bdc2a6e1 100644
--- a/spec/frontend/search/topbar/components/app_spec.js
+++ b/spec/frontend/search/topbar/components/app_spec.js
@@ -1,14 +1,14 @@
-import { GlSearchBoxByClick, GlButton } from '@gitlab/ui';
+import { GlSearchBoxByType, GlButton } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
-import Vue from 'vue';
+import Vue, { nextTick } from 'vue';
// eslint-disable-next-line no-restricted-imports
import Vuex from 'vuex';
import { MOCK_QUERY } from 'jest/search/mock_data';
import { stubComponent } from 'helpers/stub_component';
import GlobalSearchTopbar from '~/search/topbar/components/app.vue';
-import GroupFilter from '~/search/topbar/components/group_filter.vue';
-import ProjectFilter from '~/search/topbar/components/project_filter.vue';
import MarkdownDrawer from '~/vue_shared/components/markdown_drawer/markdown_drawer.vue';
+import SearchTypeIndicator from '~/search/topbar/components/search_type_indicator.vue';
+import { ENTER_KEY } from '~/lib/utils/keys';
import {
SYNTAX_OPTIONS_ADVANCED_DOCUMENT,
SYNTAX_OPTIONS_ZOEKT_DOCUMENT,
@@ -41,42 +41,22 @@ describe('GlobalSearchTopbar', () => {
});
};
- const findGlSearchBox = () => wrapper.findComponent(GlSearchBoxByClick);
- const findGroupFilter = () => wrapper.findComponent(GroupFilter);
- const findProjectFilter = () => wrapper.findComponent(ProjectFilter);
+ const findGlSearchBox = () => wrapper.findComponent(GlSearchBoxByType);
const findSyntaxOptionButton = () => wrapper.findComponent(GlButton);
const findSyntaxOptionDrawer = () => wrapper.findComponent(MarkdownDrawer);
+ const findSearchTypeIndicator = () => wrapper.findComponent(SearchTypeIndicator);
describe('template', () => {
beforeEach(() => {
createComponent();
});
- describe('Search box', () => {
- it('renders always', () => {
- expect(findGlSearchBox().exists()).toBe(true);
- });
+ it('always renders Search box', () => {
+ expect(findGlSearchBox().exists()).toBe(true);
});
- describe.each`
- snippets | showFilters
- ${null} | ${true}
- ${{ query: { snippets: '' } }} | ${true}
- ${{ query: { snippets: false } }} | ${true}
- ${{ query: { snippets: true } }} | ${false}
- ${{ query: { snippets: 'false' } }} | ${true}
- ${{ query: { snippets: 'true' } }} | ${false}
- `('topbar filters', ({ snippets, showFilters }) => {
- beforeEach(() => {
- createComponent(snippets);
- });
-
- it(`does${showFilters ? '' : ' not'} render when snippets is ${JSON.stringify(
- snippets,
- )}`, () => {
- expect(findGroupFilter().exists()).toBe(showFilters);
- expect(findProjectFilter().exists()).toBe(showFilters);
- });
+ it('always renders Search indicator', () => {
+ expect(findSearchTypeIndicator().exists()).toBe(true);
});
describe.each`
@@ -128,15 +108,15 @@ describe('GlobalSearchTopbar', () => {
});
describe.each`
- state | defaultBranchName | hasSyntaxOptions
- ${{ query: { repository_ref: '' }, searchType: 'basic' }} | ${'master'} | ${false}
- ${{ query: { repository_ref: 'v0.1' }, searchType: 'basic' }} | ${''} | ${false}
- ${{ query: { repository_ref: 'master' }, searchType: 'basic' }} | ${'master'} | ${false}
- ${{ query: { repository_ref: 'master' }, searchType: 'advanced' }} | ${''} | ${false}
- ${{ query: { repository_ref: '' }, searchType: 'advanced' }} | ${'master'} | ${true}
- ${{ query: { repository_ref: 'v0.1' }, searchType: 'advanced' }} | ${''} | ${false}
- ${{ query: { repository_ref: 'master' }, searchType: 'advanced' }} | ${'master'} | ${true}
- ${{ query: { repository_ref: 'master' }, searchType: 'zoekt' }} | ${'master'} | ${true}
+ state | hasSyntaxOptions
+ ${{ query: { repository_ref: '' }, searchType: 'basic', searchLevel: 'project', defaultBranchName: 'master' }} | ${false}
+ ${{ query: { repository_ref: 'v0.1' }, searchType: 'basic', searchLevel: 'project', defaultBranchName: '' }} | ${false}
+ ${{ query: { repository_ref: 'master' }, searchType: 'basic', searchLevel: 'project', defaultBranchName: 'master' }} | ${false}
+ ${{ query: { repository_ref: 'master' }, searchType: 'advanced', searchLevel: 'project', defaultBranchName: '' }} | ${false}
+ ${{ query: { repository_ref: '' }, searchType: 'advanced', searchLevel: 'project', defaultBranchName: 'master' }} | ${true}
+ ${{ query: { repository_ref: 'v0.1' }, searchType: 'advanced', searchLevel: 'project', defaultBranchName: '' }} | ${false}
+ ${{ query: { repository_ref: 'master' }, searchType: 'advanced', searchLevel: 'project', defaultBranchName: 'master' }} | ${true}
+ ${{ query: { repository_ref: 'master' }, searchType: 'zoekt', searchLevel: 'project', defaultBranchName: 'master' }} | ${true}
`(
`the syntax option based on component state`,
({ state, defaultBranchName, hasSyntaxOptions }) => {
@@ -162,9 +142,10 @@ describe('GlobalSearchTopbar', () => {
createComponent();
});
- it('clicking search button inside search box calls applyQuery', () => {
- findGlSearchBox().vm.$emit('submit', { preventDefault: () => {} });
+ it('clicking search button inside search box calls applyQuery', async () => {
+ await nextTick();
+ findGlSearchBox().vm.$emit('keydown', new KeyboardEvent({ key: ENTER_KEY }));
expect(actionSpies.applyQuery).toHaveBeenCalled();
});
});
diff --git a/spec/frontend/search/topbar/components/search_type_indicator_spec.js b/spec/frontend/search/topbar/components/search_type_indicator_spec.js
new file mode 100644
index 00000000000..d69ca6dfb16
--- /dev/null
+++ b/spec/frontend/search/topbar/components/search_type_indicator_spec.js
@@ -0,0 +1,128 @@
+import Vue from 'vue';
+// eslint-disable-next-line no-restricted-imports
+import Vuex from 'vuex';
+import { GlSprintf } from '@gitlab/ui';
+import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
+import { MOCK_QUERY } from 'jest/search/mock_data';
+import SearchTypeIndicator from '~/search/topbar/components/search_type_indicator.vue';
+
+Vue.use(Vuex);
+
+describe('SearchTypeIndicator', () => {
+ let wrapper;
+
+ const actionSpies = {
+ applyQuery: jest.fn(),
+ setQuery: jest.fn(),
+ preloadStoredFrequentItems: jest.fn(),
+ };
+
+ const createComponent = (initialState = {}) => {
+ const store = new Vuex.Store({
+ state: {
+ query: MOCK_QUERY,
+ ...initialState,
+ },
+ actions: actionSpies,
+ });
+
+ wrapper = shallowMountExtended(SearchTypeIndicator, {
+ store,
+ stubs: {
+ GlSprintf,
+ },
+ });
+ };
+
+ const findIndicator = (id) => wrapper.findAllByTestId(id);
+ const findDocsLink = () => wrapper.findComponentByTestId('docs-link');
+ const findSyntaxDocsLink = () => wrapper.findComponentByTestId('syntax-docs-link');
+
+ // searchType and search level params cobination in this test reflects
+ // all possible combinations
+
+ describe.each`
+ searchType | searchLevel | repository | showSearchTypeIndicator
+ ${'advanced'} | ${'project'} | ${'master'} | ${'advanced-enabled'}
+ ${'advanced'} | ${'project'} | ${'v0.1'} | ${'advanced-disabled'}
+ ${'advanced'} | ${'group'} | ${'master'} | ${'advanced-enabled'}
+ ${'advanced'} | ${'global'} | ${'master'} | ${'advanced-enabled'}
+ ${'zoekt'} | ${'project'} | ${'master'} | ${'zoekt-enabled'}
+ ${'zoekt'} | ${'project'} | ${'v0.1'} | ${'zoekt-disabled'}
+ ${'zoekt'} | ${'group'} | ${'master'} | ${'zoekt-enabled'}
+ `(
+ 'search type indicator for $searchType $searchLevel',
+ ({ searchType, repository, showSearchTypeIndicator, searchLevel }) => {
+ beforeEach(() => {
+ createComponent({
+ query: { repository_ref: repository },
+ searchType,
+ searchLevel,
+ defaultBranchName: 'master',
+ });
+ });
+ it('renders correctly', () => {
+ expect(findIndicator(showSearchTypeIndicator).exists()).toBe(true);
+ });
+ },
+ );
+
+ describe.each`
+ searchType | repository | showSearchTypeIndicator
+ ${'basic'} | ${'master'} | ${true}
+ ${'basic'} | ${'v0.1'} | ${true}
+ `(
+ 'search type indicator for $searchType and $repository',
+ ({ searchType, repository, showSearchTypeIndicator }) => {
+ beforeEach(() => {
+ createComponent({
+ query: { repository_ref: repository },
+ searchType,
+ defaultBranchName: 'master',
+ });
+ });
+ it.each(['zoekt-enabled', 'zoekt-disabled', 'advanced-enabled', 'advanced-disabled'])(
+ 'renders correct indicator %s',
+ () => {
+ expect(findIndicator(searchType).exists()).toBe(showSearchTypeIndicator);
+ },
+ );
+ },
+ );
+
+ describe.each`
+ searchType | docsLink
+ ${'advanced'} | ${'/help/user/search/advanced_search'}
+ ${'zoekt'} | ${'/help/user/search/exact_code_search'}
+ `('documentation link for $searchType', ({ searchType, docsLink }) => {
+ beforeEach(() => {
+ createComponent({
+ query: { repository_ref: 'master' },
+ searchType,
+ searchLevel: 'project',
+ defaultBranchName: 'master',
+ });
+ });
+ it('has correct link', () => {
+ expect(findDocsLink().attributes('href')).toBe(docsLink);
+ });
+ });
+
+ describe.each`
+ searchType | syntaxdocsLink
+ ${'advanced'} | ${'/help/user/search/advanced_search#use-the-advanced-search-syntax'}
+ ${'zoekt'} | ${'/help/user/search/exact_code_search#syntax'}
+ `('Syntax documentation $searchType', ({ searchType, syntaxdocsLink }) => {
+ beforeEach(() => {
+ createComponent({
+ query: { repository_ref: '000' },
+ searchType,
+ searchLevel: 'project',
+ defaultBranchName: 'master',
+ });
+ });
+ it('has correct link', () => {
+ expect(findSyntaxDocsLink().attributes('href')).toBe(syntaxdocsLink);
+ });
+ });
+});
diff --git a/spec/frontend/search/topbar/components/searchable_dropdown_item_spec.js b/spec/frontend/search/topbar/components/searchable_dropdown_item_spec.js
deleted file mode 100644
index c911fe53d40..00000000000
--- a/spec/frontend/search/topbar/components/searchable_dropdown_item_spec.js
+++ /dev/null
@@ -1,93 +0,0 @@
-import { GlDropdownItem, GlAvatar } from '@gitlab/ui';
-import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import { MOCK_GROUPS } from 'jest/search/mock_data';
-import { truncateNamespace } from '~/lib/utils/text_utility';
-import SearchableDropdownItem from '~/search/topbar/components/searchable_dropdown_item.vue';
-import { GROUP_DATA } from '~/search/topbar/constants';
-
-describe('Global Search Searchable Dropdown Item', () => {
- let wrapper;
-
- const defaultProps = {
- item: MOCK_GROUPS[0],
- selectedItem: MOCK_GROUPS[0],
- name: GROUP_DATA.name,
- fullName: GROUP_DATA.fullName,
- };
-
- const createComponent = (props) => {
- wrapper = shallowMountExtended(SearchableDropdownItem, {
- propsData: {
- ...defaultProps,
- ...props,
- },
- });
- };
-
- const findGlDropdownItem = () => wrapper.findComponent(GlDropdownItem);
- const findGlAvatar = () => wrapper.findComponent(GlAvatar);
- const findDropdownTitle = () => wrapper.findByTestId('item-title');
- const findDropdownSubtitle = () => wrapper.findByTestId('item-namespace');
-
- describe('template', () => {
- describe('always', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders GlDropdownItem', () => {
- expect(findGlDropdownItem().exists()).toBe(true);
- });
-
- it('renders GlAvatar', () => {
- expect(findGlAvatar().exists()).toBe(true);
- });
-
- it('renders Dropdown Title correctly', () => {
- const titleEl = findDropdownTitle();
-
- expect(titleEl.exists()).toBe(true);
- expect(titleEl.text()).toBe(MOCK_GROUPS[0][GROUP_DATA.name]);
- });
-
- it('renders Dropdown Subtitle correctly', () => {
- const subtitleEl = findDropdownSubtitle();
-
- expect(subtitleEl.exists()).toBe(true);
- expect(subtitleEl.text()).toBe(truncateNamespace(MOCK_GROUPS[0][GROUP_DATA.fullName]));
- });
- });
-
- describe('when item === selectedItem', () => {
- beforeEach(() => {
- createComponent({ item: MOCK_GROUPS[0], selectedItem: MOCK_GROUPS[0] });
- });
-
- it('marks the dropdown as checked', () => {
- expect(findGlDropdownItem().attributes('ischecked')).toBe('true');
- });
- });
-
- describe('when item !== selectedItem', () => {
- beforeEach(() => {
- createComponent({ item: MOCK_GROUPS[0], selectedItem: MOCK_GROUPS[1] });
- });
-
- it('marks the dropdown as not checked', () => {
- expect(findGlDropdownItem().attributes('ischecked')).toBeUndefined();
- });
- });
- });
-
- describe('actions', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('clicking the dropdown item $emits change with the item', () => {
- findGlDropdownItem().vm.$emit('click');
-
- expect(wrapper.emitted('change')[0]).toEqual([MOCK_GROUPS[0]]);
- });
- });
-});
diff --git a/spec/frontend/search/topbar/components/searchable_dropdown_spec.js b/spec/frontend/search/topbar/components/searchable_dropdown_spec.js
deleted file mode 100644
index 5acaa1c1900..00000000000
--- a/spec/frontend/search/topbar/components/searchable_dropdown_spec.js
+++ /dev/null
@@ -1,220 +0,0 @@
-import { GlDropdown, GlDropdownItem, GlSearchBoxByType, GlSkeletonLoader } from '@gitlab/ui';
-import { shallowMount, mount } from '@vue/test-utils';
-import Vue, { nextTick } from 'vue';
-// eslint-disable-next-line no-restricted-imports
-import Vuex from 'vuex';
-import { extendedWrapper } from 'helpers/vue_test_utils_helper';
-import { MOCK_GROUPS, MOCK_GROUP, MOCK_QUERY } from 'jest/search/mock_data';
-import SearchableDropdown from '~/search/topbar/components/searchable_dropdown.vue';
-import { ANY_OPTION, GROUP_DATA } from '~/search/topbar/constants';
-
-Vue.use(Vuex);
-
-describe('Global Search Searchable Dropdown', () => {
- let wrapper;
-
- const defaultProps = {
- headerText: GROUP_DATA.headerText,
- name: GROUP_DATA.name,
- fullName: GROUP_DATA.fullName,
- loading: false,
- selectedItem: ANY_OPTION,
- items: [],
- };
-
- const createComponent = (initialState, props, mountFn = shallowMount) => {
- const store = new Vuex.Store({
- state: {
- query: MOCK_QUERY,
- ...initialState,
- },
- });
-
- wrapper = extendedWrapper(
- mountFn(SearchableDropdown, {
- store,
- propsData: {
- ...defaultProps,
- ...props,
- },
- }),
- );
- };
-
- const findGlDropdown = () => wrapper.findComponent(GlDropdown);
- const findGlDropdownSearch = () => findGlDropdown().findComponent(GlSearchBoxByType);
- const findDropdownText = () => findGlDropdown().find('.dropdown-toggle-text');
- const findSearchableDropdownItems = () => wrapper.findAllByTestId('searchable-items');
- const findFrequentDropdownItems = () => wrapper.findAllByTestId('frequent-items');
- const findAnyDropdownItem = () => findGlDropdown().findComponent(GlDropdownItem);
- const findFirstSearchableDropdownItem = () => findSearchableDropdownItems().at(0);
- const findFirstFrequentDropdownItem = () => findFrequentDropdownItems().at(0);
- const findLoader = () => wrapper.findComponent(GlSkeletonLoader);
-
- describe('template', () => {
- beforeEach(() => {
- createComponent();
- });
-
- it('renders GlDropdown', () => {
- expect(findGlDropdown().exists()).toBe(true);
- });
-
- describe('findGlDropdownSearch', () => {
- it('renders always', () => {
- expect(findGlDropdownSearch().exists()).toBe(true);
- });
-
- it('has debounce prop', () => {
- expect(findGlDropdownSearch().attributes('debounce')).toBe('500');
- });
-
- describe('onSearch', () => {
- const search = 'test search';
-
- beforeEach(() => {
- findGlDropdownSearch().vm.$emit('input', search);
- });
-
- it('$emits @search when input event is fired from GlSearchBoxByType', () => {
- expect(wrapper.emitted('search')[0]).toEqual([search]);
- });
- });
- });
-
- describe('Searchable Dropdown Items', () => {
- describe('when loading is false', () => {
- beforeEach(() => {
- createComponent({}, { items: MOCK_GROUPS });
- });
-
- it('does not render loader', () => {
- expect(findLoader().exists()).toBe(false);
- });
-
- it('renders the Any Dropdown', () => {
- expect(findAnyDropdownItem().exists()).toBe(true);
- });
-
- it('renders searchable dropdown item for each item', () => {
- expect(findSearchableDropdownItems()).toHaveLength(MOCK_GROUPS.length);
- });
- });
-
- describe('when loading is true', () => {
- beforeEach(() => {
- createComponent({}, { loading: true, items: MOCK_GROUPS });
- });
-
- it('does render loader', () => {
- expect(findLoader().exists()).toBe(true);
- });
-
- it('renders the Any Dropdown', () => {
- expect(findAnyDropdownItem().exists()).toBe(true);
- });
-
- it('does not render searchable dropdown items', () => {
- expect(findSearchableDropdownItems()).toHaveLength(0);
- });
- });
- });
-
- describe.each`
- searchText | frequentItems | length
- ${''} | ${[]} | ${0}
- ${''} | ${MOCK_GROUPS} | ${MOCK_GROUPS.length}
- ${'test'} | ${[]} | ${0}
- ${'test'} | ${MOCK_GROUPS} | ${0}
- `('Frequent Dropdown Items', ({ searchText, frequentItems, length }) => {
- describe(`when search is ${searchText} and frequentItems length is ${frequentItems.length}`, () => {
- beforeEach(() => {
- createComponent({}, { frequentItems });
- findGlDropdownSearch().vm.$emit('input', searchText);
- });
-
- it(`should${length ? '' : ' not'} render frequent dropdown items`, () => {
- expect(findFrequentDropdownItems()).toHaveLength(length);
- });
- });
- });
-
- describe('Dropdown Text', () => {
- describe('when selectedItem is any', () => {
- beforeEach(() => {
- createComponent({}, {}, mount);
- });
-
- it('sets dropdown text to Any', () => {
- expect(findDropdownText().text()).toBe(ANY_OPTION.name);
- });
- });
-
- describe('selectedItem is set', () => {
- beforeEach(() => {
- createComponent({}, { selectedItem: MOCK_GROUP }, mount);
- });
-
- it('sets dropdown text to the selectedItem name', () => {
- expect(findDropdownText().text()).toBe(MOCK_GROUP[GROUP_DATA.name]);
- });
- });
- });
- });
-
- describe('actions', () => {
- beforeEach(() => {
- createComponent({}, { items: MOCK_GROUPS, frequentItems: MOCK_GROUPS });
- });
-
- it('clicking "Any" dropdown item $emits @change with ANY_OPTION', () => {
- findAnyDropdownItem().vm.$emit('click');
-
- expect(wrapper.emitted('change')[0]).toEqual([ANY_OPTION]);
- });
-
- it('on searchable item @change, the wrapper $emits change with the item', () => {
- findFirstSearchableDropdownItem().vm.$emit('change', MOCK_GROUPS[0]);
-
- expect(wrapper.emitted('change')[0]).toEqual([MOCK_GROUPS[0]]);
- });
-
- it('on frequent item @change, the wrapper $emits change with the item', () => {
- findFirstFrequentDropdownItem().vm.$emit('change', MOCK_GROUPS[0]);
-
- expect(wrapper.emitted('change')[0]).toEqual([MOCK_GROUPS[0]]);
- });
-
- describe('opening the dropdown', () => {
- beforeEach(() => {
- findGlDropdown().vm.$emit('show');
- });
-
- it('$emits @search and @first-open on the first open', () => {
- expect(wrapper.emitted('search')[0]).toStrictEqual(['']);
- expect(wrapper.emitted('first-open')[0]).toStrictEqual([]);
- });
-
- describe('when the dropdown has been opened', () => {
- it('$emits @search with the searchText', async () => {
- const searchText = 'foo';
-
- findGlDropdownSearch().vm.$emit('input', searchText);
- await nextTick();
-
- expect(wrapper.emitted('search')[1]).toStrictEqual([searchText]);
- expect(wrapper.emitted('first-open')).toHaveLength(1);
- });
-
- it('does not emit @first-open again', async () => {
- expect(wrapper.emitted('first-open')).toHaveLength(1);
-
- findGlDropdownSearch().vm.$emit('input');
- await nextTick();
-
- expect(wrapper.emitted('first-open')).toHaveLength(1);
- });
- });
- });
- });
-});