mirror of
https://github.com/iconify/iconify.git
synced 2024-12-22 09:48:54 +00:00
feat: remove browser storage, deprecate exported functions
This commit is contained in:
parent
bfdd3f021d
commit
3fe6adc34e
@ -65,8 +65,6 @@ import {
|
||||
import { sendAPIQuery } from '@iconify/core/lib/api/query';
|
||||
|
||||
// Cache
|
||||
import { initBrowserStorage } from '@iconify/core/lib/browser-storage';
|
||||
import { toggleBrowserCache } from '@iconify/core/lib/browser-storage/functions';
|
||||
import type {
|
||||
IconifyBrowserCacheType,
|
||||
IconifyBrowserCacheFunctions,
|
||||
@ -135,16 +133,20 @@ export { IconifyBrowserCacheType };
|
||||
|
||||
/**
|
||||
* Enable cache
|
||||
*
|
||||
* @deprecated No longer used
|
||||
*/
|
||||
function enableCache(storage: IconifyBrowserCacheType): void {
|
||||
toggleBrowserCache(storage, true);
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable cache
|
||||
*
|
||||
* @deprecated No longer used
|
||||
*/
|
||||
function disableCache(storage: IconifyBrowserCacheType): void {
|
||||
toggleBrowserCache(storage, false);
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
@ -160,9 +162,6 @@ setAPIModule('', fetchAPIModule);
|
||||
* Browser stuff
|
||||
*/
|
||||
if (typeof document !== 'undefined' && typeof window !== 'undefined') {
|
||||
// Set cache and load existing cache
|
||||
initBrowserStorage();
|
||||
|
||||
interface WindowWithIconifyStuff {
|
||||
IconifyPreload?: IconifyJSON[] | IconifyJSON;
|
||||
IconifyProviders?: Record<string, PartialIconifyAPIConfig>;
|
||||
|
@ -65,8 +65,6 @@ import {
|
||||
import { sendAPIQuery } from '@iconify/core/lib/api/query';
|
||||
|
||||
// Cache
|
||||
import { initBrowserStorage } from '@iconify/core/lib/browser-storage';
|
||||
import { toggleBrowserCache } from '@iconify/core/lib/browser-storage/functions';
|
||||
import type {
|
||||
IconifyBrowserCacheType,
|
||||
IconifyBrowserCacheFunctions,
|
||||
@ -132,16 +130,20 @@ export { IconifyBrowserCacheType };
|
||||
|
||||
/**
|
||||
* Enable cache
|
||||
*
|
||||
* @deprecated No longer used
|
||||
*/
|
||||
function enableCache(storage: IconifyBrowserCacheType): void {
|
||||
toggleBrowserCache(storage, true);
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable cache
|
||||
*
|
||||
* @deprecated No longer used
|
||||
*/
|
||||
function disableCache(storage: IconifyBrowserCacheType): void {
|
||||
toggleBrowserCache(storage, false);
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
@ -157,9 +159,6 @@ setAPIModule('', fetchAPIModule);
|
||||
* Browser stuff
|
||||
*/
|
||||
if (typeof document !== 'undefined' && typeof window !== 'undefined') {
|
||||
// Set cache and load existing cache
|
||||
initBrowserStorage();
|
||||
|
||||
interface WindowWithIconifyStuff {
|
||||
IconifyPreload?: IconifyJSON[] | IconifyJSON;
|
||||
IconifyProviders?: Record<string, PartialIconifyAPIConfig>;
|
||||
|
@ -75,8 +75,6 @@ import {
|
||||
import { sendAPIQuery } from '@iconify/core/lib/api/query';
|
||||
|
||||
// Cache
|
||||
import { initBrowserStorage } from '@iconify/core/lib/browser-storage';
|
||||
import { toggleBrowserCache } from '@iconify/core/lib/browser-storage/functions';
|
||||
import type {
|
||||
IconifyBrowserCacheType,
|
||||
IconifyBrowserCacheFunctions,
|
||||
@ -144,16 +142,20 @@ export { IconifyBrowserCacheType };
|
||||
|
||||
/**
|
||||
* Enable cache
|
||||
*
|
||||
* @deprecated No longer used
|
||||
*/
|
||||
function enableCache(storage: IconifyBrowserCacheType): void {
|
||||
toggleBrowserCache(storage, true);
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
* Disable cache
|
||||
*
|
||||
* @deprecated No longer used
|
||||
*/
|
||||
function disableCache(storage: IconifyBrowserCacheType): void {
|
||||
toggleBrowserCache(storage, false);
|
||||
//
|
||||
}
|
||||
|
||||
/**
|
||||
@ -169,9 +171,6 @@ setAPIModule('', fetchAPIModule);
|
||||
* Browser stuff
|
||||
*/
|
||||
if (typeof document !== 'undefined' && typeof window !== 'undefined') {
|
||||
// Set cache and load existing cache
|
||||
initBrowserStorage();
|
||||
|
||||
interface WindowWithIconifyStuff {
|
||||
IconifyPreload?: IconifyJSON[] | IconifyJSON;
|
||||
IconifyProviders?: Record<string, PartialIconifyAPIConfig>;
|
||||
|
@ -46,8 +46,6 @@ import {
|
||||
} from '@iconify/core/lib/api/loaders';
|
||||
|
||||
// Cache
|
||||
import { initBrowserStorage } from '@iconify/core/lib/browser-storage';
|
||||
import { toggleBrowserCache } from '@iconify/core/lib/browser-storage/functions';
|
||||
import type {
|
||||
IconifyBrowserCacheType,
|
||||
IconifyBrowserCacheFunctions,
|
||||
@ -101,9 +99,6 @@ export function exportFunctions(): IconifyExportedFunctions {
|
||||
//
|
||||
}
|
||||
if (_window) {
|
||||
// Set cache and load existing cache
|
||||
initBrowserStorage();
|
||||
|
||||
// Load icons from global "IconifyPreload"
|
||||
if (_window.IconifyPreload !== void 0) {
|
||||
const preload = _window.IconifyPreload;
|
||||
@ -171,10 +166,14 @@ export function exportFunctions(): IconifyExportedFunctions {
|
||||
};
|
||||
|
||||
return {
|
||||
enableCache: (storage: IconifyBrowserCacheType) =>
|
||||
toggleBrowserCache(storage, true),
|
||||
disableCache: (storage: IconifyBrowserCacheType) =>
|
||||
toggleBrowserCache(storage, false),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
enableCache: (storage: IconifyBrowserCacheType) => {
|
||||
// No longer used
|
||||
},
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
disableCache: (storage: IconifyBrowserCacheType) => {
|
||||
// No longer used
|
||||
},
|
||||
iconLoaded,
|
||||
iconExists: iconLoaded, // deprecated, kept to avoid breaking changes
|
||||
getIcon,
|
||||
|
@ -62,50 +62,10 @@
|
||||
"require": "./lib/api/types.cjs",
|
||||
"import": "./lib/api/types.mjs"
|
||||
},
|
||||
"./lib/browser-storage/config": {
|
||||
"require": "./lib/browser-storage/config.cjs",
|
||||
"import": "./lib/browser-storage/config.mjs"
|
||||
},
|
||||
"./lib/browser-storage/count": {
|
||||
"require": "./lib/browser-storage/count.cjs",
|
||||
"import": "./lib/browser-storage/count.mjs"
|
||||
},
|
||||
"./lib/browser-storage/data": {
|
||||
"require": "./lib/browser-storage/data.cjs",
|
||||
"import": "./lib/browser-storage/data.mjs"
|
||||
},
|
||||
"./lib/browser-storage/foreach": {
|
||||
"require": "./lib/browser-storage/foreach.cjs",
|
||||
"import": "./lib/browser-storage/foreach.mjs"
|
||||
},
|
||||
"./lib/browser-storage/functions": {
|
||||
"require": "./lib/browser-storage/functions.cjs",
|
||||
"import": "./lib/browser-storage/functions.mjs"
|
||||
},
|
||||
"./lib/browser-storage/global": {
|
||||
"require": "./lib/browser-storage/global.cjs",
|
||||
"import": "./lib/browser-storage/global.mjs"
|
||||
},
|
||||
"./lib/browser-storage": {
|
||||
"require": "./lib/browser-storage/index.cjs",
|
||||
"import": "./lib/browser-storage/index.mjs"
|
||||
},
|
||||
"./lib/browser-storage/index": {
|
||||
"require": "./lib/browser-storage/index.cjs",
|
||||
"import": "./lib/browser-storage/index.mjs"
|
||||
},
|
||||
"./lib/browser-storage/item": {
|
||||
"require": "./lib/browser-storage/item.cjs",
|
||||
"import": "./lib/browser-storage/item.mjs"
|
||||
},
|
||||
"./lib/browser-storage/mock": {
|
||||
"require": "./lib/browser-storage/mock.cjs",
|
||||
"import": "./lib/browser-storage/mock.mjs"
|
||||
},
|
||||
"./lib/browser-storage/store": {
|
||||
"require": "./lib/browser-storage/store.cjs",
|
||||
"import": "./lib/browser-storage/store.mjs"
|
||||
},
|
||||
"./lib/browser-storage/types": {
|
||||
"require": "./lib/browser-storage/types.cjs",
|
||||
"import": "./lib/browser-storage/types.mjs"
|
||||
|
@ -12,7 +12,6 @@ import { getStorage, addIconSet } from '../storage/storage';
|
||||
import { listToIcons } from '../icon/list';
|
||||
import { allowSimpleNames, getIconData } from '../storage/functions';
|
||||
import { sendAPIQuery } from './query';
|
||||
import { storeInBrowserStorage } from '../browser-storage/store';
|
||||
import type { IconStorageWithAPI } from './types';
|
||||
import { defaultIconProps } from '@iconify/utils/lib/icon/defaults';
|
||||
|
||||
@ -91,8 +90,7 @@ function checkIconNamesForAPI(icons: string[]): CheckIconNames {
|
||||
function parseLoaderResponse(
|
||||
storage: IconStorageWithAPI,
|
||||
icons: string[],
|
||||
data: unknown,
|
||||
isAPIResponse: boolean
|
||||
data: unknown
|
||||
) {
|
||||
function checkMissing() {
|
||||
const pending = storage.pendingIcons;
|
||||
@ -118,11 +116,6 @@ function parseLoaderResponse(
|
||||
checkMissing();
|
||||
return;
|
||||
}
|
||||
|
||||
// Cache API response
|
||||
if (isAPIResponse) {
|
||||
storeInBrowserStorage(storage, data as IconifyJSON);
|
||||
}
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
@ -189,7 +182,7 @@ function loadNewIcons(storage: IconStorageWithAPI, icons: string[]): void {
|
||||
parsePossiblyAsyncResponse(
|
||||
storage.loadIcons(icons, prefix, provider),
|
||||
(data) => {
|
||||
parseLoaderResponse(storage, icons, data, false);
|
||||
parseLoaderResponse(storage, icons, data);
|
||||
}
|
||||
);
|
||||
return;
|
||||
@ -208,7 +201,7 @@ function loadNewIcons(storage: IconStorageWithAPI, icons: string[]): void {
|
||||
},
|
||||
}
|
||||
: null;
|
||||
parseLoaderResponse(storage, [name], iconSet, false);
|
||||
parseLoaderResponse(storage, [name], iconSet);
|
||||
});
|
||||
});
|
||||
return;
|
||||
@ -220,7 +213,7 @@ function loadNewIcons(storage: IconStorageWithAPI, icons: string[]): void {
|
||||
|
||||
if (invalid.length) {
|
||||
// Invalid icons
|
||||
parseLoaderResponse(storage, invalid, null, false);
|
||||
parseLoaderResponse(storage, invalid, null);
|
||||
}
|
||||
if (!valid.length) {
|
||||
// No valid icons to load
|
||||
@ -233,7 +226,7 @@ function loadNewIcons(storage: IconStorageWithAPI, icons: string[]): void {
|
||||
: null;
|
||||
if (!api) {
|
||||
// API module not found
|
||||
parseLoaderResponse(storage, valid, null, false);
|
||||
parseLoaderResponse(storage, valid, null);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -241,7 +234,7 @@ function loadNewIcons(storage: IconStorageWithAPI, icons: string[]): void {
|
||||
const params = api.prepare(provider, prefix, valid);
|
||||
params.forEach((item) => {
|
||||
sendAPIQuery(provider, item, (data) => {
|
||||
parseLoaderResponse(storage, item.icons, data, true);
|
||||
parseLoaderResponse(storage, item.icons, data);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,14 +0,0 @@
|
||||
// Cache version. Bump when structure changes
|
||||
export const browserCacheVersion = 'iconify2';
|
||||
|
||||
// Cache keys
|
||||
export const browserCachePrefix = 'iconify';
|
||||
export const browserCacheCountKey = browserCachePrefix + '-count';
|
||||
export const browserCacheVersionKey = browserCachePrefix + '-version';
|
||||
|
||||
// Cache expiration
|
||||
export const browserStorageHour = 3600000;
|
||||
export const browserStorageCacheExpiration = 168; // In hours
|
||||
|
||||
// Maximum number of stored items
|
||||
export const browserStorageLimit = 50;
|
@ -1,24 +0,0 @@
|
||||
import { browserCacheCountKey } from './config';
|
||||
import { getStoredItem, setStoredItem } from './item';
|
||||
import type { BrowserStorageInstance } from './types';
|
||||
|
||||
/**
|
||||
* Change current count for storage
|
||||
*/
|
||||
export function setBrowserStorageItemsCount(
|
||||
storage: BrowserStorageInstance,
|
||||
value: number
|
||||
): true | undefined {
|
||||
return setStoredItem(storage, browserCacheCountKey, value.toString());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get current count from storage
|
||||
*/
|
||||
export function getBrowserStorageItemsCount(
|
||||
storage: typeof localStorage
|
||||
): number {
|
||||
return (
|
||||
parseInt(getStoredItem(storage, browserCacheCountKey) as string) || 0
|
||||
);
|
||||
}
|
@ -1,26 +0,0 @@
|
||||
import type { BrowserStorageConfig, BrowserStorageEmptyList } from './types';
|
||||
|
||||
/**
|
||||
* Storage configuration
|
||||
*/
|
||||
export const browserStorageConfig: BrowserStorageConfig = {
|
||||
local: true,
|
||||
session: true,
|
||||
};
|
||||
|
||||
/**
|
||||
* List of empty items
|
||||
*/
|
||||
export const browserStorageEmptyItems: BrowserStorageEmptyList = {
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
};
|
||||
|
||||
/**
|
||||
* Flag to check if storage has been loaded
|
||||
*/
|
||||
export let browserStorageStatus = false;
|
||||
|
||||
export function setBrowserStorageStatus(status: boolean) {
|
||||
browserStorageStatus = status;
|
||||
}
|
@ -1,108 +0,0 @@
|
||||
import {
|
||||
browserCachePrefix,
|
||||
browserCacheVersion,
|
||||
browserCacheVersionKey,
|
||||
browserStorageCacheExpiration,
|
||||
browserStorageHour,
|
||||
} from './config';
|
||||
import {
|
||||
getBrowserStorageItemsCount,
|
||||
setBrowserStorageItemsCount,
|
||||
} from './count';
|
||||
import { browserStorageEmptyItems } from './data';
|
||||
import { getBrowserStorage } from './global';
|
||||
import { getStoredItem, removeStoredItem, setStoredItem } from './item';
|
||||
import type { BrowserStorageConfig, BrowserStorageItem } from './types';
|
||||
|
||||
// Result of callback. false = delete item
|
||||
type IterateBrowserStorageCallbackResult = true | false;
|
||||
|
||||
// Callback
|
||||
type IterateBrowserStorageCallback = (
|
||||
item: BrowserStorageItem,
|
||||
index: number
|
||||
) => IterateBrowserStorageCallbackResult;
|
||||
|
||||
/**
|
||||
* Iterate items in browser storage
|
||||
*/
|
||||
export function iterateBrowserStorage(
|
||||
key: keyof BrowserStorageConfig,
|
||||
callback: IterateBrowserStorageCallback
|
||||
) {
|
||||
const func = getBrowserStorage(key);
|
||||
if (!func) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get version
|
||||
const version = getStoredItem(func, browserCacheVersionKey);
|
||||
if (version !== browserCacheVersion) {
|
||||
if (version) {
|
||||
// Version is set, but invalid - remove old entries
|
||||
const total = getBrowserStorageItemsCount(func);
|
||||
for (let i = 0; i < total; i++) {
|
||||
removeStoredItem(func, browserCachePrefix + i.toString());
|
||||
}
|
||||
}
|
||||
|
||||
// Empty data
|
||||
setStoredItem(func, browserCacheVersionKey, browserCacheVersion);
|
||||
setBrowserStorageItemsCount(func, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
// Minimum time
|
||||
const minTime =
|
||||
Math.floor(Date.now() / browserStorageHour) -
|
||||
browserStorageCacheExpiration;
|
||||
|
||||
// Parse item
|
||||
const parseItem = (index: number): true | undefined => {
|
||||
const name = browserCachePrefix + index.toString();
|
||||
const item = getStoredItem(func, name);
|
||||
|
||||
if (typeof item !== 'string') {
|
||||
// Does not exist
|
||||
return;
|
||||
}
|
||||
|
||||
// Get item, validate it
|
||||
try {
|
||||
// Parse, check time stamp
|
||||
const data = JSON.parse(item) as BrowserStorageItem;
|
||||
if (
|
||||
typeof data === 'object' &&
|
||||
typeof data.cached === 'number' &&
|
||||
data.cached > minTime &&
|
||||
typeof data.provider === 'string' &&
|
||||
typeof data.data === 'object' &&
|
||||
typeof data.data.prefix === 'string' &&
|
||||
// Valid item: run callback
|
||||
callback(data, index)
|
||||
) {
|
||||
return true;
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
} catch (err) {
|
||||
//
|
||||
}
|
||||
|
||||
// Remove item
|
||||
removeStoredItem(func, name);
|
||||
};
|
||||
|
||||
let total = getBrowserStorageItemsCount(func);
|
||||
for (let i = total - 1; i >= 0; i--) {
|
||||
if (!parseItem(i)) {
|
||||
if (i === total - 1) {
|
||||
// Last item - reduce count
|
||||
total--;
|
||||
setBrowserStorageItemsCount(func, total);
|
||||
} else {
|
||||
// Mark as empty
|
||||
browserStorageEmptyItems[key].add(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -1,34 +1,29 @@
|
||||
import { browserStorageConfig } from './data';
|
||||
import type { BrowserStorageType } from './types';
|
||||
/* eslint-disable @typescript-eslint/no-unused-vars */
|
||||
import type { BrowserStorageType } from './types.js';
|
||||
|
||||
/**
|
||||
* Cache types
|
||||
*
|
||||
* @deprecated This type is not used anymore
|
||||
*/
|
||||
export type IconifyBrowserCacheType = BrowserStorageType | 'all';
|
||||
|
||||
/**
|
||||
* Toggle cache
|
||||
*
|
||||
* @deprecated This function is not used anymore
|
||||
*/
|
||||
export function toggleBrowserCache(
|
||||
storage: IconifyBrowserCacheType,
|
||||
value: boolean
|
||||
): void {
|
||||
switch (storage) {
|
||||
case 'local':
|
||||
case 'session':
|
||||
browserStorageConfig[storage] = value;
|
||||
break;
|
||||
|
||||
case 'all':
|
||||
for (const key in browserStorageConfig) {
|
||||
browserStorageConfig[key as BrowserStorageType] = value;
|
||||
}
|
||||
break;
|
||||
}
|
||||
// Not used
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface for exported functions
|
||||
*
|
||||
* @deprecated This type is not used anymore
|
||||
*/
|
||||
export interface IconifyBrowserCacheFunctions {
|
||||
enableCache: (storage: IconifyBrowserCacheType) => void;
|
||||
|
@ -1,41 +0,0 @@
|
||||
import { browserStorageConfig } from './data';
|
||||
import type { BrowserStorageInstance, BrowserStorageType } from './types';
|
||||
|
||||
/**
|
||||
* Fake window for unit testing
|
||||
*/
|
||||
type FakeWindow = Record<string, BrowserStorageInstance>;
|
||||
|
||||
let _window: FakeWindow =
|
||||
typeof window === 'undefined' ? {} : (window as unknown as FakeWindow);
|
||||
|
||||
/**
|
||||
* Get browser storage
|
||||
*/
|
||||
export function getBrowserStorage(
|
||||
key: BrowserStorageType
|
||||
): BrowserStorageInstance | undefined {
|
||||
const attr = key + 'Storage';
|
||||
try {
|
||||
if (
|
||||
_window &&
|
||||
_window[attr] &&
|
||||
typeof _window[attr].length === 'number'
|
||||
) {
|
||||
return _window[attr];
|
||||
}
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
} catch (err) {
|
||||
//
|
||||
}
|
||||
|
||||
// Failed - mark as disabled
|
||||
browserStorageConfig[key] = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Mock window for unit testing
|
||||
*/
|
||||
export function mockWindow(fakeWindow: FakeWindow): void {
|
||||
_window = fakeWindow;
|
||||
}
|
@ -1,48 +0,0 @@
|
||||
import { addIconSet, getStorage } from '../storage/storage';
|
||||
import {
|
||||
browserStorageConfig,
|
||||
browserStorageStatus,
|
||||
setBrowserStorageStatus,
|
||||
} from './data';
|
||||
import { iterateBrowserStorage } from './foreach';
|
||||
import type { BrowserStorageType, IconStorageWithCache } from './types';
|
||||
|
||||
/**
|
||||
* Load icons from cache
|
||||
*/
|
||||
export function initBrowserStorage() {
|
||||
if (browserStorageStatus) {
|
||||
return;
|
||||
}
|
||||
setBrowserStorageStatus(true);
|
||||
|
||||
// Load each storage
|
||||
for (const key in browserStorageConfig) {
|
||||
iterateBrowserStorage(key as BrowserStorageType, (item) => {
|
||||
// Add icon set
|
||||
const iconSet = item.data;
|
||||
|
||||
const provider = item.provider;
|
||||
const prefix = iconSet.prefix;
|
||||
const storage = getStorage(
|
||||
provider,
|
||||
prefix
|
||||
) as IconStorageWithCache;
|
||||
if (!addIconSet(storage, iconSet).length) {
|
||||
// No valid icons
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store lastModified, -1 if not set to get truthy value
|
||||
// Smallest of values is stored to fix cache
|
||||
const lastModified = iconSet.lastModified || -1;
|
||||
storage.lastModifiedCached = storage.lastModifiedCached
|
||||
? Math.min(storage.lastModifiedCached, lastModified)
|
||||
: lastModified;
|
||||
|
||||
return true;
|
||||
});
|
||||
}
|
||||
|
||||
// Check for update
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
import type { BrowserStorageInstance } from './types';
|
||||
|
||||
/**
|
||||
* Get stored item with try..catch
|
||||
*/
|
||||
export function getStoredItem(
|
||||
func: BrowserStorageInstance,
|
||||
key: string
|
||||
): string | null | undefined {
|
||||
try {
|
||||
return func.getItem(key);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
} catch (err) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Store item with try..catch
|
||||
*/
|
||||
export function setStoredItem(
|
||||
func: BrowserStorageInstance,
|
||||
key: string,
|
||||
value: string
|
||||
): true | undefined {
|
||||
try {
|
||||
func.setItem(key, value);
|
||||
return true;
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
} catch (err) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove item with try..catch
|
||||
*/
|
||||
export function removeStoredItem(func: BrowserStorageInstance, key: string) {
|
||||
try {
|
||||
func.removeItem(key);
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
} catch (err) {
|
||||
//
|
||||
}
|
||||
}
|
@ -1,105 +0,0 @@
|
||||
import { mockWindow } from './global';
|
||||
import {
|
||||
browserStorageConfig,
|
||||
browserStorageEmptyItems,
|
||||
setBrowserStorageStatus,
|
||||
} from './data';
|
||||
import type { BrowserStorageType } from './types';
|
||||
|
||||
/**
|
||||
* Get next icon set prefix for testing
|
||||
*/
|
||||
let prefixCounter = 0;
|
||||
export function nextPrefix(): string {
|
||||
return 'fake-storage-' + (prefixCounter++).toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Storage class
|
||||
*/
|
||||
export class Storage {
|
||||
canRead = true;
|
||||
canWrite = true;
|
||||
items = Object.create(null) as Record<string, string>;
|
||||
|
||||
/**
|
||||
* Get number of items
|
||||
*/
|
||||
get length(): number {
|
||||
if (!this.canRead) {
|
||||
throw new Error('Restricted storage');
|
||||
}
|
||||
return Object.keys(this.items).length;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get item
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
getItem(name: string): string | null {
|
||||
if (!this.canRead) {
|
||||
throw new Error('Restricted storage');
|
||||
}
|
||||
return name in this.items ? this.items[name] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set item
|
||||
*
|
||||
* @param name
|
||||
* @param value
|
||||
*/
|
||||
setItem(name: string, value: string): void {
|
||||
if (!this.canWrite) {
|
||||
throw new Error('Read-only storage');
|
||||
}
|
||||
this.items[name] = value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove item
|
||||
*
|
||||
* @param name
|
||||
*/
|
||||
removeItem(name: string): void {
|
||||
if (!this.canWrite) {
|
||||
throw new Error('Read-only storage');
|
||||
}
|
||||
delete this.items[name];
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear everything
|
||||
*/
|
||||
clear(): void {
|
||||
if (!this.canWrite) {
|
||||
throw new Error('Read-only storage');
|
||||
}
|
||||
this.items = Object.create(null) as Record<string, string>;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create fake storage, assign localStorage type
|
||||
*/
|
||||
export function createCache(): typeof localStorage {
|
||||
return new Storage() as unknown as typeof localStorage;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset test
|
||||
*
|
||||
* @param fakeWindow
|
||||
*/
|
||||
export function reset(fakeWindow: Record<string, typeof localStorage>): void {
|
||||
// Replace window
|
||||
mockWindow(fakeWindow);
|
||||
|
||||
// Reset all data
|
||||
setBrowserStorageStatus(false);
|
||||
for (const key in browserStorageConfig) {
|
||||
browserStorageConfig[key as BrowserStorageType] = true;
|
||||
browserStorageEmptyItems[key as BrowserStorageType] = new Set();
|
||||
}
|
||||
}
|
@ -1,132 +0,0 @@
|
||||
import type { IconifyJSON } from '@iconify/types';
|
||||
import type { IconStorage } from '../storage/storage';
|
||||
import {
|
||||
browserCachePrefix,
|
||||
browserStorageHour,
|
||||
browserStorageLimit,
|
||||
} from './config';
|
||||
import {
|
||||
getBrowserStorageItemsCount,
|
||||
setBrowserStorageItemsCount,
|
||||
} from './count';
|
||||
import {
|
||||
browserStorageConfig,
|
||||
browserStorageEmptyItems,
|
||||
browserStorageStatus,
|
||||
} from './data';
|
||||
import { iterateBrowserStorage } from './foreach';
|
||||
import { getBrowserStorage } from './global';
|
||||
import { initBrowserStorage } from './index';
|
||||
import { setStoredItem } from './item';
|
||||
import type {
|
||||
BrowserStorageInstance,
|
||||
BrowserStorageItem,
|
||||
BrowserStorageType,
|
||||
IconStorageWithCache,
|
||||
} from './types';
|
||||
|
||||
/**
|
||||
* Update lastModified in storage
|
||||
*
|
||||
* Returns false if item should not be added to storage because lastModified is too low
|
||||
*/
|
||||
export function updateLastModified(
|
||||
storage: IconStorageWithCache,
|
||||
lastModified: number
|
||||
): boolean {
|
||||
const lastValue = storage.lastModifiedCached;
|
||||
if (
|
||||
// Matches or newer
|
||||
lastValue &&
|
||||
lastValue >= lastModified
|
||||
) {
|
||||
// Nothing to update
|
||||
return lastValue === lastModified;
|
||||
}
|
||||
|
||||
// Update value
|
||||
storage.lastModifiedCached = lastModified;
|
||||
if (lastValue) {
|
||||
// Old value was set: possibly items are in browser cache
|
||||
for (const key in browserStorageConfig) {
|
||||
iterateBrowserStorage(key as BrowserStorageType, (item) => {
|
||||
const iconSet = item.data;
|
||||
// Delete items with same provider and prefix
|
||||
return (
|
||||
item.provider !== storage.provider ||
|
||||
iconSet.prefix !== storage.prefix ||
|
||||
iconSet.lastModified === lastModified
|
||||
);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function to cache icons
|
||||
*/
|
||||
export function storeInBrowserStorage(storage: IconStorage, data: IconifyJSON) {
|
||||
if (!browserStorageStatus) {
|
||||
initBrowserStorage();
|
||||
}
|
||||
|
||||
function store(key: BrowserStorageType): true | undefined {
|
||||
let func: BrowserStorageInstance | undefined;
|
||||
if (!browserStorageConfig[key] || !(func = getBrowserStorage(key))) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get item index
|
||||
const set = browserStorageEmptyItems[key];
|
||||
let index: number;
|
||||
if (set.size) {
|
||||
// Remove item from set
|
||||
set.delete((index = Array.from(set).shift() as number));
|
||||
} else {
|
||||
// Append new item, unless exceeded storage limit
|
||||
index = getBrowserStorageItemsCount(func);
|
||||
if (
|
||||
index >= browserStorageLimit ||
|
||||
!setBrowserStorageItemsCount(func, index + 1)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Create and save item
|
||||
const item: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider: storage.provider,
|
||||
data,
|
||||
};
|
||||
|
||||
return setStoredItem(
|
||||
func,
|
||||
browserCachePrefix + index.toString(),
|
||||
JSON.stringify(item)
|
||||
);
|
||||
}
|
||||
|
||||
// Update lastModified
|
||||
if (data.lastModified && !updateLastModified(storage, data.lastModified)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Do not store empty sets
|
||||
if (!Object.keys(data.icons).length) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove not_found (clone object to keep old object intact)
|
||||
if (data.not_found) {
|
||||
data = Object.assign({}, data);
|
||||
delete data.not_found;
|
||||
}
|
||||
|
||||
// Attempt to store at localStorage first, then at sessionStorage
|
||||
if (!store('local')) {
|
||||
store('session');
|
||||
}
|
||||
}
|
@ -1,30 +1,6 @@
|
||||
import type { IconifyJSON } from '@iconify/types';
|
||||
import type { IconStorage } from '../storage/storage';
|
||||
|
||||
// Storage types
|
||||
export type BrowserStorageType = 'local' | 'session';
|
||||
|
||||
// localStorage
|
||||
export type BrowserStorageInstance = typeof localStorage;
|
||||
|
||||
// Config
|
||||
export type BrowserStorageConfig = Record<BrowserStorageType, boolean>;
|
||||
|
||||
// List of empty items, for re-use
|
||||
export type BrowserStorageEmptyList = Record<BrowserStorageType, Set<number>>;
|
||||
|
||||
// Stored item
|
||||
export interface BrowserStorageItem {
|
||||
cached: number;
|
||||
provider: string;
|
||||
data: IconifyJSON;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add custom stuff to storage
|
||||
* Storage types
|
||||
*
|
||||
* @deprecated This type is not used anymore
|
||||
*/
|
||||
export interface IconStorageWithCache extends IconStorage {
|
||||
// Last modified from browser cache, minimum of available values
|
||||
// If not set, but icons are cached, value is -1
|
||||
lastModifiedCached?: number;
|
||||
}
|
||||
export type BrowserStorageType = 'local' | 'session';
|
||||
|
217
packages/core/tests/cache/basic-test.ts
vendored
217
packages/core/tests/cache/basic-test.ts
vendored
@ -1,217 +0,0 @@
|
||||
import { initBrowserStorage } from '../../lib/browser-storage';
|
||||
import { browserStorageConfig } from '../../lib/browser-storage/data';
|
||||
import {
|
||||
browserCacheCountKey,
|
||||
browserCachePrefix,
|
||||
browserCacheVersion,
|
||||
browserCacheVersionKey,
|
||||
} from '../../lib/browser-storage/config';
|
||||
import { getBrowserStorageItemsCount } from '../../lib/browser-storage/count';
|
||||
import { getBrowserStorage } from '../../lib/browser-storage/global';
|
||||
import { nextPrefix, createCache, reset } from '../../lib/browser-storage/mock';
|
||||
|
||||
describe('Testing mocked localStorage', () => {
|
||||
const provider = '';
|
||||
|
||||
it('No usable cache', () => {
|
||||
reset({});
|
||||
|
||||
// Config before tests
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: true,
|
||||
});
|
||||
|
||||
// No storage available
|
||||
expect(getBrowserStorage('local')).toBeUndefined();
|
||||
expect(getBrowserStorage('session')).toBeUndefined();
|
||||
|
||||
// Attempt to load
|
||||
initBrowserStorage();
|
||||
|
||||
// Everything should be disabled
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: false,
|
||||
session: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('Empty localStorage', () => {
|
||||
reset({
|
||||
localStorage: createCache(),
|
||||
});
|
||||
|
||||
// Config before tests
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: true,
|
||||
});
|
||||
|
||||
// Only locaStorage should be available
|
||||
expect(getBrowserStorage('local')).toBeDefined();
|
||||
expect(getBrowserStorage('session')).toBeUndefined();
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
0
|
||||
);
|
||||
|
||||
// Attempt to load
|
||||
initBrowserStorage();
|
||||
|
||||
// sessionStorage should be disabled
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: false,
|
||||
});
|
||||
|
||||
// Nothing should have loaded
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
0
|
||||
);
|
||||
});
|
||||
|
||||
it('Restricted localStorage', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
|
||||
// Add one item
|
||||
cache.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
cache.setItem(browserCacheCountKey, '1');
|
||||
cache.setItem(
|
||||
browserCachePrefix + '0',
|
||||
JSON.stringify({
|
||||
cached: Date.now(),
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
foo: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
// Prevent reading and writing
|
||||
cache.canRead = false;
|
||||
cache.canWrite = false;
|
||||
|
||||
// Set cache and test it
|
||||
reset({
|
||||
localStorage: cache,
|
||||
sessionStorage: cache,
|
||||
});
|
||||
|
||||
// Config before tests
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: true,
|
||||
});
|
||||
|
||||
// Storage should not be available
|
||||
expect(getBrowserStorage('local')).toBeUndefined();
|
||||
expect(getBrowserStorage('session')).toBeUndefined();
|
||||
|
||||
// Attempt to load
|
||||
initBrowserStorage();
|
||||
|
||||
// Everything should be disabled because read-only mock throws errors
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: false,
|
||||
session: false,
|
||||
});
|
||||
});
|
||||
|
||||
it('localStorage with one item', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
|
||||
// Add one icon set
|
||||
cache.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
cache.setItem(browserCacheCountKey, '1');
|
||||
cache.setItem(
|
||||
browserCachePrefix + '0',
|
||||
JSON.stringify({
|
||||
cached: Date.now(),
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
foo: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
|
||||
// Set cache and test it
|
||||
reset({
|
||||
localStorage: cache,
|
||||
});
|
||||
|
||||
// Config before tests
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: true,
|
||||
});
|
||||
|
||||
// localStorage should be available
|
||||
expect(getBrowserStorage('local')).toBeDefined();
|
||||
expect(getBrowserStorage('session')).toBeUndefined();
|
||||
|
||||
// Attempt to load
|
||||
initBrowserStorage();
|
||||
|
||||
// sessionStorage should be disabled
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: false,
|
||||
});
|
||||
|
||||
// One item should be in localStorage
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
1
|
||||
);
|
||||
});
|
||||
|
||||
it('localStorage and sessionStorage', () => {
|
||||
reset({
|
||||
localStorage: createCache(),
|
||||
sessionStorage: createCache(),
|
||||
});
|
||||
|
||||
// Config before tests
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: true,
|
||||
});
|
||||
|
||||
// Storage should be available
|
||||
expect(getBrowserStorage('local')).toBeDefined();
|
||||
expect(getBrowserStorage('session')).toBeDefined();
|
||||
|
||||
// Storage should be empty
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
0
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('session')!)).toBe(
|
||||
0
|
||||
);
|
||||
|
||||
// Attempt to load
|
||||
initBrowserStorage();
|
||||
|
||||
// Everything should be working
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: true,
|
||||
});
|
||||
});
|
||||
});
|
555
packages/core/tests/cache/loading-test.ts
vendored
555
packages/core/tests/cache/loading-test.ts
vendored
@ -1,555 +0,0 @@
|
||||
import type { IconifyJSON } from '@iconify/types';
|
||||
import type {
|
||||
BrowserStorageItem,
|
||||
IconStorageWithCache,
|
||||
} from '../../lib/browser-storage/types';
|
||||
import { initBrowserStorage } from '../../lib/browser-storage';
|
||||
import {
|
||||
browserStorageConfig,
|
||||
browserStorageEmptyItems,
|
||||
} from '../../lib/browser-storage/data';
|
||||
import { getBrowserStorageItemsCount } from '../../lib/browser-storage/count';
|
||||
import { getBrowserStorage } from '../../lib/browser-storage/global';
|
||||
import { getStorage, iconInStorage } from '../../lib/storage/storage';
|
||||
import { nextPrefix, createCache, reset } from '../../lib/browser-storage/mock';
|
||||
import {
|
||||
browserCacheCountKey,
|
||||
browserCachePrefix,
|
||||
browserCacheVersion,
|
||||
browserCacheVersionKey,
|
||||
browserStorageHour,
|
||||
browserStorageCacheExpiration,
|
||||
} from '../../lib/browser-storage/config';
|
||||
import { getStoredItem } from '../../lib/browser-storage/item';
|
||||
|
||||
describe('Testing loading from localStorage', () => {
|
||||
const provider = '';
|
||||
|
||||
it('Valid icon set', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
const storage = getStorage(provider, prefix) as IconStorageWithCache;
|
||||
|
||||
// Add one icon set
|
||||
cache.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
cache.setItem(browserCacheCountKey, '1');
|
||||
|
||||
const item: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
foo: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
cache.setItem(browserCachePrefix + '0', JSON.stringify(item));
|
||||
|
||||
// Set cache
|
||||
reset({
|
||||
localStorage: cache,
|
||||
});
|
||||
|
||||
// Only locaStorage should be available
|
||||
expect(getBrowserStorage('local')).toBeDefined();
|
||||
expect(getBrowserStorage('session')).toBeUndefined();
|
||||
|
||||
// 1 icon
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
1
|
||||
);
|
||||
|
||||
// Check icon storage
|
||||
expect(iconInStorage(storage, 'foo')).toBe(false);
|
||||
expect(storage.lastModifiedCached).toBeUndefined();
|
||||
|
||||
// Load localStorage
|
||||
initBrowserStorage();
|
||||
|
||||
// Icon should exist now and lastModified should be set
|
||||
expect(iconInStorage(storage, 'foo')).toBe(true);
|
||||
expect(storage.lastModifiedCached).toBe(-1);
|
||||
|
||||
// Check data
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: false,
|
||||
});
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
});
|
||||
|
||||
it('Different provider', () => {
|
||||
const provider = nextPrefix();
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
const storage = getStorage(provider, prefix) as IconStorageWithCache;
|
||||
const defaultStorage = getStorage('', prefix) as IconStorageWithCache;
|
||||
const lastModified = 12345;
|
||||
|
||||
// Add one icon set
|
||||
cache.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
cache.setItem(browserCacheCountKey, '1');
|
||||
|
||||
const item: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
lastModified,
|
||||
icons: {
|
||||
foo: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
cache.setItem(browserCachePrefix + '0', JSON.stringify(item));
|
||||
expect(getStoredItem(cache, browserCachePrefix + '0')).toBeTruthy();
|
||||
|
||||
// Set cache
|
||||
reset({
|
||||
localStorage: cache,
|
||||
});
|
||||
|
||||
// Check icon storage
|
||||
expect(iconInStorage(storage, 'foo')).toBe(false);
|
||||
expect(storage.lastModifiedCached).toBeUndefined();
|
||||
|
||||
// Check default provider
|
||||
expect(iconInStorage(defaultStorage, 'foo')).toBe(false);
|
||||
expect(defaultStorage.lastModifiedCached).toBeUndefined();
|
||||
|
||||
// Load localStorage
|
||||
initBrowserStorage();
|
||||
|
||||
// Icon should exist now
|
||||
expect(iconInStorage(storage, 'foo')).toBe(true);
|
||||
expect(iconInStorage(defaultStorage, 'foo')).toBe(false);
|
||||
|
||||
// Check data
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: false,
|
||||
});
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
|
||||
expect(storage.lastModifiedCached).toBe(lastModified);
|
||||
expect(defaultStorage.lastModifiedCached).toBeUndefined();
|
||||
});
|
||||
|
||||
it('Expired icon set', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
const storage = getStorage(provider, prefix) as IconStorageWithCache;
|
||||
const lastModified = 12345;
|
||||
|
||||
// Add one icon set
|
||||
cache.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
cache.setItem(browserCacheCountKey, '1');
|
||||
|
||||
const item: BrowserStorageItem = {
|
||||
// Expiration date
|
||||
cached:
|
||||
Math.floor(Date.now() / browserStorageHour) -
|
||||
browserStorageCacheExpiration -
|
||||
1,
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
lastModified,
|
||||
icons: {
|
||||
foo: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
cache.setItem(browserCachePrefix + '0', JSON.stringify(item));
|
||||
expect(getStoredItem(cache, browserCachePrefix + '0')).toBeTruthy();
|
||||
|
||||
// Set cache
|
||||
reset({
|
||||
localStorage: cache,
|
||||
});
|
||||
|
||||
// Counter should be 1 before parsing it
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
1
|
||||
);
|
||||
|
||||
// Check icon storage
|
||||
expect(iconInStorage(storage, 'foo')).toBe(false);
|
||||
|
||||
// Load localStorage
|
||||
initBrowserStorage();
|
||||
|
||||
// Icon should not have loaded
|
||||
expect(iconInStorage(storage, 'foo')).toBe(false);
|
||||
expect(storage.lastModifiedCached).toBeUndefined();
|
||||
|
||||
// Check data
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: false,
|
||||
});
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
|
||||
// Counter should have changed to 0
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
0
|
||||
);
|
||||
});
|
||||
|
||||
it('Bad icon set', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
const storage = getStorage(provider, prefix);
|
||||
|
||||
// Add one icon set
|
||||
cache.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
cache.setItem(browserCacheCountKey, '1');
|
||||
cache.setItem(
|
||||
browserCachePrefix + '0',
|
||||
JSON.stringify({
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
foo: {
|
||||
// Missing 'body' property
|
||||
width: 20,
|
||||
},
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
expect(getStoredItem(cache, browserCachePrefix + '0')).toBeTruthy();
|
||||
|
||||
// Set cache
|
||||
reset({
|
||||
localStorage: cache,
|
||||
});
|
||||
|
||||
// Counter should be 1 before parsing it
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
1
|
||||
);
|
||||
|
||||
// Check icon storage
|
||||
expect(iconInStorage(storage, 'foo')).toBe(false);
|
||||
|
||||
// Load localStorage
|
||||
initBrowserStorage();
|
||||
|
||||
// Icon should not have loaded
|
||||
expect(iconInStorage(storage, 'foo')).toBe(false);
|
||||
|
||||
// Check data
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: false,
|
||||
});
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
|
||||
// Counter should have changed to 0
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
0
|
||||
);
|
||||
|
||||
// Item should have been deleted
|
||||
expect(getStoredItem(cache, browserCachePrefix + '0')).toBeFalsy();
|
||||
});
|
||||
|
||||
it('Wrong counter', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
const storage = getStorage(provider, prefix);
|
||||
|
||||
// Add one icon set
|
||||
cache.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
cache.setItem(browserCacheCountKey, '0'); // Should be at least "1"
|
||||
|
||||
const item: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
foo: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
cache.setItem(browserCachePrefix + '0', JSON.stringify(item));
|
||||
|
||||
// Set cache
|
||||
reset({
|
||||
localStorage: cache,
|
||||
});
|
||||
|
||||
// Counter should be 0
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
0
|
||||
);
|
||||
|
||||
// Check icon storage
|
||||
expect(iconInStorage(storage, 'foo')).toBe(false);
|
||||
|
||||
// Load localStorage
|
||||
initBrowserStorage();
|
||||
|
||||
// Icon should not have loaded
|
||||
expect(iconInStorage(storage, 'foo')).toBe(false);
|
||||
|
||||
// Check data
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: false,
|
||||
});
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
});
|
||||
|
||||
it('Missing entries at the end', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
const storage = getStorage(provider, prefix);
|
||||
|
||||
// Add one icon set
|
||||
cache.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
cache.setItem(browserCacheCountKey, '5');
|
||||
|
||||
const item: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
foo: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
cache.setItem(browserCachePrefix + '0', JSON.stringify(item));
|
||||
|
||||
// Set cache
|
||||
reset({
|
||||
localStorage: cache,
|
||||
});
|
||||
|
||||
// Counter should be 5 before validation
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
5
|
||||
);
|
||||
|
||||
// Check icon storage
|
||||
expect(iconInStorage(storage, 'foo')).toBe(false);
|
||||
|
||||
// Load localStorage
|
||||
initBrowserStorage();
|
||||
|
||||
// Icon should exist now
|
||||
expect(iconInStorage(storage, 'foo')).toBe(true);
|
||||
|
||||
// Check data
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: false,
|
||||
});
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
|
||||
// Counter should be 1 after validation
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
1
|
||||
);
|
||||
});
|
||||
|
||||
it('Missing entries', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
const storage = getStorage(provider, prefix);
|
||||
|
||||
// Add two icon sets
|
||||
cache.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
cache.setItem(browserCacheCountKey, '5');
|
||||
|
||||
// Missing: 0, 2, 3
|
||||
const item1: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
foo1: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
const item4: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
foo4: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
cache.setItem(browserCachePrefix + '1', JSON.stringify(item1));
|
||||
cache.setItem(browserCachePrefix + '4', JSON.stringify(item4));
|
||||
|
||||
// Set cache
|
||||
reset({
|
||||
localStorage: cache,
|
||||
});
|
||||
|
||||
// Counter should be 5 before validation
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
5
|
||||
);
|
||||
|
||||
// Check icon storage
|
||||
expect(iconInStorage(storage, 'foo1')).toBe(false);
|
||||
expect(iconInStorage(storage, 'foo4')).toBe(false);
|
||||
|
||||
// Load localStorage
|
||||
initBrowserStorage();
|
||||
|
||||
// Icons should exist now
|
||||
expect(iconInStorage(storage, 'foo1')).toBe(true);
|
||||
expect(iconInStorage(storage, 'foo4')).toBe(true);
|
||||
|
||||
// Check data
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: false,
|
||||
});
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set([3, 2, 0]), // reserse order
|
||||
session: new Set(),
|
||||
});
|
||||
|
||||
// Counter should be 5 after validation
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
5
|
||||
);
|
||||
});
|
||||
|
||||
it('Using both storage options', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache1 = createCache();
|
||||
const cache2 = createCache();
|
||||
const storage = getStorage(provider, prefix);
|
||||
|
||||
// Add few icon sets
|
||||
cache1.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
cache2.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
|
||||
cache1.setItem(browserCacheCountKey, '6');
|
||||
cache2.setItem(browserCacheCountKey, '3');
|
||||
|
||||
// Create 5 items
|
||||
const icons: IconifyJSON[] = [];
|
||||
const items: BrowserStorageItem[] = [];
|
||||
|
||||
for (let i = 0; i < 6; i++) {
|
||||
const icon: IconifyJSON = {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
['foo' + i.toString()]: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
};
|
||||
const item: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
icons.push(icon);
|
||||
items.push(item);
|
||||
}
|
||||
|
||||
// Add items 1,3,5 to localStorage
|
||||
[1, 3, 5].forEach((index) => {
|
||||
cache1.setItem(
|
||||
browserCachePrefix + index.toString(),
|
||||
JSON.stringify(items[index])
|
||||
);
|
||||
});
|
||||
|
||||
// Add items 0 and 2 to sessionStorage
|
||||
[0, 2].forEach((index) => {
|
||||
cache2.setItem(
|
||||
browserCachePrefix + index.toString(),
|
||||
JSON.stringify(items[index])
|
||||
);
|
||||
});
|
||||
|
||||
// Set cache
|
||||
reset({
|
||||
localStorage: cache1,
|
||||
sessionStorage: cache2,
|
||||
});
|
||||
|
||||
// Check icon storage
|
||||
for (let i = 0; i < 6; i++) {
|
||||
expect(iconInStorage(storage, 'foo' + i.toString())).toBe(false);
|
||||
}
|
||||
|
||||
// Load localStorage
|
||||
initBrowserStorage();
|
||||
|
||||
// Icons should exist now, except for number 4
|
||||
for (let i = 0; i < 6; i++) {
|
||||
expect(iconInStorage(storage, 'foo' + i.toString())).toBe(i !== 4);
|
||||
}
|
||||
|
||||
// Check data
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: true,
|
||||
});
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set([4, 2, 0]),
|
||||
session: new Set([1]),
|
||||
});
|
||||
});
|
||||
});
|
881
packages/core/tests/cache/saving-test.ts
vendored
881
packages/core/tests/cache/saving-test.ts
vendored
@ -1,881 +0,0 @@
|
||||
import type { IconifyJSON } from '@iconify/types';
|
||||
import type {
|
||||
BrowserStorageItem,
|
||||
IconStorageWithCache,
|
||||
} from '../../lib/browser-storage/types';
|
||||
import { storeInBrowserStorage } from '../../lib/browser-storage/store';
|
||||
import { initBrowserStorage } from '../../lib/browser-storage';
|
||||
import {
|
||||
browserStorageConfig,
|
||||
browserStorageEmptyItems,
|
||||
} from '../../lib/browser-storage/data';
|
||||
import { getBrowserStorageItemsCount } from '../../lib/browser-storage/count';
|
||||
import { getBrowserStorage } from '../../lib/browser-storage/global';
|
||||
import { getStorage, iconInStorage } from '../../lib/storage/storage';
|
||||
import { nextPrefix, createCache, reset } from '../../lib/browser-storage/mock';
|
||||
import {
|
||||
browserCacheCountKey,
|
||||
browserCachePrefix,
|
||||
browserCacheVersion,
|
||||
browserCacheVersionKey,
|
||||
browserStorageHour,
|
||||
browserStorageCacheExpiration,
|
||||
} from '../../lib/browser-storage/config';
|
||||
|
||||
describe('Testing saving to localStorage', () => {
|
||||
const provider = '';
|
||||
|
||||
it('One icon set', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
const storage = getStorage(provider, prefix) as IconStorageWithCache;
|
||||
|
||||
// Add one icon set
|
||||
const icon: IconifyJSON = {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
foo: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
};
|
||||
const item: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
|
||||
// Set cache
|
||||
reset({
|
||||
localStorage: cache,
|
||||
});
|
||||
|
||||
// Check icon storage
|
||||
expect(iconInStorage(storage, 'foo')).toBe(false);
|
||||
expect(storage.lastModifiedCached).toBeUndefined();
|
||||
|
||||
// Counter should be 0
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
0
|
||||
);
|
||||
|
||||
// Save item
|
||||
storeInBrowserStorage(storage, icon);
|
||||
|
||||
// Storing in cache should not add item to storage
|
||||
expect(iconInStorage(storage, 'foo')).toBe(false);
|
||||
|
||||
// lastModified is missing, so should not have updated
|
||||
expect(storage.lastModifiedCached).toBeUndefined();
|
||||
|
||||
// Check data that should have been updated because storeCache()
|
||||
// should call load function before first execution
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: false,
|
||||
});
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
|
||||
// Check cache
|
||||
expect(cache.getItem(browserCachePrefix + '0')).toBe(
|
||||
JSON.stringify(item)
|
||||
);
|
||||
expect(cache.getItem(browserCacheCountKey)).toBe('1');
|
||||
expect(cache.getItem(browserCacheVersionKey)).toBe(browserCacheVersion);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
1
|
||||
);
|
||||
});
|
||||
|
||||
it('Multiple icon sets', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
const storage = getStorage(provider, prefix) as IconStorageWithCache;
|
||||
const lastModified = 12345;
|
||||
|
||||
// Add icon sets
|
||||
const icon0: IconifyJSON = {
|
||||
prefix: prefix,
|
||||
lastModified,
|
||||
icons: {
|
||||
foo0: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
};
|
||||
const item0: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: icon0,
|
||||
};
|
||||
const icon1: IconifyJSON = {
|
||||
prefix: prefix,
|
||||
lastModified,
|
||||
icons: {
|
||||
foo: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
};
|
||||
const item1: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: icon1,
|
||||
};
|
||||
|
||||
// Set cache
|
||||
reset({
|
||||
localStorage: cache,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
0
|
||||
);
|
||||
expect(storage.lastModifiedCached).toBeUndefined();
|
||||
|
||||
// Save items
|
||||
storeInBrowserStorage(storage, icon0);
|
||||
storeInBrowserStorage(storage, icon1);
|
||||
|
||||
// Check data that should have been updated because storeCache()
|
||||
// should call load function before first execution
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: false,
|
||||
});
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
|
||||
// lastModified should be set
|
||||
expect(storage.lastModifiedCached).toBe(lastModified);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
2
|
||||
);
|
||||
|
||||
// Check cache
|
||||
expect(cache.getItem(browserCachePrefix + '0')).toBe(
|
||||
JSON.stringify(item0)
|
||||
);
|
||||
expect(cache.getItem(browserCachePrefix + '1')).toBe(
|
||||
JSON.stringify(item1)
|
||||
);
|
||||
expect(cache.getItem(browserCacheCountKey)).toBe('2');
|
||||
expect(cache.getItem(browserCacheVersionKey)).toBe(browserCacheVersion);
|
||||
});
|
||||
|
||||
it('Multiple icon sets, first is outdated', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
const storage = getStorage(provider, prefix) as IconStorageWithCache;
|
||||
const lastModified1 = 1234;
|
||||
const lastModified2 = 12345;
|
||||
|
||||
// Add icon sets
|
||||
const icon0: IconifyJSON = {
|
||||
prefix: prefix,
|
||||
lastModified: lastModified1,
|
||||
icons: {
|
||||
foo0: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// lastModified is newer than first entry: first entry should be deleted
|
||||
const icon1: IconifyJSON = {
|
||||
prefix: prefix,
|
||||
lastModified: lastModified2,
|
||||
icons: {
|
||||
foo: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
};
|
||||
const item1: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: icon1,
|
||||
};
|
||||
|
||||
// Set cache
|
||||
reset({
|
||||
localStorage: cache,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
0
|
||||
);
|
||||
expect(storage.lastModifiedCached).toBeUndefined();
|
||||
|
||||
// Save items
|
||||
storeInBrowserStorage(storage, icon0);
|
||||
storeInBrowserStorage(storage, icon1);
|
||||
|
||||
// Check data that should have been updated because storeCache()
|
||||
// should call load function before first execution
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: false,
|
||||
});
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
|
||||
// lastModified should be set to max value
|
||||
expect(storage.lastModifiedCached).toBe(lastModified2);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
1
|
||||
);
|
||||
|
||||
// Check cache
|
||||
expect(cache.getItem(browserCachePrefix + '0')).toBe(
|
||||
// Second item!
|
||||
JSON.stringify(item1)
|
||||
);
|
||||
expect(cache.getItem(browserCachePrefix + '1')).toBeFalsy();
|
||||
expect(cache.getItem(browserCacheCountKey)).toBe('1');
|
||||
expect(cache.getItem(browserCacheVersionKey)).toBe(browserCacheVersion);
|
||||
});
|
||||
|
||||
it('Multiple icon sets, second set is outdated', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
const storage = getStorage(provider, prefix) as IconStorageWithCache;
|
||||
const lastModified1 = 12345;
|
||||
const lastModified2 = 1234;
|
||||
|
||||
// Add icon sets
|
||||
const icon0: IconifyJSON = {
|
||||
prefix: prefix,
|
||||
lastModified: lastModified1,
|
||||
icons: {
|
||||
foo0: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
};
|
||||
const item0: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: icon0,
|
||||
};
|
||||
|
||||
// Icon set with lastModified lower than previous entry should not be stored
|
||||
const icon1: IconifyJSON = {
|
||||
prefix: prefix,
|
||||
lastModified: lastModified2,
|
||||
icons: {
|
||||
foo: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
// Set cache
|
||||
reset({
|
||||
localStorage: cache,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
0
|
||||
);
|
||||
expect(storage.lastModifiedCached).toBeUndefined();
|
||||
|
||||
// Save items
|
||||
storeInBrowserStorage(storage, icon0);
|
||||
storeInBrowserStorage(storage, icon1);
|
||||
|
||||
// Check data that should have been updated because storeCache()
|
||||
// should call load function before first execution
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: false,
|
||||
});
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
|
||||
// lastModified should be set to maximum value
|
||||
expect(storage.lastModifiedCached).toBe(lastModified1);
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
1
|
||||
);
|
||||
|
||||
// Check cache
|
||||
expect(cache.getItem(browserCachePrefix + '0')).toBe(
|
||||
JSON.stringify(item0)
|
||||
);
|
||||
expect(cache.getItem(browserCachePrefix + '1')).toBeFalsy();
|
||||
expect(cache.getItem(browserCacheCountKey)).toBe('1');
|
||||
expect(cache.getItem(browserCacheVersionKey)).toBe(browserCacheVersion);
|
||||
});
|
||||
|
||||
it('Adding icon set on unused spot', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
const storage = getStorage(provider, prefix);
|
||||
|
||||
// Add icon sets
|
||||
const icon0: IconifyJSON = {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
foo0: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
};
|
||||
const item0: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: icon0,
|
||||
};
|
||||
const icon1: IconifyJSON = {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
foo: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
};
|
||||
const item1: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: icon1,
|
||||
};
|
||||
|
||||
// Add item
|
||||
cache.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
cache.setItem(browserCacheCountKey, '2');
|
||||
cache.setItem(browserCachePrefix + '1', JSON.stringify(item1));
|
||||
|
||||
// Set cache
|
||||
reset({
|
||||
localStorage: cache,
|
||||
});
|
||||
|
||||
// Load data
|
||||
initBrowserStorage();
|
||||
|
||||
// Check data
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: false,
|
||||
});
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set([0]),
|
||||
session: new Set(),
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
2
|
||||
);
|
||||
|
||||
// Save items
|
||||
storeInBrowserStorage(storage, icon0);
|
||||
|
||||
// Check data
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
2
|
||||
);
|
||||
|
||||
// Check cache
|
||||
expect(cache.getItem(browserCachePrefix + '0')).toBe(
|
||||
JSON.stringify(item0)
|
||||
);
|
||||
expect(cache.getItem(browserCachePrefix + '1')).toBe(
|
||||
JSON.stringify(item1)
|
||||
);
|
||||
expect(cache.getItem(browserCacheCountKey)).toBe('2');
|
||||
expect(cache.getItem(browserCacheVersionKey)).toBe(browserCacheVersion);
|
||||
});
|
||||
|
||||
it('Adding multiple icon sets to existing data', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
const storage = getStorage(provider, prefix);
|
||||
|
||||
// Add icon sets
|
||||
const icons: IconifyJSON[] = [];
|
||||
const items: BrowserStorageItem[] = [];
|
||||
for (let i = 0; i < 12; i++) {
|
||||
const icon: IconifyJSON = {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
['foo' + i.toString()]: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
};
|
||||
const item: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
|
||||
// Make items 2 and 4 expire
|
||||
if (i === 2 || i === 4) {
|
||||
item.cached -= browserStorageCacheExpiration + 1;
|
||||
}
|
||||
|
||||
// Change expiration for items 6 and 8 to almost expire
|
||||
if (i === 6 || i === 8) {
|
||||
item.cached -= browserStorageCacheExpiration - 1;
|
||||
}
|
||||
|
||||
icons.push(icon);
|
||||
items.push(item);
|
||||
|
||||
// Skip items 1, 5, 9+
|
||||
if (i !== 1 && i !== 5 && i < 9) {
|
||||
cache.setItem(
|
||||
browserCachePrefix + i.toString(),
|
||||
JSON.stringify(item)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
cache.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
cache.setItem(browserCacheCountKey, '10');
|
||||
|
||||
// Set cache
|
||||
reset({
|
||||
sessionStorage: cache,
|
||||
});
|
||||
|
||||
// Load data
|
||||
initBrowserStorage();
|
||||
|
||||
// Check data
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: false,
|
||||
session: true,
|
||||
});
|
||||
|
||||
// Counter should have changed to 9 after validation because last item is missing
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('session')!)).toBe(
|
||||
9
|
||||
);
|
||||
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
// mix of expired and skipped items
|
||||
// reverse order, 9 should not be there because it is last item
|
||||
session: new Set([5, 4, 2, 1]),
|
||||
});
|
||||
expect(cache.getItem(browserCacheCountKey)).toBe('9');
|
||||
|
||||
// Check cached items
|
||||
[0, 3, 6, 7, 8].forEach((index) => {
|
||||
expect(cache.getItem(browserCachePrefix + index.toString())).toBe(
|
||||
JSON.stringify(items[index])
|
||||
);
|
||||
});
|
||||
|
||||
// Check expired items - should have been deleted
|
||||
// Also check items that weren't supposed to be added
|
||||
[2, 4, 1, 5, 9, 10, 11, 12, 13].forEach((index) => {
|
||||
expect(
|
||||
cache.getItem(browserCachePrefix + index.toString())
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
// Add item 5
|
||||
storeInBrowserStorage(storage, icons[5]);
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set([4, 2, 1]),
|
||||
});
|
||||
expect(cache.getItem(browserCacheCountKey)).toBe('9');
|
||||
|
||||
// Add items 4, 2, 1
|
||||
const list = [4, 2, 1];
|
||||
list.slice(0).forEach((index) => {
|
||||
expect(list.shift()).toBe(index);
|
||||
storeInBrowserStorage(storage, icons[index]);
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(list),
|
||||
});
|
||||
expect(cache.getItem(browserCacheCountKey)).toBe('9');
|
||||
});
|
||||
|
||||
// Add item 10
|
||||
storeInBrowserStorage(storage, icons[10]);
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
expect(cache.getItem(browserCacheCountKey)).toBe('10');
|
||||
|
||||
// Add item 11
|
||||
storeInBrowserStorage(storage, icons[11]);
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
expect(cache.getItem(browserCacheCountKey)).toBe('11');
|
||||
});
|
||||
|
||||
it('Overwrite outdated data', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache = createCache();
|
||||
const storage = getStorage(provider, prefix);
|
||||
|
||||
// Add data in old format
|
||||
cache.setItem(browserCacheVersionKey, '1.0.6');
|
||||
cache.setItem(browserCacheCountKey, '3');
|
||||
for (let i = 0; i < 3; i++) {
|
||||
cache.setItem(
|
||||
browserCachePrefix + i.toString(),
|
||||
JSON.stringify({
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
['foo' + i.toString()]: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
// Set cache
|
||||
reset({
|
||||
localStorage: cache,
|
||||
});
|
||||
|
||||
// Check icon storage
|
||||
expect(iconInStorage(storage, 'foo1')).toBe(false);
|
||||
|
||||
// Load cache
|
||||
initBrowserStorage();
|
||||
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: false,
|
||||
});
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
|
||||
// Add one icon set
|
||||
const icon: IconifyJSON = {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
foo: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
};
|
||||
const item: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
|
||||
// Save item
|
||||
storeInBrowserStorage(storage, icon);
|
||||
|
||||
// Storing in cache should not add item to storage
|
||||
expect(iconInStorage(storage, 'foo')).toBe(false);
|
||||
|
||||
// Check data that should have been updated because storeCache()
|
||||
// should call load function before first execution
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: false,
|
||||
});
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
|
||||
// Check cache
|
||||
expect(cache.getItem(browserCachePrefix + '0')).toBe(
|
||||
JSON.stringify(item)
|
||||
);
|
||||
expect(cache.getItem(browserCacheCountKey)).toBe('1');
|
||||
expect(cache.getItem(browserCacheVersionKey)).toBe(browserCacheVersion);
|
||||
});
|
||||
|
||||
it('Using both storage options', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache1 = createCache();
|
||||
const cache2 = createCache();
|
||||
const storage = getStorage(provider, prefix);
|
||||
|
||||
// Add icon sets to localStorage
|
||||
cache1.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
cache1.setItem(browserCacheCountKey, '3');
|
||||
[0, 1, 2].forEach((index) => {
|
||||
const icon: IconifyJSON = {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
['foo' + index.toString()]: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
};
|
||||
const item: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
cache1.setItem(
|
||||
browserCachePrefix + index.toString(),
|
||||
JSON.stringify(item)
|
||||
);
|
||||
});
|
||||
|
||||
// Add icon sets to sessionStorage
|
||||
cache2.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
cache2.setItem(browserCacheCountKey, '4');
|
||||
[0, 1, 2, 3].forEach((index) => {
|
||||
const icon: IconifyJSON = {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
['bar' + index.toString()]: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
};
|
||||
const item: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
cache2.setItem(
|
||||
browserCachePrefix + index.toString(),
|
||||
JSON.stringify(item)
|
||||
);
|
||||
});
|
||||
|
||||
// Set cache
|
||||
reset({
|
||||
localStorage: cache1,
|
||||
sessionStorage: cache2,
|
||||
});
|
||||
|
||||
// Load data
|
||||
initBrowserStorage();
|
||||
|
||||
// Check data
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: true,
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
3
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('session')!)).toBe(
|
||||
4
|
||||
);
|
||||
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
|
||||
// Check icon storage
|
||||
for (let i = 0; i < 3; i++) {
|
||||
expect(iconInStorage(storage, 'foo' + i.toString())).toBe(true);
|
||||
}
|
||||
for (let i = 0; i < 4; i++) {
|
||||
expect(iconInStorage(storage, 'bar' + i.toString())).toBe(true);
|
||||
}
|
||||
|
||||
// Add new item to localStorage
|
||||
const icon: IconifyJSON = {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
'new-icon': {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
};
|
||||
const item: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
storeInBrowserStorage(storage, icon);
|
||||
|
||||
// Check data
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
4 // +1
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('session')!)).toBe(
|
||||
4
|
||||
);
|
||||
|
||||
// Check cache
|
||||
expect(cache1.getItem(browserCachePrefix + '3')).toBe(
|
||||
JSON.stringify(item)
|
||||
);
|
||||
});
|
||||
|
||||
it('Using both storage options, but localStorage is read only', () => {
|
||||
const prefix = nextPrefix();
|
||||
const cache1 = createCache();
|
||||
const cache2 = createCache();
|
||||
const storage = getStorage(provider, prefix);
|
||||
|
||||
// Add icon sets to localStorage
|
||||
cache1.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
cache1.setItem(browserCacheCountKey, '3');
|
||||
[0, 1, 2].forEach((index) => {
|
||||
const icon: IconifyJSON = {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
['foo' + index.toString()]: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
};
|
||||
const item: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
cache1.setItem(
|
||||
browserCachePrefix + index.toString(),
|
||||
JSON.stringify(item)
|
||||
);
|
||||
});
|
||||
|
||||
// Add icon sets to sessionStorage
|
||||
cache2.setItem(browserCacheVersionKey, browserCacheVersion);
|
||||
cache2.setItem(browserCacheCountKey, '4');
|
||||
[0, 1, 2, 3].forEach((index) => {
|
||||
const icon: IconifyJSON = {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
['bar' + index.toString()]: {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
};
|
||||
const item: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
cache2.setItem(
|
||||
browserCachePrefix + index.toString(),
|
||||
JSON.stringify(item)
|
||||
);
|
||||
});
|
||||
|
||||
// Set cache
|
||||
reset({
|
||||
localStorage: cache1,
|
||||
sessionStorage: cache2,
|
||||
});
|
||||
|
||||
// Load data
|
||||
initBrowserStorage();
|
||||
|
||||
// Check data
|
||||
expect(browserStorageConfig).toEqual({
|
||||
local: true,
|
||||
session: true,
|
||||
});
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
3
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('session')!)).toBe(
|
||||
4
|
||||
);
|
||||
|
||||
// Check icon storage
|
||||
for (let i = 0; i < 3; i++) {
|
||||
expect(iconInStorage(storage, 'foo' + i.toString())).toBe(true);
|
||||
}
|
||||
for (let i = 0; i < 4; i++) {
|
||||
expect(iconInStorage(storage, 'bar' + i.toString())).toBe(true);
|
||||
}
|
||||
|
||||
// Set localStorage to read-only
|
||||
cache1.canWrite = false;
|
||||
|
||||
// Add new item to localStorage
|
||||
const icon: IconifyJSON = {
|
||||
prefix: prefix,
|
||||
icons: {
|
||||
'new-icon': {
|
||||
body: '<g></g>',
|
||||
},
|
||||
},
|
||||
};
|
||||
const item: BrowserStorageItem = {
|
||||
cached: Math.floor(Date.now() / browserStorageHour),
|
||||
provider,
|
||||
data: icon,
|
||||
};
|
||||
storeInBrowserStorage(storage, icon);
|
||||
|
||||
// Check data
|
||||
expect(browserStorageEmptyItems).toEqual({
|
||||
local: new Set(),
|
||||
session: new Set(),
|
||||
});
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('local')!)).toBe(
|
||||
3
|
||||
);
|
||||
// eslint-disable-next-line @typescript-eslint/no-non-null-assertion
|
||||
expect(getBrowserStorageItemsCount(getBrowserStorage('session')!)).toBe(
|
||||
5 // +1
|
||||
);
|
||||
|
||||
// Check cache
|
||||
expect(cache2.getItem(browserCachePrefix + '4')).toBe(
|
||||
JSON.stringify(item)
|
||||
);
|
||||
});
|
||||
});
|
Loading…
Reference in New Issue
Block a user