unit testing cookie or localstorage code with jest
Imagine - you enter a website and first thing you see is a cookie banner telling you the website is heavily built on cookies and is not able to run without it and you have to accept these cookies… (PS: raoulkramer.de uses no cookies - mouse drop)
You write a Cookie Component, called CookieBanner and in my case it is done in vue.js. The component shall appear when your visitor drives by the first time and will store in a cookie (or maybe localStorage) his choice.
Everything is fine in the browser, then you want to write a unit test, to make this component secure against regressions and wonder "Where is my document.cookie?".
the problem
In unit testing context, you do not have a browser around your components and accessing `window` or `document` will not work. You can not test code that depends on the browser context.
the solution
You need to mock a `document` object, providing a cookie getter and setter function. And your component needs a wrapping access to the document.
ok, what?
In vue.js components can have external properties and own data properties. The CookieBanner shall work standalone and be embeddable everywhere, an external property is unhandy.
In your component you set a `local` data property `document`:
…,
data() {
return {
…,
document: window.document,
…,
};
},
…
In your cookie handling/manipulating you need to add one line:
…,
methods: {
cookieValue(name) {
const { document } = this; // add this line to your existing code
document.cookie…
…
},
cookieExists(name) {
const { document } = this; // add this line to your existing code
…
},
},
…
No other code changes in your component code are needed.
unit test document.cookie mock
In your test file, you need to create a fakeDocumentCookie object, with a cookie interface, like document.cookie has (gist):
// idea from here @see https://stackoverflow.com/questions/6456429/is-it-possible-to-mock-document-cookie-in-javascript
const fakeDocumentCookie = {
cookies: '',
get cookie() {
return this.cookies;
},
set cookie(cookieValue) {
const cookies = this.cookies.split(' ');
const cookieName = cookieValue.split('=').shift();
const cookieNameLength = cookieName.length;
let cookieIndex = -1;
cookies.forEach((value, index) => {
if (`${value.substr(0, cookieNameLength)}=` === `${cookieName}=`) {
cookieIndex = index;
}
});
if (cookieIndex > -1) {
cookies[cookieIndex] = `${cookieValue};`;
} else {
cookies.push(`${cookieValue};`);
}
this.cookies = cookies.join(' ').trim();
},
};
And put this object in your component via setData():
const wrapper = mount(CookieBanner);
wrapper.setData({ document: fakeDocumentCookie });
And now you can unit test your cookie functions and your component too.
and for window.localStorage?
For localStorage you need to wrap your `window` object in your component, and in your test file create a fakeWindowLocalStorage, which you inject into your component via setData() (gist):
const fakeWindowLocalStorage = {
localStorage: {
data: {},
length: 0,
setItem(name, value) {
this.data[name] = value.toString();
this.length = Object.keys(this.data).length;
},
getItem(name) {
return this.data[name];
},
removeItem(name) {
delete this.data[name];
this.length = Object.keys(this.data).length;
},
},
};
And inject this in your component as your window object:
const wrapper = mount(CookieBanner);
wrapper.setData({ window: fakeWindowLocalStorage });
Happy document.cookie / window.localStorage unit-testing.
Article Image from Emily Morter via unsplash and ghost ❤.