diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-30 06:07:17 +0000 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-06-30 06:07:17 +0000 |
commit | 28fd41cf28bfac77fe877b6cce83594c1f9f21a1 (patch) | |
tree | f40a522a22db6518445b243b5244207416665f01 /spec/frontend/search | |
parent | dbb27a91536f29550f7714356ab499d318e9d7e2 (diff) | |
download | gitlab-ce-28fd41cf28bfac77fe877b6cce83594c1f9f21a1.tar.gz |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/search')
-rw-r--r-- | spec/frontend/search/mock_data.js | 2 | ||||
-rw-r--r-- | spec/frontend/search/store/actions_spec.js | 86 | ||||
-rw-r--r-- | spec/frontend/search/store/mutations_spec.js | 9 | ||||
-rw-r--r-- | spec/frontend/search/store/utils_spec.js | 147 | ||||
-rw-r--r-- | spec/frontend/search/topbar/components/group_filter_spec.js | 49 | ||||
-rw-r--r-- | spec/frontend/search/topbar/components/project_filter_spec.js | 35 |
6 files changed, 315 insertions, 13 deletions
diff --git a/spec/frontend/search/mock_data.js b/spec/frontend/search/mock_data.js index fbe01f372b0..ad082e98a41 100644 --- a/spec/frontend/search/mock_data.js +++ b/spec/frontend/search/mock_data.js @@ -63,3 +63,5 @@ export const MOCK_SORT_OPTIONS = [ }, }, ]; + +export const MOCK_LS_KEY = 'mock-ls-key'; diff --git a/spec/frontend/search/store/actions_spec.js b/spec/frontend/search/store/actions_spec.js index bb711b3af81..8c53d913108 100644 --- a/spec/frontend/search/store/actions_spec.js +++ b/spec/frontend/search/store/actions_spec.js @@ -5,9 +5,11 @@ 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 { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from '~/search/store/constants'; import * as types from '~/search/store/mutation_types'; import createState from '~/search/store/state'; -import { MOCK_QUERY, MOCK_GROUPS, MOCK_PROJECT, MOCK_PROJECTS } from '../mock_data'; +import * as storeUtils from '~/search/store/utils'; +import { MOCK_QUERY, MOCK_GROUPS, MOCK_PROJECT, MOCK_PROJECTS, MOCK_GROUP } from '../mock_data'; jest.mock('~/flash'); jest.mock('~/lib/utils/url_utility', () => ({ @@ -141,4 +143,86 @@ describe('Global Search Store Actions', () => { }); }); }); + + describe('loadFrequentGroups', () => { + beforeEach(() => { + storeUtils.loadDataFromLS = jest.fn().mockReturnValue(MOCK_GROUPS); + }); + + it(`calls loadDataFromLS with ${GROUPS_LOCAL_STORAGE_KEY} and LOAD_FREQUENT_ITEMS mutation`, async () => { + await testAction({ + action: actions.loadFrequentGroups, + state, + expectedMutations: [ + { + type: types.LOAD_FREQUENT_ITEMS, + payload: { key: GROUPS_LOCAL_STORAGE_KEY, data: MOCK_GROUPS }, + }, + ], + }); + + expect(storeUtils.loadDataFromLS).toHaveBeenCalledWith(GROUPS_LOCAL_STORAGE_KEY); + }); + }); + + describe('loadFrequentProjects', () => { + beforeEach(() => { + storeUtils.loadDataFromLS = jest.fn().mockReturnValue(MOCK_PROJECTS); + }); + + it(`calls loadDataFromLS with ${PROJECTS_LOCAL_STORAGE_KEY} and LOAD_FREQUENT_ITEMS mutation`, async () => { + await testAction({ + action: actions.loadFrequentProjects, + state, + expectedMutations: [ + { + type: types.LOAD_FREQUENT_ITEMS, + payload: { key: PROJECTS_LOCAL_STORAGE_KEY, data: MOCK_PROJECTS }, + }, + ], + }); + + expect(storeUtils.loadDataFromLS).toHaveBeenCalledWith(PROJECTS_LOCAL_STORAGE_KEY); + }); + }); + + describe('setFrequentGroup', () => { + beforeEach(() => { + storeUtils.setFrequentItemToLS = jest.fn(); + }); + + it(`calls setFrequentItemToLS with ${GROUPS_LOCAL_STORAGE_KEY} and item data`, async () => { + await testAction({ + action: actions.setFrequentGroup, + payload: MOCK_GROUP, + state, + }); + + expect(storeUtils.setFrequentItemToLS).toHaveBeenCalledWith( + GROUPS_LOCAL_STORAGE_KEY, + state.frequentItems, + MOCK_GROUP, + ); + }); + }); + + describe('setFrequentProject', () => { + beforeEach(() => { + storeUtils.setFrequentItemToLS = jest.fn(); + }); + + it(`calls setFrequentItemToLS with ${PROJECTS_LOCAL_STORAGE_KEY} and item data`, async () => { + await testAction({ + action: actions.setFrequentProject, + payload: MOCK_PROJECT, + state, + }); + + expect(storeUtils.setFrequentItemToLS).toHaveBeenCalledWith( + PROJECTS_LOCAL_STORAGE_KEY, + state.frequentItems, + MOCK_PROJECT, + ); + }); + }); }); diff --git a/spec/frontend/search/store/mutations_spec.js b/spec/frontend/search/store/mutations_spec.js index df94ba40ff2..a60718a972d 100644 --- a/spec/frontend/search/store/mutations_spec.js +++ b/spec/frontend/search/store/mutations_spec.js @@ -71,4 +71,13 @@ describe('Global Search Store Mutations', () => { expect(state.query[payload.key]).toBe(payload.value); }); }); + + describe('LOAD_FREQUENT_ITEMS', () => { + it('sets frequentItems[key] to data', () => { + const payload = { key: 'test-key', data: [1, 2, 3] }; + mutations[types.LOAD_FREQUENT_ITEMS](state, payload); + + expect(state.frequentItems[payload.key]).toStrictEqual(payload.data); + }); + }); }); diff --git a/spec/frontend/search/store/utils_spec.js b/spec/frontend/search/store/utils_spec.js new file mode 100644 index 00000000000..e5364500464 --- /dev/null +++ b/spec/frontend/search/store/utils_spec.js @@ -0,0 +1,147 @@ +import { useLocalStorageSpy } from 'helpers/local_storage_helper'; +import { MAX_FREQUENCY } from '~/search/store/constants'; +import { loadDataFromLS, setFrequentItemToLS } from '~/search/store/utils'; +import { MOCK_LS_KEY, MOCK_GROUPS } from '../mock_data'; + +useLocalStorageSpy(); +jest.mock('~/lib/utils/accessor', () => ({ + isLocalStorageAccessSafe: jest.fn().mockReturnValue(true), +})); + +describe('Global Search Store Utils', () => { + afterEach(() => { + localStorage.clear(); + }); + + describe('loadDataFromLS', () => { + let res; + + describe('with valid data', () => { + beforeEach(() => { + localStorage.setItem(MOCK_LS_KEY, JSON.stringify(MOCK_GROUPS)); + res = loadDataFromLS(MOCK_LS_KEY); + }); + + it('returns parsed array', () => { + expect(res).toStrictEqual(MOCK_GROUPS); + }); + }); + + describe('with invalid data', () => { + beforeEach(() => { + localStorage.setItem(MOCK_LS_KEY, '[}'); + res = loadDataFromLS(MOCK_LS_KEY); + }); + + it('wipes local storage and returns an empty array', () => { + expect(localStorage.removeItem).toHaveBeenCalledWith(MOCK_LS_KEY); + expect(res).toStrictEqual([]); + }); + }); + }); + + describe('setFrequentItemToLS', () => { + const frequentItems = {}; + + describe('with existing data', () => { + describe(`when frequency is less than ${MAX_FREQUENCY}`, () => { + beforeEach(() => { + frequentItems[MOCK_LS_KEY] = [{ id: MOCK_GROUPS[0].id, frequency: 1 }]; + setFrequentItemToLS(MOCK_LS_KEY, frequentItems, MOCK_GROUPS[0]); + }); + + it('adds 1 to the frequency and calls localStorage.setItem', () => { + expect(localStorage.setItem).toHaveBeenCalledWith( + MOCK_LS_KEY, + JSON.stringify([{ id: MOCK_GROUPS[0].id, frequency: 2 }]), + ); + }); + }); + + describe(`when frequency is equal to ${MAX_FREQUENCY}`, () => { + beforeEach(() => { + frequentItems[MOCK_LS_KEY] = [{ id: MOCK_GROUPS[0].id, frequency: MAX_FREQUENCY }]; + setFrequentItemToLS(MOCK_LS_KEY, frequentItems, MOCK_GROUPS[0]); + }); + + it(`does not further increase frequency past ${MAX_FREQUENCY} and calls localStorage.setItem`, () => { + expect(localStorage.setItem).toHaveBeenCalledWith( + MOCK_LS_KEY, + JSON.stringify([{ id: MOCK_GROUPS[0].id, frequency: MAX_FREQUENCY }]), + ); + }); + }); + }); + + describe('with no existing data', () => { + beforeEach(() => { + frequentItems[MOCK_LS_KEY] = []; + setFrequentItemToLS(MOCK_LS_KEY, frequentItems, MOCK_GROUPS[0]); + }); + + it('adds a new entry with frequency 1 and calls localStorage.setItem', () => { + expect(localStorage.setItem).toHaveBeenCalledWith( + MOCK_LS_KEY, + JSON.stringify([{ id: MOCK_GROUPS[0].id, frequency: 1 }]), + ); + }); + }); + + describe('with multiple entries', () => { + beforeEach(() => { + frequentItems[MOCK_LS_KEY] = [ + { id: MOCK_GROUPS[0].id, frequency: 1 }, + { id: MOCK_GROUPS[1].id, frequency: 1 }, + ]; + setFrequentItemToLS(MOCK_LS_KEY, frequentItems, MOCK_GROUPS[1]); + }); + + it('sorts the array by most frequent', () => { + expect(localStorage.setItem).toHaveBeenCalledWith( + MOCK_LS_KEY, + JSON.stringify([ + { id: MOCK_GROUPS[1].id, frequency: 2 }, + { id: MOCK_GROUPS[0].id, frequency: 1 }, + ]), + ); + }); + }); + + describe('with max entries', () => { + beforeEach(() => { + frequentItems[MOCK_LS_KEY] = [ + { id: 1, frequency: 5 }, + { id: 2, frequency: 4 }, + { id: 3, frequency: 3 }, + { id: 4, frequency: 2 }, + { id: 5, frequency: 1 }, + ]; + setFrequentItemToLS(MOCK_LS_KEY, frequentItems, { id: 6 }); + }); + + it('removes the least frequent', () => { + expect(localStorage.setItem).toHaveBeenCalledWith( + MOCK_LS_KEY, + JSON.stringify([ + { id: 1, frequency: 5 }, + { id: 2, frequency: 4 }, + { id: 3, frequency: 3 }, + { id: 4, frequency: 2 }, + { id: 6, frequency: 1 }, + ]), + ); + }); + }); + + describe('with null data loaded in', () => { + beforeEach(() => { + frequentItems[MOCK_LS_KEY] = null; + setFrequentItemToLS(MOCK_LS_KEY, frequentItems, MOCK_GROUPS[0]); + }); + + it('wipes local storage', () => { + expect(localStorage.removeItem).toHaveBeenCalledWith(MOCK_LS_KEY); + }); + }); + }); +}); diff --git a/spec/frontend/search/topbar/components/group_filter_spec.js b/spec/frontend/search/topbar/components/group_filter_spec.js index 15b46f9c058..3b460402537 100644 --- a/spec/frontend/search/topbar/components/group_filter_spec.js +++ b/spec/frontend/search/topbar/components/group_filter_spec.js @@ -1,13 +1,14 @@ -import { createLocalVue, shallowMount } from '@vue/test-utils'; +import { shallowMount } from '@vue/test-utils'; +import Vue from 'vue'; import Vuex from 'vuex'; import { MOCK_GROUP, MOCK_QUERY } 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'; -const localVue = createLocalVue(); -localVue.use(Vuex); +Vue.use(Vuex); jest.mock('~/lib/utils/url_utility', () => ({ visitUrl: jest.fn(), @@ -19,6 +20,8 @@ describe('GroupFilter', () => { const actionSpies = { fetchGroups: jest.fn(), + setFrequentGroup: jest.fn(), + loadFrequentGroups: jest.fn(), }; const defaultProps = { @@ -35,7 +38,6 @@ describe('GroupFilter', () => { }); wrapper = shallowMount(GroupFilter, { - localVue, store, propsData: { ...defaultProps, @@ -77,14 +79,35 @@ describe('GroupFilter', () => { }); }); - describe('when @change is emitted', () => { + describe('when @change is emitted with Any', () => { + beforeEach(() => { + createComponent(); + + findSearchableDropdown().vm.$emit('change', ANY_OPTION); + }); + + it('calls setUrlParams with group null, project id null, and then calls visitUrl', () => { + expect(setUrlParams).toHaveBeenCalledWith({ + [GROUP_DATA.queryParam]: null, + [PROJECT_DATA.queryParam]: null, + }); + + expect(visitUrl).toHaveBeenCalled(); + }); + + it('does not call setFrequentGroup', () => { + expect(actionSpies.setFrequentGroup).not.toHaveBeenCalled(); + }); + }); + + describe('when @change is emitted with a group', () => { beforeEach(() => { createComponent(); findSearchableDropdown().vm.$emit('change', MOCK_GROUP); }); - it('calls calls setUrlParams with group id, project id null, and visitUrl', () => { + it('calls setUrlParams with group id, project id null, and then calls visitUrl', () => { expect(setUrlParams).toHaveBeenCalledWith({ [GROUP_DATA.queryParam]: MOCK_GROUP.id, [PROJECT_DATA.queryParam]: null, @@ -92,6 +115,10 @@ describe('GroupFilter', () => { expect(visitUrl).toHaveBeenCalled(); }); + + it(`calls setFrequentGroup with the group and ${GROUPS_LOCAL_STORAGE_KEY}`, () => { + expect(actionSpies.setFrequentGroup).toHaveBeenCalledWith(expect.any(Object), MOCK_GROUP); + }); }); }); @@ -118,4 +145,14 @@ describe('GroupFilter', () => { }); }); }); + + describe('onCreate', () => { + beforeEach(() => { + createComponent(); + }); + + it('calls loadFrequentGroups', () => { + expect(actionSpies.loadFrequentGroups).toHaveBeenCalledTimes(1); + }); + }); }); diff --git a/spec/frontend/search/topbar/components/project_filter_spec.js b/spec/frontend/search/topbar/components/project_filter_spec.js index 3bd0769b34a..d260df4120b 100644 --- a/spec/frontend/search/topbar/components/project_filter_spec.js +++ b/spec/frontend/search/topbar/components/project_filter_spec.js @@ -1,13 +1,14 @@ -import { createLocalVue, shallowMount } from '@vue/test-utils'; +import { shallowMount } from '@vue/test-utils'; +import Vue from 'vue'; import Vuex from 'vuex'; import { MOCK_PROJECT, MOCK_QUERY } 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'; -const localVue = createLocalVue(); -localVue.use(Vuex); +Vue.use(Vuex); jest.mock('~/lib/utils/url_utility', () => ({ visitUrl: jest.fn(), @@ -19,6 +20,8 @@ describe('ProjectFilter', () => { const actionSpies = { fetchProjects: jest.fn(), + setFrequentProject: jest.fn(), + loadFrequentProjects: jest.fn(), }; const defaultProps = { @@ -35,7 +38,6 @@ describe('ProjectFilter', () => { }); wrapper = shallowMount(ProjectFilter, { - localVue, store, propsData: { ...defaultProps, @@ -84,12 +86,16 @@ describe('ProjectFilter', () => { findSearchableDropdown().vm.$emit('change', ANY_OPTION); }); - it('calls setUrlParams with project id, not group id, then calls visitUrl', () => { + it('calls setUrlParams with null, no group id, then calls visitUrl', () => { expect(setUrlParams).toHaveBeenCalledWith({ - [PROJECT_DATA.queryParam]: ANY_OPTION.id, + [PROJECT_DATA.queryParam]: null, }); expect(visitUrl).toHaveBeenCalled(); }); + + it('does not call setFrequentProject', () => { + expect(actionSpies.setFrequentProject).not.toHaveBeenCalled(); + }); }); describe('with a Project', () => { @@ -104,6 +110,13 @@ describe('ProjectFilter', () => { }); expect(visitUrl).toHaveBeenCalled(); }); + + it(`calls setFrequentProject with the group and ${PROJECTS_LOCAL_STORAGE_KEY}`, () => { + expect(actionSpies.setFrequentProject).toHaveBeenCalledWith( + expect.any(Object), + MOCK_PROJECT, + ); + }); }); }); }); @@ -131,4 +144,14 @@ describe('ProjectFilter', () => { }); }); }); + + describe('onCreate', () => { + beforeEach(() => { + createComponent(); + }); + + it('calls loadFrequentProjects', () => { + expect(actionSpies.loadFrequentProjects).toHaveBeenCalledTimes(1); + }); + }); }); |