Skip to content
Snippets Groups Projects
Commit bef42d9a authored by Luke "Jared" Bennett's avatar Luke "Jared" Bennett Committed by Phil Hughes
Browse files

Fallback localstorage cases

parent b8153535
No related branches found
No related tags found
No related merge requests found
Showing
with 684 additions and 41 deletions
/* eslint-disable func-names, space-before-function-paren, wrap-iife, no-param-reassign, quotes, prefer-template, no-var, one-var, no-unused-vars, one-var-declaration-per-line, no-void, consistent-return, no-empty, max-len */
import AccessorUtilities from './lib/utils/accessor';
 
window.Autosave = (function() {
function Autosave(field, key) {
this.field = field;
this.isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();
if (key.join != null) {
key = key.join("/");
}
Loading
Loading
@@ -17,16 +20,12 @@ window.Autosave = (function() {
}
 
Autosave.prototype.restore = function() {
var e, text;
if (window.localStorage == null) {
return;
}
try {
text = window.localStorage.getItem(this.key);
} catch (error) {
e = error;
return;
}
var text;
if (!this.isLocalStorageAvailable) return;
text = window.localStorage.getItem(this.key);
if ((text != null ? text.length : void 0) > 0) {
this.field.val(text);
}
Loading
Loading
@@ -35,27 +34,22 @@ window.Autosave = (function() {
 
Autosave.prototype.save = function() {
var text;
if (window.localStorage == null) {
return;
}
text = this.field.val();
if ((text != null ? text.length : void 0) > 0) {
try {
return window.localStorage.setItem(this.key, text);
} catch (error) {}
} else {
return this.reset();
if (this.isLocalStorageAvailable && (text != null ? text.length : void 0) > 0) {
return window.localStorage.setItem(this.key, text);
}
return this.reset();
};
 
Autosave.prototype.reset = function() {
if (window.localStorage == null) {
return;
}
try {
return window.localStorage.removeItem(this.key);
} catch (error) {}
if (!this.isLocalStorageAvailable) return;
return window.localStorage.removeItem(this.key);
};
 
return Autosave;
})();
export default window.Autosave;
import AccessorUtilities from '../../lib/utils/accessor';
const unicodeSupportTestMap = {
// man, student (emojione does not have any of these yet), http://emojipedia.org/emoji-zwj-sequences/
// occupationZwj: '\u{1F468}\u{200D}\u{1F393}',
Loading
Loading
@@ -140,16 +142,25 @@ function generateUnicodeSupportMap(testMap) {
 
function getUnicodeSupportMap() {
let unicodeSupportMap;
const userAgentFromCache = window.localStorage.getItem('gl-emoji-user-agent');
let userAgentFromCache;
const isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();
if (isLocalStorageAvailable) userAgentFromCache = window.localStorage.getItem('gl-emoji-user-agent');
try {
unicodeSupportMap = JSON.parse(window.localStorage.getItem('gl-emoji-unicode-support-map'));
} catch (err) {
// swallow
}
if (!unicodeSupportMap || userAgentFromCache !== navigator.userAgent) {
unicodeSupportMap = generateUnicodeSupportMap(unicodeSupportTestMap);
window.localStorage.setItem('gl-emoji-user-agent', navigator.userAgent);
window.localStorage.setItem('gl-emoji-unicode-support-map', JSON.stringify(unicodeSupportMap));
if (isLocalStorageAvailable) {
window.localStorage.setItem('gl-emoji-user-agent', navigator.userAgent);
window.localStorage.setItem('gl-emoji-unicode-support-map', JSON.stringify(unicodeSupportMap));
}
}
 
return unicodeSupportMap;
Loading
Loading
Loading
Loading
@@ -8,6 +8,11 @@ export default {
type: Array,
required: true,
},
isLocalStorageAvailable: {
type: Boolean,
required: false,
default: true,
},
},
 
computed: {
Loading
Loading
@@ -47,7 +52,12 @@ export default {
 
template: `
<div>
<ul v-if="hasItems">
<div
v-if="!isLocalStorageAvailable"
class="dropdown-info-note">
This feature requires local storage to be enabled
</div>
<ul v-else-if="hasItems">
<li
v-for="(item, index) in processedItems"
:key="index">
Loading
Loading
/* global Flash */
import FilteredSearchContainer from './container';
import RecentSearchesRoot from './recent_searches_root';
import RecentSearchesStore from './stores/recent_searches_store';
Loading
Loading
@@ -15,7 +13,9 @@ class FilteredSearchManager {
this.tokensContainer = this.container.querySelector('.tokens-container');
this.filteredSearchTokenKeys = gl.FilteredSearchTokenKeys;
 
this.recentSearchesStore = new RecentSearchesStore();
this.recentSearchesStore = new RecentSearchesStore({
isLocalStorageAvailable: RecentSearchesService.isAvailable(),
});
let recentSearchesKey = 'issue-recent-searches';
if (page === 'merge_requests') {
recentSearchesKey = 'merge-request-recent-searches';
Loading
Loading
@@ -24,9 +24,10 @@ class FilteredSearchManager {
 
// Fetch recent searches from localStorage
this.fetchingRecentSearchesPromise = this.recentSearchesService.fetch()
.catch(() => {
.catch((error) => {
if (error.name === 'RecentSearchesServiceError') return undefined;
// eslint-disable-next-line no-new
new Flash('An error occured while parsing recent searches');
new window.Flash('An error occured while parsing recent searches');
// Gracefully fail to empty array
return [];
})
Loading
Loading
Loading
Loading
@@ -183,6 +183,9 @@ class FilteredSearchVisualTokens {
 
static moveInputToTheRight() {
const input = FilteredSearchContainer.container.querySelector('.filtered-search');
if (!input) return;
const inputLi = input.parentElement;
const tokenContainer = FilteredSearchContainer.container.querySelector('.tokens-container');
 
Loading
Loading
Loading
Loading
@@ -29,12 +29,15 @@ class RecentSearchesRoot {
}
 
render() {
const state = this.store.state;
this.vm = new Vue({
el: this.wrapperElement,
data: this.store.state,
data() { return state; },
template: `
<recent-searches-dropdown-content
:items="recentSearches" />
:items="recentSearches"
:is-local-storage-available="isLocalStorageAvailable"
/>
`,
components: {
'recent-searches-dropdown-content': RecentSearchesDropdownContent,
Loading
Loading
import RecentSearchesServiceError from './recent_searches_service_error';
import AccessorUtilities from '../../lib/utils/accessor';
class RecentSearchesService {
constructor(localStorageKey = 'issuable-recent-searches') {
this.localStorageKey = localStorageKey;
}
 
fetch() {
if (!RecentSearchesService.isAvailable()) {
const error = new RecentSearchesServiceError();
return Promise.reject(error);
}
const input = window.localStorage.getItem(this.localStorageKey);
 
let searches = [];
Loading
Loading
@@ -19,8 +27,14 @@ class RecentSearchesService {
}
 
save(searches = []) {
if (!RecentSearchesService.isAvailable()) return;
window.localStorage.setItem(this.localStorageKey, JSON.stringify(searches));
}
static isAvailable() {
return AccessorUtilities.isLocalStorageAccessSafe();
}
}
 
export default RecentSearchesService;
class RecentSearchesServiceError {
constructor(message) {
this.name = 'RecentSearchesServiceError';
this.message = message || 'Recent Searches Service is unavailable';
}
}
// Can't use `extends` for builtin prototypes and get true inheritance yet
RecentSearchesServiceError.prototype = Error.prototype;
export default RecentSearchesServiceError;
function isPropertyAccessSafe(base, property) {
let safe;
try {
safe = !!base[property];
} catch (error) {
safe = false;
}
return safe;
}
function isFunctionCallSafe(base, functionName, ...args) {
let safe = true;
try {
base[functionName](...args);
} catch (error) {
safe = false;
}
return safe;
}
function isLocalStorageAccessSafe() {
let safe;
const TEST_KEY = 'isLocalStorageAccessSafe';
const TEST_VALUE = 'true';
safe = isPropertyAccessSafe(window, 'localStorage');
if (!safe) return safe;
safe = isFunctionCallSafe(window.localStorage, 'setItem', TEST_KEY, TEST_VALUE);
if (safe) window.localStorage.removeItem(TEST_KEY);
return safe;
}
const AccessorUtilities = {
isPropertyAccessSafe,
isFunctionCallSafe,
isLocalStorageAccessSafe,
};
export default AccessorUtilities;
/* eslint no-param-reassign: ["error", { "props": false }]*/
/* eslint no-new: "off" */
import AccessorUtilities from './lib/utils/accessor';
((global) => {
/**
* Memorize the last selected tab after reloading a page.
Loading
Loading
@@ -9,6 +11,8 @@
constructor({ currentTabKey = 'current_signin_tab', tabSelector = 'ul.nav-tabs' } = {}) {
this.currentTabKey = currentTabKey;
this.tabSelector = tabSelector;
this.isLocalStorageAvailable = AccessorUtilities.isLocalStorageAccessSafe();
this.bootstrap();
}
 
Loading
Loading
@@ -37,11 +41,15 @@
}
 
saveData(val) {
localStorage.setItem(this.currentTabKey, val);
if (!this.isLocalStorageAvailable) return undefined;
return window.localStorage.setItem(this.currentTabKey, val);
}
 
readData() {
return localStorage.getItem(this.currentTabKey);
if (!this.isLocalStorageAvailable) return null;
return window.localStorage.getItem(this.currentTabKey);
}
}
 
Loading
Loading
import Autosave from '~/autosave';
import AccessorUtilities from '~/lib/utils/accessor';
describe('Autosave', () => {
let autosave;
describe('class constructor', () => {
const key = 'key';
const field = jasmine.createSpyObj('field', ['data', 'on']);
beforeEach(() => {
spyOn(AccessorUtilities, 'isLocalStorageAccessSafe').and.returnValue(true);
spyOn(Autosave.prototype, 'restore');
autosave = new Autosave(field, key);
});
it('should set .isLocalStorageAvailable', () => {
expect(AccessorUtilities.isLocalStorageAccessSafe).toHaveBeenCalled();
expect(autosave.isLocalStorageAvailable).toBe(true);
});
});
describe('restore', () => {
const key = 'key';
const field = jasmine.createSpyObj('field', ['trigger']);
beforeEach(() => {
autosave = {
field,
key,
};
spyOn(window.localStorage, 'getItem');
});
describe('if .isLocalStorageAvailable is `false`', () => {
beforeEach(() => {
autosave.isLocalStorageAvailable = false;
Autosave.prototype.restore.call(autosave);
});
it('should not call .getItem', () => {
expect(window.localStorage.getItem).not.toHaveBeenCalled();
});
});
describe('if .isLocalStorageAvailable is `true`', () => {
beforeEach(() => {
autosave.isLocalStorageAvailable = true;
Autosave.prototype.restore.call(autosave);
});
it('should call .getItem', () => {
expect(window.localStorage.getItem).toHaveBeenCalledWith(key);
});
});
});
describe('save', () => {
const field = jasmine.createSpyObj('field', ['val']);
beforeEach(() => {
autosave = jasmine.createSpyObj('autosave', ['reset']);
autosave.field = field;
field.val.and.returnValue('value');
spyOn(window.localStorage, 'setItem');
});
describe('if .isLocalStorageAvailable is `false`', () => {
beforeEach(() => {
autosave.isLocalStorageAvailable = false;
Autosave.prototype.save.call(autosave);
});
it('should not call .setItem', () => {
expect(window.localStorage.setItem).not.toHaveBeenCalled();
});
});
describe('if .isLocalStorageAvailable is `true`', () => {
beforeEach(() => {
autosave.isLocalStorageAvailable = true;
Autosave.prototype.save.call(autosave);
});
it('should call .setItem', () => {
expect(window.localStorage.setItem).toHaveBeenCalled();
});
});
});
describe('reset', () => {
const key = 'key';
beforeEach(() => {
autosave = {
key,
};
spyOn(window.localStorage, 'removeItem');
});
describe('if .isLocalStorageAvailable is `false`', () => {
beforeEach(() => {
autosave.isLocalStorageAvailable = false;
Autosave.prototype.reset.call(autosave);
});
it('should not call .removeItem', () => {
expect(window.localStorage.removeItem).not.toHaveBeenCalled();
});
});
describe('if .isLocalStorageAvailable is `true`', () => {
beforeEach(() => {
autosave.isLocalStorageAvailable = true;
Autosave.prototype.reset.call(autosave);
});
it('should call .removeItem', () => {
expect(window.localStorage.removeItem).toHaveBeenCalledWith(key);
});
});
});
});
import { getUnicodeSupportMap } from '~/behaviors/gl_emoji/unicode_support_map';
import AccessorUtilities from '~/lib/utils/accessor';
describe('Unicode Support Map', () => {
describe('getUnicodeSupportMap', () => {
const stringSupportMap = 'stringSupportMap';
beforeEach(() => {
spyOn(AccessorUtilities, 'isLocalStorageAccessSafe');
spyOn(window.localStorage, 'getItem');
spyOn(window.localStorage, 'setItem');
spyOn(JSON, 'parse');
spyOn(JSON, 'stringify').and.returnValue(stringSupportMap);
});
describe('if isLocalStorageAvailable is `true`', function () {
beforeEach(() => {
AccessorUtilities.isLocalStorageAccessSafe.and.returnValue(true);
getUnicodeSupportMap();
});
it('should call .getItem and .setItem', () => {
const allArgs = window.localStorage.setItem.calls.allArgs();
expect(window.localStorage.getItem).toHaveBeenCalledWith('gl-emoji-user-agent');
expect(allArgs[0][0]).toBe('gl-emoji-user-agent');
expect(allArgs[0][1]).toBe(navigator.userAgent);
expect(allArgs[1][0]).toBe('gl-emoji-unicode-support-map');
expect(allArgs[1][1]).toBe(stringSupportMap);
});
});
describe('if isLocalStorageAvailable is `false`', function () {
beforeEach(() => {
AccessorUtilities.isLocalStorageAccessSafe.and.returnValue(false);
getUnicodeSupportMap();
});
it('should not call .getItem or .setItem', () => {
expect(window.localStorage.getItem.calls.count()).toBe(1);
expect(window.localStorage.setItem).not.toHaveBeenCalled();
});
});
});
});
Loading
Loading
@@ -76,6 +76,26 @@ describe('RecentSearchesDropdownContent', () => {
});
});
 
describe('if isLocalStorageAvailable is `false`', () => {
let el;
beforeEach(() => {
const props = Object.assign({ isLocalStorageAvailable: false }, propsDataWithItems);
vm = createComponent(props);
el = vm.$el;
});
it('should render an info note', () => {
const note = el.querySelector('.dropdown-info-note');
const items = el.querySelectorAll('.filtered-search-history-dropdown-item');
expect(note).toBeDefined();
expect(note.innerText.trim()).toBe('This feature requires local storage to be enabled');
expect(items.length).toEqual(propsDataWithoutItems.items.length);
});
});
describe('computed', () => {
describe('processedItems', () => {
it('with items', () => {
Loading
Loading
import * as recentSearchesStoreSrc from '~/filtered_search/stores/recent_searches_store';
import RecentSearchesService from '~/filtered_search/services/recent_searches_service';
import RecentSearchesServiceError from '~/filtered_search/services/recent_searches_service_error';
require('~/lib/utils/url_utility');
require('~/lib/utils/common_utils');
require('~/filtered_search/filtered_search_token_keys');
Loading
Loading
@@ -60,6 +64,36 @@ describe('Filtered Search Manager', () => {
manager.cleanup();
});
 
describe('class constructor', () => {
const isLocalStorageAvailable = 'isLocalStorageAvailable';
let filteredSearchManager;
beforeEach(() => {
spyOn(RecentSearchesService, 'isAvailable').and.returnValue(isLocalStorageAvailable);
spyOn(recentSearchesStoreSrc, 'default');
filteredSearchManager = new gl.FilteredSearchManager();
return filteredSearchManager;
});
it('should instantiate RecentSearchesStore with isLocalStorageAvailable', () => {
expect(RecentSearchesService.isAvailable).toHaveBeenCalled();
expect(recentSearchesStoreSrc.default).toHaveBeenCalledWith({
isLocalStorageAvailable,
});
});
it('should not instantiate Flash if an RecentSearchesServiceError is caught', () => {
spyOn(RecentSearchesService.prototype, 'fetch').and.callFake(() => Promise.reject(new RecentSearchesServiceError()));
spyOn(window, 'Flash');
filteredSearchManager = new gl.FilteredSearchManager();
expect(window.Flash).not.toHaveBeenCalled();
});
});
describe('search', () => {
const defaultParams = '?scope=all&utf8=%E2%9C%93&state=opened';
 
Loading
Loading
import RecentSearchesRoot from '~/filtered_search/recent_searches_root';
import * as vueSrc from 'vue';
describe('RecentSearchesRoot', () => {
describe('render', () => {
let recentSearchesRoot;
let data;
let template;
beforeEach(() => {
recentSearchesRoot = {
store: {
state: 'state',
},
};
spyOn(vueSrc, 'default').and.callFake((options) => {
data = options.data;
template = options.template;
});
RecentSearchesRoot.prototype.render.call(recentSearchesRoot);
});
it('should instantiate Vue', () => {
expect(vueSrc.default).toHaveBeenCalled();
expect(data()).toBe(recentSearchesRoot.store.state);
expect(template).toContain(':is-local-storage-available="isLocalStorageAvailable"');
});
});
});
import RecentSearchesServiceError from '~/filtered_search/services/recent_searches_service_error';
describe('RecentSearchesServiceError', () => {
let recentSearchesServiceError;
beforeEach(() => {
recentSearchesServiceError = new RecentSearchesServiceError();
});
it('instantiates an instance of RecentSearchesServiceError and not an Error', () => {
expect(recentSearchesServiceError).toEqual(jasmine.any(RecentSearchesServiceError));
expect(recentSearchesServiceError.name).toBe('RecentSearchesServiceError');
});
it('should set a default message', () => {
expect(recentSearchesServiceError.message).toBe('Recent Searches Service is unavailable');
});
});
/* eslint-disable promise/catch-or-return */
 
import RecentSearchesService from '~/filtered_search/services/recent_searches_service';
import AccessorUtilities from '~/lib/utils/accessor';
 
describe('RecentSearchesService', () => {
let service;
Loading
Loading
@@ -11,6 +12,10 @@ describe('RecentSearchesService', () => {
});
 
describe('fetch', () => {
beforeEach(() => {
spyOn(RecentSearchesService, 'isAvailable').and.returnValue(true);
});
it('should default to empty array', (done) => {
const fetchItemsPromise = service.fetch();
 
Loading
Loading
@@ -29,11 +34,21 @@ describe('RecentSearchesService', () => {
const fetchItemsPromise = service.fetch();
 
fetchItemsPromise
.catch(() => {
.catch((error) => {
expect(error).toEqual(jasmine.any(SyntaxError));
done();
});
});
 
it('should reject when service is unavailable', (done) => {
RecentSearchesService.isAvailable.and.returnValue(false);
service.fetch().catch((error) => {
expect(error).toEqual(jasmine.any(Error));
done();
});
});
it('should return items from localStorage', (done) => {
window.localStorage.setItem(service.localStorageKey, '["foo", "bar"]');
const fetchItemsPromise = service.fetch();
Loading
Loading
@@ -44,15 +59,89 @@ describe('RecentSearchesService', () => {
done();
});
});
describe('if .isAvailable returns `false`', () => {
beforeEach(() => {
RecentSearchesService.isAvailable.and.returnValue(false);
spyOn(window.localStorage, 'getItem');
RecentSearchesService.prototype.fetch();
});
it('should not call .getItem', () => {
expect(window.localStorage.getItem).not.toHaveBeenCalled();
});
});
});
 
describe('setRecentSearches', () => {
beforeEach(() => {
spyOn(RecentSearchesService, 'isAvailable').and.returnValue(true);
});
it('should save things in localStorage', () => {
const items = ['foo', 'bar'];
service.save(items);
const newLocalStorageValue =
window.localStorage.getItem(service.localStorageKey);
const newLocalStorageValue = window.localStorage.getItem(service.localStorageKey);
expect(JSON.parse(newLocalStorageValue)).toEqual(items);
});
});
describe('save', () => {
beforeEach(() => {
spyOn(window.localStorage, 'setItem');
spyOn(RecentSearchesService, 'isAvailable');
});
describe('if .isAvailable returns `true`', () => {
const searchesString = 'searchesString';
const localStorageKey = 'localStorageKey';
const recentSearchesService = {
localStorageKey,
};
beforeEach(() => {
RecentSearchesService.isAvailable.and.returnValue(true);
spyOn(JSON, 'stringify').and.returnValue(searchesString);
RecentSearchesService.prototype.save.call(recentSearchesService);
});
it('should call .setItem', () => {
expect(window.localStorage.setItem).toHaveBeenCalledWith(localStorageKey, searchesString);
});
});
describe('if .isAvailable returns `false`', () => {
beforeEach(() => {
RecentSearchesService.isAvailable.and.returnValue(false);
RecentSearchesService.prototype.save();
});
it('should not call .setItem', () => {
expect(window.localStorage.setItem).not.toHaveBeenCalled();
});
});
});
describe('isAvailable', () => {
let isAvailable;
beforeEach(() => {
spyOn(AccessorUtilities, 'isLocalStorageAccessSafe').and.callThrough();
isAvailable = RecentSearchesService.isAvailable();
});
it('should call .isLocalStorageAccessSafe', () => {
expect(AccessorUtilities.isLocalStorageAccessSafe).toHaveBeenCalled();
});
it('should return a boolean', () => {
expect(typeof isAvailable).toBe('boolean');
});
});
});
import AccessorUtilities from '~/lib/utils/accessor';
describe('AccessorUtilities', () => {
const testError = new Error('test error');
describe('isPropertyAccessSafe', () => {
let base;
it('should return `true` if access is safe', () => {
base = { testProp: 'testProp' };
expect(AccessorUtilities.isPropertyAccessSafe(base, 'testProp')).toBe(true);
});
it('should return `false` if access throws an error', () => {
base = { get testProp() { throw testError; } };
expect(AccessorUtilities.isPropertyAccessSafe(base, 'testProp')).toBe(false);
});
it('should return `false` if property is undefined', () => {
base = {};
expect(AccessorUtilities.isPropertyAccessSafe(base, 'testProp')).toBe(false);
});
});
describe('isFunctionCallSafe', () => {
const base = {};
it('should return `true` if calling is safe', () => {
base.func = () => {};
expect(AccessorUtilities.isFunctionCallSafe(base, 'func')).toBe(true);
});
it('should return `false` if calling throws an error', () => {
base.func = () => { throw new Error('test error'); };
expect(AccessorUtilities.isFunctionCallSafe(base, 'func')).toBe(false);
});
it('should return `false` if function is undefined', () => {
base.func = undefined;
expect(AccessorUtilities.isFunctionCallSafe(base, 'func')).toBe(false);
});
});
describe('isLocalStorageAccessSafe', () => {
beforeEach(() => {
spyOn(window.localStorage, 'setItem');
spyOn(window.localStorage, 'removeItem');
});
it('should return `true` if access is safe', () => {
expect(AccessorUtilities.isLocalStorageAccessSafe()).toBe(true);
});
it('should return `false` if access to .setItem isnt safe', () => {
window.localStorage.setItem.and.callFake(() => { throw testError; });
expect(AccessorUtilities.isLocalStorageAccessSafe()).toBe(false);
});
it('should set a test item if access is safe', () => {
AccessorUtilities.isLocalStorageAccessSafe();
expect(window.localStorage.setItem).toHaveBeenCalledWith('isLocalStorageAccessSafe', 'true');
});
it('should remove the test item if access is safe', () => {
AccessorUtilities.isLocalStorageAccessSafe();
expect(window.localStorage.removeItem).toHaveBeenCalledWith('isLocalStorageAccessSafe');
});
});
});
import AccessorUtilities from '~/lib/utils/accessor';
require('~/signin_tabs_memoizer');
 
((global) => {
Loading
Loading
@@ -19,6 +21,8 @@ require('~/signin_tabs_memoizer');
 
beforeEach(() => {
loadFixtures(fixtureTemplate);
spyOn(AccessorUtilities, 'isLocalStorageAccessSafe').and.returnValue(true);
});
 
it('does nothing if no tab was previously selected', () => {
Loading
Loading
@@ -49,5 +53,91 @@ require('~/signin_tabs_memoizer');
 
expect(memo.readData()).toEqual('#standard');
});
describe('class constructor', () => {
beforeEach(() => {
memo = createMemoizer();
});
it('should set .isLocalStorageAvailable', () => {
expect(AccessorUtilities.isLocalStorageAccessSafe).toHaveBeenCalled();
expect(memo.isLocalStorageAvailable).toBe(true);
});
});
describe('saveData', () => {
beforeEach(() => {
memo = {
currentTabKey,
};
spyOn(localStorage, 'setItem');
});
describe('if .isLocalStorageAvailable is `false`', () => {
beforeEach(function () {
memo.isLocalStorageAvailable = false;
global.ActiveTabMemoizer.prototype.saveData.call(memo);
});
it('should not call .setItem', () => {
expect(localStorage.setItem).not.toHaveBeenCalled();
});
});
describe('if .isLocalStorageAvailable is `true`', () => {
const value = 'value';
beforeEach(function () {
memo.isLocalStorageAvailable = true;
global.ActiveTabMemoizer.prototype.saveData.call(memo, value);
});
it('should call .setItem', () => {
expect(localStorage.setItem).toHaveBeenCalledWith(currentTabKey, value);
});
});
});
describe('readData', () => {
const itemValue = 'itemValue';
let readData;
beforeEach(() => {
memo = {
currentTabKey,
};
spyOn(localStorage, 'getItem').and.returnValue(itemValue);
});
describe('if .isLocalStorageAvailable is `false`', () => {
beforeEach(function () {
memo.isLocalStorageAvailable = false;
readData = global.ActiveTabMemoizer.prototype.readData.call(memo);
});
it('should not call .getItem and should return `null`', () => {
expect(localStorage.getItem).not.toHaveBeenCalled();
expect(readData).toBe(null);
});
});
describe('if .isLocalStorageAvailable is `true`', () => {
beforeEach(function () {
memo.isLocalStorageAvailable = true;
readData = global.ActiveTabMemoizer.prototype.readData.call(memo);
});
it('should call .getItem and return the localStorage value', () => {
expect(window.localStorage.getItem).toHaveBeenCalledWith(currentTabKey);
expect(readData).toBe(itemValue);
});
});
});
});
})(window);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment