summaryrefslogtreecommitdiff
path: root/spec/frontend/search
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/search')
-rw-r--r--spec/frontend/search/highlight_blob_search_result_spec.js3
-rw-r--r--spec/frontend/search/index_spec.js3
-rw-r--r--spec/frontend/search/mock_data.js22
-rw-r--r--spec/frontend/search/sidebar/components/app_spec.js4
-rw-r--r--spec/frontend/search/sidebar/components/confidentiality_filter_spec.js2
-rw-r--r--spec/frontend/search/sidebar/components/radio_filter_spec.js6
-rw-r--r--spec/frontend/search/sidebar/components/status_filter_spec.js4
-rw-r--r--spec/frontend/search/sort/components/app_spec.js168
-rw-r--r--spec/frontend/search/store/actions_spec.js6
-rw-r--r--spec/frontend/search/store/mutations_spec.js2
-rw-r--r--spec/frontend/search/topbar/components/app_spec.js113
-rw-r--r--spec/frontend/search/topbar/components/group_filter_spec.js2
-rw-r--r--spec/frontend/search/topbar/components/project_filter_spec.js4
-rw-r--r--spec/frontend/search/topbar/components/searchable_dropdown_spec.js4
14 files changed, 322 insertions, 21 deletions
diff --git a/spec/frontend/search/highlight_blob_search_result_spec.js b/spec/frontend/search/highlight_blob_search_result_spec.js
index 112e6f5124f..c1b0c7d794b 100644
--- a/spec/frontend/search/highlight_blob_search_result_spec.js
+++ b/spec/frontend/search/highlight_blob_search_result_spec.js
@@ -1,6 +1,7 @@
import setHighlightClass from '~/search/highlight_blob_search_result';
const fixture = 'search/blob_search_result.html';
+const searchKeyword = 'Send'; // spec/frontend/fixtures/search.rb#79
describe('search/highlight_blob_search_result', () => {
preloadFixtures(fixture);
@@ -8,7 +9,7 @@ describe('search/highlight_blob_search_result', () => {
beforeEach(() => loadFixtures(fixture));
it('highlights lines with search term occurrence', () => {
- setHighlightClass();
+ setHighlightClass(searchKeyword);
expect(document.querySelectorAll('.blob-result .hll').length).toBe(4);
});
diff --git a/spec/frontend/search/index_spec.js b/spec/frontend/search/index_spec.js
index 023cd341345..1992a7f4437 100644
--- a/spec/frontend/search/index_spec.js
+++ b/spec/frontend/search/index_spec.js
@@ -1,9 +1,11 @@
+import setHighlightClass from 'ee_else_ce/search/highlight_blob_search_result';
import { initSearchApp } from '~/search';
import createStore from '~/search/store';
jest.mock('~/search/store');
jest.mock('~/search/topbar');
jest.mock('~/search/sidebar');
+jest.mock('ee_else_ce/search/highlight_blob_search_result');
describe('initSearchApp', () => {
let defaultLocation;
@@ -42,6 +44,7 @@ describe('initSearchApp', () => {
it(`decodes ${search} to ${decodedSearch}`, () => {
expect(createStore).toHaveBeenCalledWith({ query: { search: decodedSearch } });
+ expect(setHighlightClass).toHaveBeenCalledWith(decodedSearch);
});
});
});
diff --git a/spec/frontend/search/mock_data.js b/spec/frontend/search/mock_data.js
index ee509eaad8d..d076997b04a 100644
--- a/spec/frontend/search/mock_data.js
+++ b/spec/frontend/search/mock_data.js
@@ -26,7 +26,7 @@ export const MOCK_GROUPS = [
export const MOCK_PROJECT = {
name: 'test project',
- namespace_id: MOCK_GROUP.id,
+ namespace: MOCK_GROUP,
nameWithNamespace: 'test group test project',
id: 'test_1',
};
@@ -34,14 +34,30 @@ export const MOCK_PROJECT = {
export const MOCK_PROJECTS = [
{
name: 'test project',
- namespace_id: MOCK_GROUP.id,
+ namespace: MOCK_GROUP,
name_with_namespace: 'test group test project',
id: 'test_1',
},
{
name: 'test project 2',
- namespace_id: MOCK_GROUP.id,
+ namespace: MOCK_GROUP,
name_with_namespace: 'test group test project 2',
id: 'test_2',
},
];
+
+export const MOCK_SORT_OPTIONS = [
+ {
+ title: 'Most relevant',
+ sortable: false,
+ sortParam: 'relevant',
+ },
+ {
+ title: 'Created date',
+ sortable: true,
+ sortParam: {
+ asc: 'created_asc',
+ desc: 'created_desc',
+ },
+ },
+];
diff --git a/spec/frontend/search/sidebar/components/app_spec.js b/spec/frontend/search/sidebar/components/app_spec.js
index 94a39b90d02..b93527c1fe9 100644
--- a/spec/frontend/search/sidebar/components/app_spec.js
+++ b/spec/frontend/search/sidebar/components/app_spec.js
@@ -1,6 +1,6 @@
-import Vuex from 'vuex';
-import { createLocalVue, shallowMount } from '@vue/test-utils';
import { GlButton, GlLink } from '@gitlab/ui';
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+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';
diff --git a/spec/frontend/search/sidebar/components/confidentiality_filter_spec.js b/spec/frontend/search/sidebar/components/confidentiality_filter_spec.js
index 42fcc859308..3713e1d414f 100644
--- a/spec/frontend/search/sidebar/components/confidentiality_filter_spec.js
+++ b/spec/frontend/search/sidebar/components/confidentiality_filter_spec.js
@@ -1,5 +1,5 @@
-import Vuex from 'vuex';
import { createLocalVue, shallowMount } from '@vue/test-utils';
+import Vuex from 'vuex';
import { MOCK_QUERY } from 'jest/search/mock_data';
import ConfidentialityFilter from '~/search/sidebar/components/confidentiality_filter.vue';
import RadioFilter from '~/search/sidebar/components/radio_filter.vue';
diff --git a/spec/frontend/search/sidebar/components/radio_filter_spec.js b/spec/frontend/search/sidebar/components/radio_filter_spec.js
index 9918af54cfe..4c81312e479 100644
--- a/spec/frontend/search/sidebar/components/radio_filter_spec.js
+++ b/spec/frontend/search/sidebar/components/radio_filter_spec.js
@@ -1,10 +1,10 @@
-import Vuex from 'vuex';
-import { createLocalVue, shallowMount } from '@vue/test-utils';
import { GlFormRadioGroup, GlFormRadio } from '@gitlab/ui';
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import Vuex from 'vuex';
import { MOCK_QUERY } from 'jest/search/mock_data';
import RadioFilter from '~/search/sidebar/components/radio_filter.vue';
-import { stateFilterData } from '~/search/sidebar/constants/state_filter_data';
import { confidentialFilterData } from '~/search/sidebar/constants/confidential_filter_data';
+import { stateFilterData } from '~/search/sidebar/constants/state_filter_data';
const localVue = createLocalVue();
localVue.use(Vuex);
diff --git a/spec/frontend/search/sidebar/components/status_filter_spec.js b/spec/frontend/search/sidebar/components/status_filter_spec.js
index 21fc663397e..08ce57b206b 100644
--- a/spec/frontend/search/sidebar/components/status_filter_spec.js
+++ b/spec/frontend/search/sidebar/components/status_filter_spec.js
@@ -1,8 +1,8 @@
-import Vuex from 'vuex';
import { createLocalVue, shallowMount } from '@vue/test-utils';
+import Vuex from 'vuex';
import { MOCK_QUERY } from 'jest/search/mock_data';
-import StatusFilter from '~/search/sidebar/components/status_filter.vue';
import RadioFilter from '~/search/sidebar/components/radio_filter.vue';
+import StatusFilter from '~/search/sidebar/components/status_filter.vue';
const localVue = createLocalVue();
localVue.use(Vuex);
diff --git a/spec/frontend/search/sort/components/app_spec.js b/spec/frontend/search/sort/components/app_spec.js
new file mode 100644
index 00000000000..5806d6b51d2
--- /dev/null
+++ b/spec/frontend/search/sort/components/app_spec.js
@@ -0,0 +1,168 @@
+import { GlButtonGroup, GlButton, GlDropdown, GlDropdownItem } from '@gitlab/ui';
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import Vuex from 'vuex';
+import { MOCK_QUERY, MOCK_SORT_OPTIONS } from 'jest/search/mock_data';
+import GlobalSearchSort from '~/search/sort/components/app.vue';
+import { SORT_DIRECTION_UI } from '~/search/sort/constants';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('GlobalSearchSort', () => {
+ let wrapper;
+
+ const actionSpies = {
+ setQuery: jest.fn(),
+ applyQuery: jest.fn(),
+ };
+
+ const defaultProps = {
+ searchSortOptions: MOCK_SORT_OPTIONS,
+ };
+
+ const createComponent = (initialState, props) => {
+ const store = new Vuex.Store({
+ state: {
+ query: MOCK_QUERY,
+ ...initialState,
+ },
+ actions: actionSpies,
+ });
+
+ wrapper = shallowMount(GlobalSearchSort, {
+ localVue,
+ store,
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const findSortButtonGroup = () => wrapper.find(GlButtonGroup);
+ const findSortDropdown = () => wrapper.find(GlDropdown);
+ const findSortDirectionButton = () => wrapper.find(GlButton);
+ const findDropdownItems = () => findSortDropdown().findAll(GlDropdownItem);
+ const findDropdownItemsText = () => findDropdownItems().wrappers.map((w) => w.text());
+
+ describe('template', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders Sort Button Group', () => {
+ expect(findSortButtonGroup().exists()).toBe(true);
+ });
+
+ it('renders Sort Dropdown', () => {
+ expect(findSortDropdown().exists()).toBe(true);
+ });
+
+ it('renders Sort Direction Button', () => {
+ expect(findSortDirectionButton().exists()).toBe(true);
+ });
+ });
+
+ describe('Sort Dropdown Items', () => {
+ describe('renders', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('an instance for each namespace', () => {
+ expect(findDropdownItemsText()).toStrictEqual(
+ MOCK_SORT_OPTIONS.map((option) => option.title),
+ );
+ });
+ });
+
+ describe.each`
+ sortQuery | value
+ ${null} | ${MOCK_SORT_OPTIONS[0].title}
+ ${'asdf'} | ${MOCK_SORT_OPTIONS[0].title}
+ ${MOCK_SORT_OPTIONS[0].sortParam} | ${MOCK_SORT_OPTIONS[0].title}
+ ${MOCK_SORT_OPTIONS[1].sortParam.desc} | ${MOCK_SORT_OPTIONS[1].title}
+ ${MOCK_SORT_OPTIONS[1].sortParam.asc} | ${MOCK_SORT_OPTIONS[1].title}
+ `('selected', ({ sortQuery, value }) => {
+ describe(`when sort option is ${sortQuery}`, () => {
+ beforeEach(() => {
+ createComponent({ query: { sort: sortQuery } });
+ });
+
+ it('is set correctly', () => {
+ expect(findSortDropdown().attributes('text')).toBe(value);
+ });
+ });
+ });
+ });
+
+ describe.each`
+ description | sortQuery | sortUi | disabled
+ ${'non-sortable'} | ${MOCK_SORT_OPTIONS[0].sortParam} | ${SORT_DIRECTION_UI.disabled} | ${'true'}
+ ${'descending sortable'} | ${MOCK_SORT_OPTIONS[1].sortParam.desc} | ${SORT_DIRECTION_UI.desc} | ${undefined}
+ ${'ascending sortable'} | ${MOCK_SORT_OPTIONS[1].sortParam.asc} | ${SORT_DIRECTION_UI.asc} | ${undefined}
+ `('Sort Direction Button', ({ description, sortQuery, sortUi, disabled }) => {
+ describe(`when sort option is ${description}`, () => {
+ beforeEach(() => {
+ createComponent({ query: { sort: sortQuery } });
+ });
+
+ it('sets the UI correctly', () => {
+ expect(findSortDirectionButton().attributes('disabled')).toBe(disabled);
+ expect(findSortDirectionButton().attributes('title')).toBe(sortUi.tooltip);
+ expect(findSortDirectionButton().attributes('icon')).toBe(sortUi.icon);
+ });
+ });
+ });
+
+ describe('actions', () => {
+ describe.each`
+ description | index | value
+ ${'non-sortable'} | ${0} | ${MOCK_SORT_OPTIONS[0].sortParam}
+ ${'sortable'} | ${1} | ${MOCK_SORT_OPTIONS[1].sortParam.desc}
+ `('handleSortChange', ({ description, index, value }) => {
+ describe(`when clicking a ${description} option`, () => {
+ beforeEach(() => {
+ createComponent();
+ findDropdownItems().at(index).vm.$emit('click');
+ });
+
+ it('calls setQuery and applyQuery correctly', () => {
+ expect(actionSpies.setQuery).toHaveBeenCalledTimes(1);
+ expect(actionSpies.applyQuery).toHaveBeenCalledTimes(1);
+ expect(actionSpies.setQuery).toHaveBeenCalledWith(expect.any(Object), {
+ key: 'sort',
+ value,
+ });
+ });
+ });
+ });
+
+ describe.each`
+ description | sortQuery | value
+ ${'descending'} | ${MOCK_SORT_OPTIONS[1].sortParam.desc} | ${MOCK_SORT_OPTIONS[1].sortParam.asc}
+ ${'ascending'} | ${MOCK_SORT_OPTIONS[1].sortParam.asc} | ${MOCK_SORT_OPTIONS[1].sortParam.desc}
+ `('handleSortDirectionChange', ({ description, sortQuery, value }) => {
+ describe(`when toggling a ${description} option`, () => {
+ beforeEach(() => {
+ createComponent({ query: { sort: sortQuery } });
+ findSortDirectionButton().vm.$emit('click');
+ });
+
+ it('calls setQuery and applyQuery correctly', () => {
+ expect(actionSpies.setQuery).toHaveBeenCalledTimes(1);
+ expect(actionSpies.applyQuery).toHaveBeenCalledTimes(1);
+ expect(actionSpies.setQuery).toHaveBeenCalledWith(expect.any(Object), {
+ key: 'sort',
+ value,
+ });
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/search/store/actions_spec.js b/spec/frontend/search/store/actions_spec.js
index e4536a3e136..ab622c53387 100644
--- a/spec/frontend/search/store/actions_spec.js
+++ b/spec/frontend/search/store/actions_spec.js
@@ -1,12 +1,12 @@
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import Api from '~/api';
+import createFlash from '~/flash';
+import axios from '~/lib/utils/axios_utils';
+import * as urlUtils from '~/lib/utils/url_utility';
import * as actions from '~/search/store/actions';
import * as types from '~/search/store/mutation_types';
-import * as urlUtils from '~/lib/utils/url_utility';
import createState from '~/search/store/state';
-import axios from '~/lib/utils/axios_utils';
-import createFlash from '~/flash';
import { MOCK_QUERY, MOCK_GROUPS, MOCK_PROJECT, MOCK_PROJECTS } from '../mock_data';
jest.mock('~/flash');
diff --git a/spec/frontend/search/store/mutations_spec.js b/spec/frontend/search/store/mutations_spec.js
index 560ed66263b..df94ba40ff2 100644
--- a/spec/frontend/search/store/mutations_spec.js
+++ b/spec/frontend/search/store/mutations_spec.js
@@ -1,6 +1,6 @@
+import * as types from '~/search/store/mutation_types';
import mutations from '~/search/store/mutations';
import createState from '~/search/store/state';
-import * as types from '~/search/store/mutation_types';
import { MOCK_QUERY, MOCK_GROUPS, MOCK_PROJECTS } from '../mock_data';
describe('Global Search Store Mutations', () => {
diff --git a/spec/frontend/search/topbar/components/app_spec.js b/spec/frontend/search/topbar/components/app_spec.js
new file mode 100644
index 00000000000..fb953f2ed1b
--- /dev/null
+++ b/spec/frontend/search/topbar/components/app_spec.js
@@ -0,0 +1,113 @@
+import { GlForm, GlSearchBoxByType, GlButton } from '@gitlab/ui';
+import { createLocalVue, shallowMount } from '@vue/test-utils';
+import Vuex from 'vuex';
+import { MOCK_QUERY } from 'jest/search/mock_data';
+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';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('GlobalSearchTopbar', () => {
+ let wrapper;
+
+ const actionSpies = {
+ applyQuery: jest.fn(),
+ setQuery: jest.fn(),
+ };
+
+ const createComponent = (initialState) => {
+ const store = new Vuex.Store({
+ state: {
+ query: MOCK_QUERY,
+ ...initialState,
+ },
+ actions: actionSpies,
+ });
+
+ wrapper = shallowMount(GlobalSearchTopbar, {
+ localVue,
+ store,
+ });
+ };
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const findTopbarForm = () => wrapper.find(GlForm);
+ const findGlSearchBox = () => wrapper.find(GlSearchBoxByType);
+ const findGroupFilter = () => wrapper.find(GroupFilter);
+ const findProjectFilter = () => wrapper.find(ProjectFilter);
+ const findSearchButton = () => wrapper.find(GlButton);
+
+ describe('template', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('renders Topbar Form always', () => {
+ expect(findTopbarForm().exists()).toBe(true);
+ });
+
+ describe('Search box', () => {
+ it('renders always', () => {
+ expect(findGlSearchBox().exists()).toBe(true);
+ });
+
+ describe('onSearch', () => {
+ const testSearch = 'test search';
+
+ beforeEach(() => {
+ findGlSearchBox().vm.$emit('input', testSearch);
+ });
+
+ it('calls setQuery when input event is fired from GlSearchBoxByType', () => {
+ expect(actionSpies.setQuery).toHaveBeenCalledWith(expect.any(Object), {
+ key: 'search',
+ value: testSearch,
+ });
+ });
+ });
+ });
+
+ 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('renders SearchButton always', () => {
+ expect(findSearchButton().exists()).toBe(true);
+ });
+ });
+
+ describe('actions', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('clicking SearchButton calls applyQuery', () => {
+ findTopbarForm().vm.$emit('submit', { preventDefault: () => {} });
+
+ expect(actionSpies.applyQuery).toHaveBeenCalled();
+ });
+ });
+});
diff --git a/spec/frontend/search/topbar/components/group_filter_spec.js b/spec/frontend/search/topbar/components/group_filter_spec.js
index 017808d576e..15b46f9c058 100644
--- a/spec/frontend/search/topbar/components/group_filter_spec.js
+++ b/spec/frontend/search/topbar/components/group_filter_spec.js
@@ -1,5 +1,5 @@
-import Vuex from 'vuex';
import { createLocalVue, shallowMount } from '@vue/test-utils';
+import Vuex from 'vuex';
import { MOCK_GROUP, MOCK_QUERY } from 'jest/search/mock_data';
import { visitUrl, setUrlParams } from '~/lib/utils/url_utility';
import GroupFilter from '~/search/topbar/components/group_filter.vue';
diff --git a/spec/frontend/search/topbar/components/project_filter_spec.js b/spec/frontend/search/topbar/components/project_filter_spec.js
index c1fc61d7e89..3bd0769b34a 100644
--- a/spec/frontend/search/topbar/components/project_filter_spec.js
+++ b/spec/frontend/search/topbar/components/project_filter_spec.js
@@ -1,5 +1,5 @@
-import Vuex from 'vuex';
import { createLocalVue, shallowMount } from '@vue/test-utils';
+import Vuex from 'vuex';
import { MOCK_PROJECT, MOCK_QUERY } from 'jest/search/mock_data';
import { visitUrl, setUrlParams } from '~/lib/utils/url_utility';
import ProjectFilter from '~/search/topbar/components/project_filter.vue';
@@ -99,7 +99,7 @@ describe('ProjectFilter', () => {
it('calls setUrlParams with project id, group id, then calls visitUrl', () => {
expect(setUrlParams).toHaveBeenCalledWith({
- [GROUP_DATA.queryParam]: MOCK_PROJECT.namespace_id,
+ [GROUP_DATA.queryParam]: MOCK_PROJECT.namespace.id,
[PROJECT_DATA.queryParam]: MOCK_PROJECT.id,
});
expect(visitUrl).toHaveBeenCalled();
diff --git a/spec/frontend/search/topbar/components/searchable_dropdown_spec.js b/spec/frontend/search/topbar/components/searchable_dropdown_spec.js
index 86e29571d0f..5de948592d4 100644
--- a/spec/frontend/search/topbar/components/searchable_dropdown_spec.js
+++ b/spec/frontend/search/topbar/components/searchable_dropdown_spec.js
@@ -1,6 +1,6 @@
-import Vuex from 'vuex';
-import { createLocalVue, shallowMount, mount } from '@vue/test-utils';
import { GlDropdown, GlDropdownItem, GlSearchBoxByType, GlSkeletonLoader } from '@gitlab/ui';
+import { createLocalVue, shallowMount, mount } from '@vue/test-utils';
+import Vuex from 'vuex';
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';