Skip to content
This repository has been archived by the owner on Oct 15, 2023. It is now read-only.

Commit

Permalink
Refacto Jest tests for the cache-manager
Browse files Browse the repository at this point in the history
  • Loading branch information
yoriiis committed Apr 3, 2020
1 parent 6d70d28 commit 94cc8b4
Show file tree
Hide file tree
Showing 4 changed files with 204 additions and 15 deletions.
23 changes: 23 additions & 0 deletions src/__mocks__/mocks.js
Original file line number Diff line number Diff line change
Expand Up @@ -41,3 +41,26 @@ export function mockCacheManager (manager, { getDatasFromCache = true } = {}) {
setDatasToCache: jest.fn()
};
}

/**
* Mock implementation of Browser storage
*
* @return {Object} Object implementation of browser storage
*/
export function mockStorage () {
let store = {};
return {
getItem (key) {
return store[key] || null;
},
setItem (key, value) {
store[key] = value.toString();
},
removeItem (key) {
delete store[key];
},
clear () {
store = {};
}
};
}
155 changes: 155 additions & 0 deletions src/__tests__/cache-manager.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
import CacheManager from '../cache-manager';
import { mockStorage } from '../__mocks__/mocks';

let cacheManager;

const getOptions = () => {
return {
cacheMethod: 'localStorage',
keyBrowserStorage: 'cache'
};
};
const cacheMethod = getOptions().cacheMethod;
const keyBrowserStorage = getOptions().keyBrowserStorage;
const datas = { people: true, planet: false, species: true };

const getInstance = () => {
return new CacheManager(getOptions());
};

beforeEach(() => {
Object.defineProperty(window, cacheMethod, {
value: mockStorage()
});

cacheManager = getInstance();
});

afterEach(() => {
window[cacheMethod].removeItem(keyBrowserStorage);
});

describe('CacheManager constructor', () => {
it('Should initialize the constructor', () => {
expect(cacheManager.options).toEqual({
cacheMethod: 'localStorage',
keyBrowserStorage: 'cache'
});
});

it('Should initialize the constructor without options', () => {
const instance = new CacheManager();

expect(instance.options).toEqual({
cacheMethod: 'sessionStorage',
keyBrowserStorage: 'stepManager'
});
});
});

describe('CacheManager getDatasFromCache', () => {
it('Should call the getDatasFromCache function with datas in cache', () => {
window[cacheMethod].setItem(keyBrowserStorage, JSON.stringify(datas));

jest.spyOn(window[cacheMethod], 'getItem');

const result = cacheManager.getDatasFromCache();

expect(window[cacheMethod].getItem).toHaveBeenCalledWith(
cacheManager.options.keyBrowserStorage
);
expect(result).toEqual(datas);
});

it('Should call the getDatasFromCache function without datas in cache', () => {
jest.spyOn(window[cacheMethod], 'getItem');

const result = cacheManager.getDatasFromCache();

expect(result).toEqual(null);
});

it('Should call the getDatasFromCache function with filters and datas in cache', () => {
const filters = ['people'];
window[cacheMethod].setItem(keyBrowserStorage, JSON.stringify(datas));

jest.spyOn(window[cacheMethod], 'getItem');

// Render the first item corresponding to filters array
// to not rewrite the function filterDatas inside the test
cacheManager.filterDatas = jest.fn().mockImplementation(() => datas[filters[0]]);

const result = cacheManager.getDatasFromCache(filters);

expect(cacheManager.filterDatas).toHaveBeenCalledWith(filters, datas);
expect(result).toEqual(true);
});
});

describe('CacheManager filterDatas', () => {
it('Should call the filterDatas function', () => {
expect(cacheManager.filterDatas(['people'], datas)).toEqual({ people: true });
expect(cacheManager.filterDatas(['people', 'species'], datas)).toEqual({
people: true,
species: true
});
expect(cacheManager.filterDatas(['fake'], datas)).toEqual(null);
expect(cacheManager.filterDatas([], datas)).toEqual(null);
});
});

describe('CacheManager setDatasToCache', () => {
it('Should call the setDatasToCache function', () => {
const route = 'people';

cacheManager.getDatasFromCache = jest.fn();
jest.spyOn(window[cacheMethod], 'setItem');

cacheManager.setDatasToCache({ route, datas: datas.people });

expect(cacheManager.getDatasFromCache).toHaveBeenCalled();
expect(window[cacheMethod].setItem).toHaveBeenCalledWith(
cacheManager.options.keyBrowserStorage,
JSON.stringify({
[route]: {
datas: true
}
})
);
});

it('Should call the setDatasToCache function with already datas in cache', () => {
const route = 'planet';
const firstDatas = {
people: {
datas: datas.people
}
};
const result = firstDatas;
result[route] = {
datas: datas[route]
};
window[cacheMethod].setItem(keyBrowserStorage, JSON.stringify(firstDatas));

cacheManager.getDatasFromCache = jest.fn().mockImplementation(() => firstDatas);
jest.spyOn(window[cacheMethod], 'setItem');

cacheManager.setDatasToCache({ route, datas: datas[route] });

expect(cacheManager.getDatasFromCache).toHaveBeenCalled();
expect(window[cacheMethod].setItem).toHaveBeenCalledWith(
cacheManager.options.keyBrowserStorage,
JSON.stringify(result)
);
});
});

describe('CacheManager removeDatasFromCache', () => {
it('Should call the removeDatasFromCache function', () => {
jest.spyOn(window[cacheMethod], 'removeItem');

cacheManager.removeDatasFromCache();

expect(window[cacheMethod].removeItem).toHaveBeenCalledWith(keyBrowserStorage);
});
});
1 change: 0 additions & 1 deletion src/__tests__/router.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,6 @@ beforeEach(() => {
oldURL: 'http://localhost.com/#people'
};
window.sessionStorage.removeItem('stepManager');
document.body.innerHTML = '<div id="steps"></div>';
router = getInstance();
});

Expand Down
40 changes: 26 additions & 14 deletions src/cache-manager.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,30 +26,42 @@ export default class CacheManager {
// Retrieve the data in the cache with the correct key
// Cache key is composed by profile id and a static name
const datas =
window[this.options.cacheMethod].getItem(`${this.options.keyBrowserStorage}`) || null;
window[this.options.cacheMethod].getItem(this.options.keyBrowserStorage) || null;

if (datas !== null) {
// Datas are stringify, parse them
const datasFormatted = JSON.parse(datas);

// Check if datas must be filtered
if (Array.isArray(filters)) {
// Loop on all route filters and extract selected routes datas
filters.forEach(filter => {
if (datasFormatted[filter]) {
if (datasToReturn === null) {
datasToReturn = {};
}
datasToReturn[filter] = datasFormatted[filter];
}
});
} else {
datasToReturn = datasFormatted;
}
datasToReturn = Array.isArray(filters)
? this.filterDatas(filters, datasFormatted)
: datasFormatted;
}
return datasToReturn;
}

/**
* Filter datas from cache by keys
*
* @param {Array} filters Filters list
* @param {Object} datas Datas from browser storage
*
* @returns {Object} Datas filtered by keys
*/
filterDatas (filters, datas) {
let datasToReturn = null;

// Loop on all route filters and extract selected routes datas
const validKeys = Object.keys(datas).filter(key => filters.includes(key));

if (validKeys.length) {
datasToReturn = {};
validKeys.map(key => (datasToReturn[key] = datas[key]));
}

return datasToReturn;
}

/**
* Set step datas to the cache
*
Expand Down

0 comments on commit 94cc8b4

Please sign in to comment.