Commit 8fd46077 authored by Simon Knox's avatar Simon Knox

Merge branch '239384_03-global-search-inflate-recent-items' into 'master'

Global Search - Inflate Recent Items

See merge request gitlab-org/gitlab!65183
parents 036225c5 99e69f66
...@@ -4,7 +4,7 @@ import { visitUrl, setUrlParams } from '~/lib/utils/url_utility'; ...@@ -4,7 +4,7 @@ import { visitUrl, setUrlParams } from '~/lib/utils/url_utility';
import { __ } from '~/locale'; import { __ } from '~/locale';
import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from './constants'; import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from './constants';
import * as types from './mutation_types'; import * as types from './mutation_types';
import { loadDataFromLS, setFrequentItemToLS } from './utils'; import { loadDataFromLS, setFrequentItemToLS, mergeById } from './utils';
export const fetchGroups = ({ commit }, search) => { export const fetchGroups = ({ commit }, search) => {
commit(types.REQUEST_GROUPS); commit(types.REQUEST_GROUPS);
...@@ -41,14 +41,30 @@ export const fetchProjects = ({ commit, state }, search) => { ...@@ -41,14 +41,30 @@ export const fetchProjects = ({ commit, state }, search) => {
} }
}; };
export const loadFrequentGroups = ({ commit }) => { export const loadFrequentGroups = async ({ commit }) => {
const data = loadDataFromLS(GROUPS_LOCAL_STORAGE_KEY); const data = loadDataFromLS(GROUPS_LOCAL_STORAGE_KEY);
commit(types.LOAD_FREQUENT_ITEMS, { key: GROUPS_LOCAL_STORAGE_KEY, data }); commit(types.LOAD_FREQUENT_ITEMS, { key: GROUPS_LOCAL_STORAGE_KEY, data });
const promises = data.map((d) => Api.group(d.id));
try {
const inflatedData = mergeById(await Promise.all(promises), data);
commit(types.LOAD_FREQUENT_ITEMS, { key: GROUPS_LOCAL_STORAGE_KEY, data: inflatedData });
} catch {
createFlash({ message: __('There was a problem fetching recent groups.') });
}
}; };
export const loadFrequentProjects = ({ commit }) => { export const loadFrequentProjects = async ({ commit }) => {
const data = loadDataFromLS(PROJECTS_LOCAL_STORAGE_KEY); const data = loadDataFromLS(PROJECTS_LOCAL_STORAGE_KEY);
commit(types.LOAD_FREQUENT_ITEMS, { key: PROJECTS_LOCAL_STORAGE_KEY, data }); commit(types.LOAD_FREQUENT_ITEMS, { key: PROJECTS_LOCAL_STORAGE_KEY, data });
const promises = data.map((d) => Api.project(d.id).then((res) => res.data));
try {
const inflatedData = mergeById(await Promise.all(promises), data);
commit(types.LOAD_FREQUENT_ITEMS, { key: PROJECTS_LOCAL_STORAGE_KEY, data: inflatedData });
} catch {
createFlash({ message: __('There was a problem fetching recent projects.') });
}
}; };
export const setFrequentGroup = ({ state }, item) => { export const setFrequentGroup = ({ state }, item) => {
......
import AccessorUtilities from '../../lib/utils/accessor'; import AccessorUtilities from '../../lib/utils/accessor';
import { MAX_FREQUENT_ITEMS, MAX_FREQUENCY } from './constants'; import { MAX_FREQUENT_ITEMS, MAX_FREQUENCY } from './constants';
function extractKeys(object, keyList) {
return Object.fromEntries(keyList.map((key) => [key, object[key]]));
}
export const loadDataFromLS = (key) => { export const loadDataFromLS = (key) => {
if (!AccessorUtilities.isLocalStorageAccessSafe()) { if (!AccessorUtilities.isLocalStorageAccessSafe()) {
return []; return [];
...@@ -15,13 +19,16 @@ export const loadDataFromLS = (key) => { ...@@ -15,13 +19,16 @@ export const loadDataFromLS = (key) => {
} }
}; };
export const setFrequentItemToLS = (key, data, item) => { export const setFrequentItemToLS = (key, data, itemData) => {
if (!AccessorUtilities.isLocalStorageAccessSafe()) { if (!AccessorUtilities.isLocalStorageAccessSafe()) {
return; return;
} }
const keyList = ['id', 'avatar_url', 'name', 'full_name', 'name_with_namespace', 'frequency'];
try { try {
const frequentItems = data[key]; const frequentItems = data[key].map((obj) => extractKeys(obj, keyList));
const item = extractKeys(itemData, keyList);
const existingItemIndex = frequentItems.findIndex((i) => i.id === item.id); const existingItemIndex = frequentItems.findIndex((i) => i.id === item.id);
if (existingItemIndex >= 0) { if (existingItemIndex >= 0) {
...@@ -34,7 +41,7 @@ export const setFrequentItemToLS = (key, data, item) => { ...@@ -34,7 +41,7 @@ export const setFrequentItemToLS = (key, data, item) => {
frequentItems.pop(); frequentItems.pop();
} }
frequentItems.push({ id: item.id, frequency: 1 }); frequentItems.push({ ...item, frequency: 1 });
} }
// Sort by frequency // Sort by frequency
...@@ -48,3 +55,10 @@ export const setFrequentItemToLS = (key, data, item) => { ...@@ -48,3 +55,10 @@ export const setFrequentItemToLS = (key, data, item) => {
localStorage.removeItem(key); localStorage.removeItem(key);
} }
}; };
export const mergeById = (inflatedData, storedData) => {
return inflatedData.map((data) => {
const stored = storedData?.find((d) => d.id === data.id) || {};
return { ...stored, ...data };
});
};
...@@ -23,9 +23,6 @@ export default { ...@@ -23,9 +23,6 @@ export default {
return isEmpty(this.initialData) ? ANY_OPTION : this.initialData; return isEmpty(this.initialData) ? ANY_OPTION : this.initialData;
}, },
}, },
created() {
this.loadFrequentGroups();
},
methods: { methods: {
...mapActions(['fetchGroups', 'setFrequentGroup', 'loadFrequentGroups']), ...mapActions(['fetchGroups', 'setFrequentGroup', 'loadFrequentGroups']),
handleGroupChange(group) { handleGroupChange(group) {
...@@ -52,6 +49,7 @@ export default { ...@@ -52,6 +49,7 @@ export default {
:loading="fetchingGroups" :loading="fetchingGroups"
:selected-item="selectedGroup" :selected-item="selectedGroup"
:items="groups" :items="groups"
@first-open="loadFrequentGroups"
@search="fetchGroups" @search="fetchGroups"
@change="handleGroupChange" @change="handleGroupChange"
/> />
......
...@@ -22,9 +22,6 @@ export default { ...@@ -22,9 +22,6 @@ export default {
return this.initialData ? this.initialData : ANY_OPTION; return this.initialData ? this.initialData : ANY_OPTION;
}, },
}, },
created() {
this.loadFrequentProjects();
},
methods: { methods: {
...mapActions(['fetchProjects', 'setFrequentProject', 'loadFrequentProjects']), ...mapActions(['fetchProjects', 'setFrequentProject', 'loadFrequentProjects']),
handleProjectChange(project) { handleProjectChange(project) {
...@@ -55,6 +52,7 @@ export default { ...@@ -55,6 +52,7 @@ export default {
:loading="fetchingProjects" :loading="fetchingProjects"
:selected-item="selectedProject" :selected-item="selectedProject"
:items="projects" :items="projects"
@first-open="loadFrequentProjects"
@search="fetchProjects" @search="fetchProjects"
@change="handleProjectChange" @change="handleProjectChange"
/> />
......
...@@ -65,6 +65,7 @@ export default { ...@@ -65,6 +65,7 @@ export default {
data() { data() {
return { return {
searchText: '', searchText: '',
hasBeenOpened: false,
}; };
}, },
methods: { methods: {
...@@ -72,6 +73,11 @@ export default { ...@@ -72,6 +73,11 @@ export default {
return selected.id === this.selectedItem.id; return selected.id === this.selectedItem.id;
}, },
openDropdown() { openDropdown() {
if (!this.hasBeenOpened) {
this.hasBeenOpened = true;
this.$emit('first-open');
}
this.$emit('search', this.searchText); this.$emit('search', this.searchText);
}, },
resetDropdown() { resetDropdown() {
......
...@@ -33051,6 +33051,12 @@ msgstr "" ...@@ -33051,6 +33051,12 @@ msgstr ""
msgid "There was a problem fetching project users." msgid "There was a problem fetching project users."
msgstr "" msgstr ""
msgid "There was a problem fetching recent groups."
msgstr ""
msgid "There was a problem fetching recent projects."
msgstr ""
msgid "There was a problem fetching the job token scope value" msgid "There was a problem fetching the job token scope value"
msgstr "" msgstr ""
......
import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from '~/search/store/constants';
import * as types from '~/search/store/mutation_types';
export const MOCK_QUERY = { export const MOCK_QUERY = {
scope: 'issues', scope: 'issues',
state: 'all', state: 'all',
...@@ -6,45 +9,45 @@ export const MOCK_QUERY = { ...@@ -6,45 +9,45 @@ export const MOCK_QUERY = {
}; };
export const MOCK_GROUP = { export const MOCK_GROUP = {
id: 1,
name: 'test group', name: 'test group',
full_name: 'full name / test group', full_name: 'full name / test group',
id: 1,
}; };
export const MOCK_GROUPS = [ export const MOCK_GROUPS = [
{ {
id: 1,
avatar_url: null, avatar_url: null,
name: 'test group', name: 'test group',
full_name: 'full name / test group', full_name: 'full name / test group',
id: 1,
}, },
{ {
id: 2,
avatar_url: 'https://avatar.com', avatar_url: 'https://avatar.com',
name: 'test group 2', name: 'test group 2',
full_name: 'full name / test group 2', full_name: 'full name / test group 2',
id: 2,
}, },
]; ];
export const MOCK_PROJECT = { export const MOCK_PROJECT = {
id: 1,
name: 'test project', name: 'test project',
namespace: MOCK_GROUP, namespace: MOCK_GROUP,
nameWithNamespace: 'test group / test project', nameWithNamespace: 'test group / test project',
id: 1,
}; };
export const MOCK_PROJECTS = [ export const MOCK_PROJECTS = [
{ {
id: 1,
name: 'test project', name: 'test project',
namespace: MOCK_GROUP, namespace: MOCK_GROUP,
name_with_namespace: 'test group / test project', name_with_namespace: 'test group / test project',
id: 1,
}, },
{ {
id: 2,
name: 'test project 2', name: 'test project 2',
namespace: MOCK_GROUP, namespace: MOCK_GROUP,
name_with_namespace: 'test group / test project 2', name_with_namespace: 'test group / test project 2',
id: 2,
}, },
]; ];
...@@ -65,3 +68,39 @@ export const MOCK_SORT_OPTIONS = [ ...@@ -65,3 +68,39 @@ export const MOCK_SORT_OPTIONS = [
]; ];
export const MOCK_LS_KEY = 'mock-ls-key'; export const MOCK_LS_KEY = 'mock-ls-key';
export const MOCK_INFLATED_DATA = [
{ id: 1, name: 'test 1' },
{ id: 2, name: 'test 2' },
];
export const FRESH_STORED_DATA = [
{ id: 1, name: 'test 1', frequency: 1 },
{ id: 2, name: 'test 2', frequency: 2 },
];
export const STALE_STORED_DATA = [
{ id: 1, name: 'blah 1', frequency: 1 },
{ id: 2, name: 'blah 2', frequency: 2 },
];
export const MOCK_FRESH_DATA_RES = { name: 'fresh' };
export const PROMISE_ALL_EXPECTED_MUTATIONS = {
initGroups: {
type: types.LOAD_FREQUENT_ITEMS,
payload: { key: GROUPS_LOCAL_STORAGE_KEY, data: FRESH_STORED_DATA },
},
resGroups: {
type: types.LOAD_FREQUENT_ITEMS,
payload: { key: GROUPS_LOCAL_STORAGE_KEY, data: [MOCK_FRESH_DATA_RES, MOCK_FRESH_DATA_RES] },
},
initProjects: {
type: types.LOAD_FREQUENT_ITEMS,
payload: { key: PROJECTS_LOCAL_STORAGE_KEY, data: FRESH_STORED_DATA },
},
resProjects: {
type: types.LOAD_FREQUENT_ITEMS,
payload: { key: PROJECTS_LOCAL_STORAGE_KEY, data: [MOCK_FRESH_DATA_RES, MOCK_FRESH_DATA_RES] },
},
};
...@@ -9,7 +9,16 @@ import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from '~/search/s ...@@ -9,7 +9,16 @@ import { GROUPS_LOCAL_STORAGE_KEY, PROJECTS_LOCAL_STORAGE_KEY } from '~/search/s
import * as types from '~/search/store/mutation_types'; import * as types from '~/search/store/mutation_types';
import createState from '~/search/store/state'; import createState from '~/search/store/state';
import * as storeUtils from '~/search/store/utils'; import * as storeUtils from '~/search/store/utils';
import { MOCK_QUERY, MOCK_GROUPS, MOCK_PROJECT, MOCK_PROJECTS, MOCK_GROUP } from '../mock_data'; import {
MOCK_QUERY,
MOCK_GROUPS,
MOCK_PROJECT,
MOCK_PROJECTS,
MOCK_GROUP,
FRESH_STORED_DATA,
MOCK_FRESH_DATA_RES,
PROMISE_ALL_EXPECTED_MUTATIONS,
} from '../mock_data';
jest.mock('~/flash'); jest.mock('~/flash');
jest.mock('~/lib/utils/url_utility', () => ({ jest.mock('~/lib/utils/url_utility', () => ({
...@@ -58,6 +67,33 @@ describe('Global Search Store Actions', () => { ...@@ -58,6 +67,33 @@ describe('Global Search Store Actions', () => {
}); });
}); });
describe.each`
action | axiosMock | type | expectedMutations | flashCallCount | lsKey
${actions.loadFrequentGroups} | ${{ method: 'onGet', code: 200 }} | ${'success'} | ${[PROMISE_ALL_EXPECTED_MUTATIONS.initGroups, PROMISE_ALL_EXPECTED_MUTATIONS.resGroups]} | ${0} | ${GROUPS_LOCAL_STORAGE_KEY}
${actions.loadFrequentGroups} | ${{ method: 'onGet', code: 500 }} | ${'error'} | ${[PROMISE_ALL_EXPECTED_MUTATIONS.initGroups]} | ${1} | ${GROUPS_LOCAL_STORAGE_KEY}
${actions.loadFrequentProjects} | ${{ method: 'onGet', code: 200 }} | ${'success'} | ${[PROMISE_ALL_EXPECTED_MUTATIONS.initProjects, PROMISE_ALL_EXPECTED_MUTATIONS.resProjects]} | ${0} | ${PROJECTS_LOCAL_STORAGE_KEY}
${actions.loadFrequentProjects} | ${{ method: 'onGet', code: 500 }} | ${'error'} | ${[PROMISE_ALL_EXPECTED_MUTATIONS.initProjects]} | ${1} | ${PROJECTS_LOCAL_STORAGE_KEY}
`(
'Promise.all calls',
({ action, axiosMock, type, expectedMutations, flashCallCount, lsKey }) => {
describe(action.name, () => {
describe(`on ${type}`, () => {
beforeEach(() => {
storeUtils.loadDataFromLS = jest.fn().mockReturnValue(FRESH_STORED_DATA);
mock[axiosMock.method]().reply(axiosMock.code, MOCK_FRESH_DATA_RES);
});
it(`should dispatch the correct mutations`, () => {
return testAction({ action, state, expectedMutations }).then(() => {
expect(storeUtils.loadDataFromLS).toHaveBeenCalledWith(lsKey);
flashCallback(flashCallCount);
});
});
});
});
},
);
describe('getGroupsData', () => { describe('getGroupsData', () => {
const mockCommit = () => {}; const mockCommit = () => {};
beforeEach(() => { beforeEach(() => {
...@@ -144,48 +180,6 @@ describe('Global Search Store Actions', () => { ...@@ -144,48 +180,6 @@ 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', () => { describe('setFrequentGroup', () => {
beforeEach(() => { beforeEach(() => {
storeUtils.setFrequentItemToLS = jest.fn(); storeUtils.setFrequentItemToLS = jest.fn();
......
import { useLocalStorageSpy } from 'helpers/local_storage_helper'; import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import { MAX_FREQUENCY } from '~/search/store/constants'; import { MAX_FREQUENCY } from '~/search/store/constants';
import { loadDataFromLS, setFrequentItemToLS } from '~/search/store/utils'; import { loadDataFromLS, setFrequentItemToLS, mergeById } from '~/search/store/utils';
import { MOCK_LS_KEY, MOCK_GROUPS } from '../mock_data'; import {
MOCK_LS_KEY,
MOCK_GROUPS,
MOCK_INFLATED_DATA,
FRESH_STORED_DATA,
STALE_STORED_DATA,
} from '../mock_data';
useLocalStorageSpy(); useLocalStorageSpy();
jest.mock('~/lib/utils/accessor', () => ({ jest.mock('~/lib/utils/accessor', () => ({
...@@ -46,28 +52,28 @@ describe('Global Search Store Utils', () => { ...@@ -46,28 +52,28 @@ describe('Global Search Store Utils', () => {
describe('with existing data', () => { describe('with existing data', () => {
describe(`when frequency is less than ${MAX_FREQUENCY}`, () => { describe(`when frequency is less than ${MAX_FREQUENCY}`, () => {
beforeEach(() => { beforeEach(() => {
frequentItems[MOCK_LS_KEY] = [{ id: MOCK_GROUPS[0].id, frequency: 1 }]; frequentItems[MOCK_LS_KEY] = [{ ...MOCK_GROUPS[0], frequency: 1 }];
setFrequentItemToLS(MOCK_LS_KEY, frequentItems, MOCK_GROUPS[0]); setFrequentItemToLS(MOCK_LS_KEY, frequentItems, MOCK_GROUPS[0]);
}); });
it('adds 1 to the frequency and calls localStorage.setItem', () => { it('adds 1 to the frequency and calls localStorage.setItem', () => {
expect(localStorage.setItem).toHaveBeenCalledWith( expect(localStorage.setItem).toHaveBeenCalledWith(
MOCK_LS_KEY, MOCK_LS_KEY,
JSON.stringify([{ id: MOCK_GROUPS[0].id, frequency: 2 }]), JSON.stringify([{ ...MOCK_GROUPS[0], frequency: 2 }]),
); );
}); });
}); });
describe(`when frequency is equal to ${MAX_FREQUENCY}`, () => { describe(`when frequency is equal to ${MAX_FREQUENCY}`, () => {
beforeEach(() => { beforeEach(() => {
frequentItems[MOCK_LS_KEY] = [{ id: MOCK_GROUPS[0].id, frequency: MAX_FREQUENCY }]; frequentItems[MOCK_LS_KEY] = [{ ...MOCK_GROUPS[0], frequency: MAX_FREQUENCY }];
setFrequentItemToLS(MOCK_LS_KEY, frequentItems, MOCK_GROUPS[0]); setFrequentItemToLS(MOCK_LS_KEY, frequentItems, MOCK_GROUPS[0]);
}); });
it(`does not further increase frequency past ${MAX_FREQUENCY} and calls localStorage.setItem`, () => { it(`does not further increase frequency past ${MAX_FREQUENCY} and calls localStorage.setItem`, () => {
expect(localStorage.setItem).toHaveBeenCalledWith( expect(localStorage.setItem).toHaveBeenCalledWith(
MOCK_LS_KEY, MOCK_LS_KEY,
JSON.stringify([{ id: MOCK_GROUPS[0].id, frequency: MAX_FREQUENCY }]), JSON.stringify([{ ...MOCK_GROUPS[0], frequency: MAX_FREQUENCY }]),
); );
}); });
}); });
...@@ -82,7 +88,7 @@ describe('Global Search Store Utils', () => { ...@@ -82,7 +88,7 @@ describe('Global Search Store Utils', () => {
it('adds a new entry with frequency 1 and calls localStorage.setItem', () => { it('adds a new entry with frequency 1 and calls localStorage.setItem', () => {
expect(localStorage.setItem).toHaveBeenCalledWith( expect(localStorage.setItem).toHaveBeenCalledWith(
MOCK_LS_KEY, MOCK_LS_KEY,
JSON.stringify([{ id: MOCK_GROUPS[0].id, frequency: 1 }]), JSON.stringify([{ ...MOCK_GROUPS[0], frequency: 1 }]),
); );
}); });
}); });
...@@ -90,8 +96,8 @@ describe('Global Search Store Utils', () => { ...@@ -90,8 +96,8 @@ describe('Global Search Store Utils', () => {
describe('with multiple entries', () => { describe('with multiple entries', () => {
beforeEach(() => { beforeEach(() => {
frequentItems[MOCK_LS_KEY] = [ frequentItems[MOCK_LS_KEY] = [
{ id: MOCK_GROUPS[0].id, frequency: 1 }, { ...MOCK_GROUPS[0], frequency: 1 },
{ id: MOCK_GROUPS[1].id, frequency: 1 }, { ...MOCK_GROUPS[1], frequency: 1 },
]; ];
setFrequentItemToLS(MOCK_LS_KEY, frequentItems, MOCK_GROUPS[1]); setFrequentItemToLS(MOCK_LS_KEY, frequentItems, MOCK_GROUPS[1]);
}); });
...@@ -100,8 +106,8 @@ describe('Global Search Store Utils', () => { ...@@ -100,8 +106,8 @@ describe('Global Search Store Utils', () => {
expect(localStorage.setItem).toHaveBeenCalledWith( expect(localStorage.setItem).toHaveBeenCalledWith(
MOCK_LS_KEY, MOCK_LS_KEY,
JSON.stringify([ JSON.stringify([
{ id: MOCK_GROUPS[1].id, frequency: 2 }, { ...MOCK_GROUPS[1], frequency: 2 },
{ id: MOCK_GROUPS[0].id, frequency: 1 }, { ...MOCK_GROUPS[0], frequency: 1 },
]), ]),
); );
}); });
...@@ -143,5 +149,40 @@ describe('Global Search Store Utils', () => { ...@@ -143,5 +149,40 @@ describe('Global Search Store Utils', () => {
expect(localStorage.removeItem).toHaveBeenCalledWith(MOCK_LS_KEY); expect(localStorage.removeItem).toHaveBeenCalledWith(MOCK_LS_KEY);
}); });
}); });
describe('with additional data', () => {
beforeEach(() => {
const MOCK_ADDITIONAL_DATA_GROUP = { ...MOCK_GROUPS[0], extraData: 'test' };
frequentItems[MOCK_LS_KEY] = [];
setFrequentItemToLS(MOCK_LS_KEY, frequentItems, MOCK_ADDITIONAL_DATA_GROUP);
});
it('parses out extra data for LS', () => {
expect(localStorage.setItem).toHaveBeenCalledWith(
MOCK_LS_KEY,
JSON.stringify([{ ...MOCK_GROUPS[0], frequency: 1 }]),
);
});
});
});
describe.each`
description | inflatedData | storedData | response
${'identical'} | ${MOCK_INFLATED_DATA} | ${FRESH_STORED_DATA} | ${FRESH_STORED_DATA}
${'stale'} | ${MOCK_INFLATED_DATA} | ${STALE_STORED_DATA} | ${FRESH_STORED_DATA}
${'empty'} | ${MOCK_INFLATED_DATA} | ${[]} | ${MOCK_INFLATED_DATA}
${'null'} | ${MOCK_INFLATED_DATA} | ${null} | ${MOCK_INFLATED_DATA}
`('mergeById', ({ description, inflatedData, storedData, response }) => {
describe(`with ${description} storedData`, () => {
let res;
beforeEach(() => {
res = mergeById(inflatedData, storedData);
});
it('prioritizes inflatedData and preserves frequency count', () => {
expect(response).toStrictEqual(res);
});
});
}); });
}); });
...@@ -64,12 +64,14 @@ describe('GroupFilter', () => { ...@@ -64,12 +64,14 @@ describe('GroupFilter', () => {
}); });
describe('events', () => { describe('events', () => {
beforeEach(() => {
createComponent();
});
describe('when @search is emitted', () => { describe('when @search is emitted', () => {
const search = 'test'; const search = 'test';
beforeEach(() => { beforeEach(() => {
createComponent();
findSearchableDropdown().vm.$emit('search', search); findSearchableDropdown().vm.$emit('search', search);
}); });
...@@ -81,8 +83,6 @@ describe('GroupFilter', () => { ...@@ -81,8 +83,6 @@ describe('GroupFilter', () => {
describe('when @change is emitted with Any', () => { describe('when @change is emitted with Any', () => {
beforeEach(() => { beforeEach(() => {
createComponent();
findSearchableDropdown().vm.$emit('change', ANY_OPTION); findSearchableDropdown().vm.$emit('change', ANY_OPTION);
}); });
...@@ -102,8 +102,6 @@ describe('GroupFilter', () => { ...@@ -102,8 +102,6 @@ describe('GroupFilter', () => {
describe('when @change is emitted with a group', () => { describe('when @change is emitted with a group', () => {
beforeEach(() => { beforeEach(() => {
createComponent();
findSearchableDropdown().vm.$emit('change', MOCK_GROUP); findSearchableDropdown().vm.$emit('change', MOCK_GROUP);
}); });
...@@ -120,6 +118,16 @@ describe('GroupFilter', () => { ...@@ -120,6 +118,16 @@ describe('GroupFilter', () => {
expect(actionSpies.setFrequentGroup).toHaveBeenCalledWith(expect.any(Object), MOCK_GROUP); expect(actionSpies.setFrequentGroup).toHaveBeenCalledWith(expect.any(Object), MOCK_GROUP);
}); });
}); });
describe('when @first-open is emitted', () => {
beforeEach(() => {
findSearchableDropdown().vm.$emit('first-open');
});
it('calls loadFrequentGroups', () => {
expect(actionSpies.loadFrequentGroups).toHaveBeenCalledTimes(1);
});
});
}); });
describe('computed', () => { describe('computed', () => {
...@@ -145,14 +153,4 @@ describe('GroupFilter', () => { ...@@ -145,14 +153,4 @@ describe('GroupFilter', () => {
}); });
}); });
}); });
describe('onCreate', () => {
beforeEach(() => {
createComponent();
});
it('calls loadFrequentGroups', () => {
expect(actionSpies.loadFrequentGroups).toHaveBeenCalledTimes(1);
});
});
}); });
...@@ -119,6 +119,16 @@ describe('ProjectFilter', () => { ...@@ -119,6 +119,16 @@ describe('ProjectFilter', () => {
}); });
}); });
}); });
describe('when @first-open is emitted', () => {
beforeEach(() => {
findSearchableDropdown().vm.$emit('first-open');
});
it('calls loadFrequentProjects', () => {
expect(actionSpies.loadFrequentProjects).toHaveBeenCalledTimes(1);
});
});
}); });
describe('computed', () => { describe('computed', () => {
...@@ -144,14 +154,4 @@ describe('ProjectFilter', () => { ...@@ -144,14 +154,4 @@ describe('ProjectFilter', () => {
}); });
}); });
}); });
describe('onCreate', () => {
beforeEach(() => {
createComponent();
});
it('calls loadFrequentProjects', () => {
expect(actionSpies.loadFrequentProjects).toHaveBeenCalledTimes(1);
});
});
}); });
...@@ -159,5 +159,30 @@ describe('Global Search Searchable Dropdown', () => { ...@@ -159,5 +159,30 @@ describe('Global Search Searchable Dropdown', () => {
expect(wrapper.emitted('change')[0]).toEqual([MOCK_GROUPS[0]]); expect(wrapper.emitted('change')[0]).toEqual([MOCK_GROUPS[0]]);
}); });
describe('opening the dropdown', () => {
describe('for the first time', () => {
beforeEach(() => {
findGlDropdown().vm.$emit('show');
});
it('$emits @search and @first-open', () => {
expect(wrapper.emitted('search')[0]).toStrictEqual([wrapper.vm.searchText]);
expect(wrapper.emitted('first-open')[0]).toStrictEqual([]);
});
});
describe('not for the first time', () => {
beforeEach(() => {
wrapper.setData({ hasBeenOpened: true });
findGlDropdown().vm.$emit('show');
});
it('$emits @search and not @first-open', () => {
expect(wrapper.emitted('search')[0]).toStrictEqual([wrapper.vm.searchText]);
expect(wrapper.emitted('first-open')).toBeUndefined();
});
});
});
}); });
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment