diff options
Diffstat (limited to 'spec/frontend/super_sidebar/utils_spec.js')
-rw-r--r-- | spec/frontend/super_sidebar/utils_spec.js | 171 |
1 files changed, 171 insertions, 0 deletions
diff --git a/spec/frontend/super_sidebar/utils_spec.js b/spec/frontend/super_sidebar/utils_spec.js new file mode 100644 index 00000000000..8c8673ddbc4 --- /dev/null +++ b/spec/frontend/super_sidebar/utils_spec.js @@ -0,0 +1,171 @@ +import { + getTopFrequentItems, + trackContextAccess, + formatContextSwitcherItems, + ariaCurrent, +} from '~/super_sidebar/utils'; +import { useLocalStorageSpy } from 'helpers/local_storage_helper'; +import AccessorUtilities from '~/lib/utils/accessor'; +import { FREQUENT_ITEMS, FIFTEEN_MINUTES_IN_MS } from '~/frequent_items/constants'; +import { unsortedFrequentItems, sortedFrequentItems } from '../frequent_items/mock_data'; +import { searchUserProjectsAndGroupsResponseMock } from './mock_data'; + +describe('Super sidebar utils spec', () => { + describe('getTopFrequentItems', () => { + const maxItems = 3; + + it.each([undefined, null])('returns empty array if `items` is %s', (items) => { + const result = getTopFrequentItems(items); + + expect(result.length).toBe(0); + }); + + it('returns the requested amount of items', () => { + const result = getTopFrequentItems(unsortedFrequentItems, maxItems); + + expect(result.length).toBe(maxItems); + }); + + it('sorts frequent items in order of frequency and lastAccessedOn', () => { + const result = getTopFrequentItems(unsortedFrequentItems, maxItems); + const expectedResult = sortedFrequentItems.slice(0, maxItems); + + expect(result).toEqual(expectedResult); + }); + }); + + describe('trackContextAccess', () => { + useLocalStorageSpy(); + + const username = 'root'; + const context = { + namespace: 'groups', + item: { id: 1 }, + }; + const storageKey = `${username}/frequent-${context.namespace}`; + + it('returns `false` if local storage is not available', () => { + jest.spyOn(AccessorUtilities, 'canUseLocalStorage').mockReturnValue(false); + + expect(trackContextAccess()).toBe(false); + }); + + it('creates a new item if it does not exist in the local storage', () => { + trackContextAccess(username, context); + + expect(window.localStorage.setItem).toHaveBeenCalledWith( + storageKey, + JSON.stringify([ + { + id: 1, + frequency: 1, + lastAccessedOn: Date.now(), + }, + ]), + ); + }); + + it('updates existing item if it was persisted to the local storage over 15 minutes ago', () => { + window.localStorage.setItem( + storageKey, + JSON.stringify([ + { + id: 1, + frequency: 2, + lastAccessedOn: Date.now() - FIFTEEN_MINUTES_IN_MS - 1, + }, + ]), + ); + trackContextAccess(username, context); + + expect(window.localStorage.setItem).toHaveBeenCalledWith( + storageKey, + JSON.stringify([ + { + id: 1, + frequency: 3, + lastAccessedOn: Date.now(), + }, + ]), + ); + }); + + it('leaves item as is if it was persisted to the local storage under 15 minutes ago', () => { + const jsonString = JSON.stringify([ + { + id: 1, + frequency: 2, + lastAccessedOn: Date.now() - FIFTEEN_MINUTES_IN_MS, + }, + ]); + window.localStorage.setItem(storageKey, jsonString); + + expect(window.localStorage.setItem).toHaveBeenCalledTimes(1); + expect(window.localStorage.setItem).toHaveBeenCalledWith(storageKey, jsonString); + + trackContextAccess(username, context); + + expect(window.localStorage.setItem).toHaveBeenCalledTimes(3); + expect(window.localStorage.setItem).toHaveBeenLastCalledWith(storageKey, jsonString); + }); + + it('replaces the least popular item in the local storage once the persisted items limit has been hit', () => { + // Add the maximum amount of items to the local storage, in increasing popularity + const storedItems = Array.from({ length: FREQUENT_ITEMS.MAX_COUNT }).map((_, i) => ({ + id: i + 1, + frequency: i + 1, + lastAccessedOn: Date.now(), + })); + // The first item is considered the least popular one as it has the lowest frequency (1) + const [leastPopularItem] = storedItems; + // Persist the list to the local storage + const jsonString = JSON.stringify(storedItems); + window.localStorage.setItem(storageKey, jsonString); + // Track some new item that hasn't been visited yet + const newItem = { + id: FREQUENT_ITEMS.MAX_COUNT + 1, + }; + trackContextAccess(username, { + namespace: 'groups', + item: newItem, + }); + // Finally, retrieve the final data from the local storage + const finallyStoredItems = JSON.parse(window.localStorage.getItem(storageKey)); + + expect(finallyStoredItems).not.toEqual(expect.arrayContaining([leastPopularItem])); + expect(finallyStoredItems).toEqual( + expect.arrayContaining([ + expect.objectContaining({ + id: newItem.id, + frequency: 1, + }), + ]), + ); + }); + }); + + describe('formatContextSwitcherItems', () => { + it('returns the formatted items', () => { + const projects = searchUserProjectsAndGroupsResponseMock.data.projects.nodes; + expect(formatContextSwitcherItems(projects)).toEqual([ + { + id: projects[0].id, + avatar: null, + title: projects[0].name, + subtitle: 'Gitlab Org', + link: projects[0].webUrl, + }, + ]); + }); + }); + + describe('ariaCurrent', () => { + it.each` + isActive | expected + ${true} | ${'page'} + ${false} | ${null} + `('returns `$expected` when `isActive` is `$isActive`', ({ isActive, expected }) => { + expect(ariaCurrent(isActive)).toBe(expected); + }); + }); +}); |