diff options
Diffstat (limited to 'spec/frontend/super_sidebar/utils_spec.js')
-rw-r--r-- | spec/frontend/super_sidebar/utils_spec.js | 167 |
1 files changed, 162 insertions, 5 deletions
diff --git a/spec/frontend/super_sidebar/utils_spec.js b/spec/frontend/super_sidebar/utils_spec.js index 8c8673ddbc4..536599e6c12 100644 --- a/spec/frontend/super_sidebar/utils_spec.js +++ b/spec/frontend/super_sidebar/utils_spec.js @@ -1,14 +1,21 @@ +import * as Sentry from '@sentry/browser'; import { getTopFrequentItems, trackContextAccess, formatContextSwitcherItems, + getItemsFromLocalStorage, + removeItemFromLocalStorage, 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'; +import { cachedFrequentProjects, searchUserProjectsAndGroupsResponseMock } from './mock_data'; + +jest.mock('@sentry/browser'); + +useLocalStorageSpy(); describe('Super sidebar utils spec', () => { describe('getTopFrequentItems', () => { @@ -35,8 +42,6 @@ describe('Super sidebar utils spec', () => { }); describe('trackContextAccess', () => { - useLocalStorageSpy(); - const username = 'root'; const context = { namespace: 'groups', @@ -65,7 +70,7 @@ describe('Super sidebar utils spec', () => { ); }); - it('updates existing item if it was persisted to the local storage over 15 minutes ago', () => { + it('updates existing item frequency/access time if it was persisted to the local storage over 15 minutes ago', () => { window.localStorage.setItem( storageKey, JSON.stringify([ @@ -90,7 +95,7 @@ describe('Super sidebar utils spec', () => { ); }); - it('leaves item as is if it was persisted to the local storage under 15 minutes ago', () => { + it('leaves item frequency/access time as is if it was persisted to the local storage under 15 minutes ago', () => { const jsonString = JSON.stringify([ { id: 1, @@ -109,6 +114,39 @@ describe('Super sidebar utils spec', () => { expect(window.localStorage.setItem).toHaveBeenLastCalledWith(storageKey, jsonString); }); + it('always updates stored item metadata', () => { + window.localStorage.setItem( + storageKey, + JSON.stringify([ + { + id: 1, + frequency: 2, + lastAccessedOn: Date.now(), + }, + ]), + ); + + trackContextAccess(username, { + ...context, + item: { + ...context.item, + avatarUrl: '/group.png', + }, + }); + + expect(window.localStorage.setItem).toHaveBeenCalledWith( + storageKey, + JSON.stringify([ + { + id: 1, + avatarUrl: '/group.png', + frequency: 2, + lastAccessedOn: Date.now(), + }, + ]), + ); + }); + 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) => ({ @@ -159,6 +197,125 @@ describe('Super sidebar utils spec', () => { }); }); + describe('getItemsFromLocalStorage', () => { + const storageKey = 'mockStorageKey'; + const maxItems = 5; + const storedItems = JSON.parse(cachedFrequentProjects); + + beforeEach(() => { + window.localStorage.setItem(storageKey, cachedFrequentProjects); + }); + + describe('when localStorage cannot be accessed', () => { + beforeEach(() => { + jest.spyOn(AccessorUtilities, 'canUseLocalStorage').mockReturnValue(false); + }); + + it('returns an empty array', () => { + const items = getItemsFromLocalStorage({ storageKey, maxItems }); + expect(items).toEqual([]); + }); + }); + + describe('when localStorage contains parseable data', () => { + it('returns an array of items limited by max items', () => { + const items = getItemsFromLocalStorage({ storageKey, maxItems }); + expect(items.length).toEqual(maxItems); + + items.forEach((item) => { + expect(storedItems).toContainEqual(item); + }); + }); + + it('returns all items if max items is large', () => { + const items = getItemsFromLocalStorage({ storageKey, maxItems: 1 }); + expect(items.length).toEqual(1); + + expect(storedItems).toContainEqual(items[0]); + }); + }); + + describe('when localStorage contains unparseable data', () => { + let items; + + beforeEach(() => { + window.localStorage.setItem(storageKey, 'unparseable'); + items = getItemsFromLocalStorage({ storageKey, maxItems }); + }); + + it('logs an error to Sentry', () => { + expect(Sentry.captureException).toHaveBeenCalled(); + }); + + it('returns an empty array', () => { + expect(items).toEqual([]); + }); + }); + }); + + describe('removeItemFromLocalStorage', () => { + const storageKey = 'mockStorageKey'; + const originalStoredItems = JSON.parse(cachedFrequentProjects); + + beforeEach(() => { + window.localStorage.setItem(storageKey, cachedFrequentProjects); + }); + + describe('when given an item to delete', () => { + let items; + let modifiedStoredItems; + + beforeEach(() => { + items = removeItemFromLocalStorage({ storageKey, item: { id: 3 } }); + modifiedStoredItems = JSON.parse(window.localStorage.getItem(storageKey)); + }); + + it('removes the item from localStorage', () => { + expect(modifiedStoredItems.length).toBe(originalStoredItems.length - 1); + expect(modifiedStoredItems).not.toContainEqual(originalStoredItems[2]); + }); + + it('returns the resulting stored structure', () => { + expect(items).toEqual(modifiedStoredItems); + }); + }); + + describe('when given an unknown item to delete', () => { + let items; + let modifiedStoredItems; + + beforeEach(() => { + items = removeItemFromLocalStorage({ storageKey, item: { id: 'does-not-exist' } }); + modifiedStoredItems = JSON.parse(window.localStorage.getItem(storageKey)); + }); + + it('does not change the stored value', () => { + expect(modifiedStoredItems).toEqual(originalStoredItems); + }); + + it('returns the stored structure', () => { + expect(items).toEqual(originalStoredItems); + }); + }); + + describe('when localStorage has unparseable data', () => { + let items; + + beforeEach(() => { + window.localStorage.setItem(storageKey, 'unparseable'); + items = removeItemFromLocalStorage({ storageKey, item: { id: 3 } }); + }); + + it('logs an error to Sentry', () => { + expect(Sentry.captureException).toHaveBeenCalled(); + }); + + it('returns an empty array', () => { + expect(items).toEqual([]); + }); + }); + }); + describe('ariaCurrent', () => { it.each` isActive | expected |