what is the best way to mock window.sessionStorage in jest
Solution 1
Here is the solution only use jestjs
and typescript
, nothing more.
index.ts
:
export function getUserInfo() {
const userInfo = window.sessionStorage.getItem('userInfo');
if (userInfo) {
return JSON.parse(userInfo);
}
return {};
}
index.spec.ts
:
import { getUserInfo } from './';
const localStorageMock = (() => {
let store = {};
return {
getItem(key) {
return store[key] || null;
},
setItem(key, value) {
store[key] = value.toString();
},
removeItem(key) {
delete store[key];
},
clear() {
store = {};
}
};
})();
Object.defineProperty(window, 'sessionStorage', {
value: localStorageMock
});
describe('getUserInfo', () => {
beforeEach(() => {
window.sessionStorage.clear();
jest.restoreAllMocks();
});
it('should get user info from session storage', () => {
const getItemSpy = jest.spyOn(window.sessionStorage, 'getItem');
window.sessionStorage.setItem('userInfo', JSON.stringify({ userId: 1, userEmail: '[email protected]' }));
const actualValue = getUserInfo();
expect(actualValue).toEqual({ userId: 1, userEmail: '[email protected]' });
expect(getItemSpy).toBeCalledWith('userInfo');
});
it('should get empty object if no user info in session storage', () => {
const getItemSpy = jest.spyOn(window.sessionStorage, 'getItem');
const actualValue = getUserInfo();
expect(actualValue).toEqual({});
expect(window.sessionStorage.getItem).toBeCalledWith('userInfo');
expect(getItemSpy).toBeCalledWith('userInfo');
});
});
Unit test result with 100% coverage report:
PASS src/stackoverflow/51566816/index.spec.ts
getUserInfo
✓ should get user info from session storage (6ms)
✓ should get empty object if no user info in session storage (1ms)
----------|----------|----------|----------|----------|-------------------|
File | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s |
----------|----------|----------|----------|----------|-------------------|
All files | 100 | 100 | 100 | 100 | |
index.ts | 100 | 100 | 100 | 100 | |
----------|----------|----------|----------|----------|-------------------|
Test Suites: 1 passed, 1 total
Tests: 2 passed, 2 total
Snapshots: 0 total
Time: 4.548s, estimated 6s
Here is the completed demo: https://github.com/mrdulin/jest-codelab/tree/master/src/stackoverflow/51566816
Solution 2
You probably do not even need a mock. Just use window.sessionStorage
as usual and write your condition based on window.sessionStorage.getItem(...)
result instead of spying window.sessionStorage.setItem
. Simply don't forget to call window.sessionStorage.clear()
in beforeEach
as demonstrated.
From Eric Burel's comment
Solution 3
This works for me along with adding object:
defineProperty(window, 'sessionStorage', {
writable: true,
configurable: true,
value: localStorageMock
}
Related videos on Youtube
LHE
Updated on March 10, 2022Comments
-
LHE about 2 years
Below is a very simple jest unit test and when running it, you will get error like
Cannot spyOn on a primitive value; undefined given
TypeError: Cannot read property 'getItem' of undefined
but according to the last two comments of this post, localStorage and sessionStorage were already added to latest JSDOM and jest. If using jest-localstorage-mock and add it to my jest setupFiles then you will see weird error like
TypeError: object[methodName].mockImplementation is not a function
So my question is what's the best way to mock localStorage/sessionStorage in jest. Thanks
describe('window.sessionStorage', () => { let mockSessionStorage; beforeEach(() => { mockSessionStorage = {}; jest.spyOn(window.sessionStorage, "getItem").mockImplementation(key => { return mockSessionStorage[key]; }); }); describe('getItem-', () => { beforeEach(() => { mockSessionStorage = { foo: 'bar', } }); it('gets string item', () => { const ret = window.sessionStorage.getItem('foo'); expect(ret).toBe('bar'); }); }); });
Below is my jest config
module.exports = { verbose: true, //setupFiles: ["jest-localstorage-mock"], testURL: "http://localhost/" };
-
Saksham over 3 yearsanything to be done to restore the original behavior of session storage at the end? Will this mock be valid only for the current test file and won't leak globally?
-
Eric Burel over 3 yearsYou probably do not even need a mock. Just use
window.sessionStorage
as usual and write your condition based onwindow.sessionStorage.getItem(...)
result instead of spyingwindow.sessionStorage.setItem
. Simply don't forget to callwindow.sessionStorage.clear()
inbeforeEach
as demonstrated. -
Oh Xyz over 3 years@EricBurel This should be a good valid answer.
-
Alan Yong over 2 yearsreturn
ReferenceError: window is not defined