I'm having trouble testing a react component that uses localstorage to save a JWT token and retrieves it for api calls and routing based on authentication.
The component itself works fine, but when i test, i'm getting this error in all the three tests
TypeError: localStorage.getItem is not a function
Here is the code i have written
home.test.js
import React from 'react';
import { shallow, mount } from 'enzyme';
import { expect } from 'chai';
import sinon from 'sinon';
import Home from '../containers/Home.jsx';
describe('<Home />', () => {
beforeAll(() => {
global.localStorage = {
i2x_token: 'someToken',
};
});
it('renders without exploding', () => {
shallow(<Home />);
});
it('renders children when passed in', () => {
const wrapper = shallow(
<Home>
<div className='unique' />
</Home>,
);
expect(wrapper.contains(<div className='unique' />)).to.equal(true);
});
it('calls componentWillMount', () => {
sinon.spy(Home.prototype, 'componentWillMount');
const wrapper = mount(<Home />);
expect(Home.prototype.componentWillMount).to.have.property('callCount', 1);
Home.prototype.componentWillMount.restore();
});
});
home.jsx
import React, { Component } from 'react';
import { browserHistory } from 'react-router';
import Header from '../components/Header.jsx';
import Content from '../components/Content.jsx';
import { API_CONTENT } from '../utils/constants';
import request from '../utils/request';
class Home extends Component {
constructor(props) {
super(props);
this.state = {
content: null,
};
this.logout = this.logout.bind(this);
}
componentWillMount() {
const token = localStorage.getItem('i2x_token');
const requestURL = API_CONTENT;
const requestObj = {
method: 'GET',
headers: new Headers({
Authorization: `JWT ${token}`,
}),
};
request(requestURL, requestObj).then((reply) => {
if (reply.results.length > 0) {
this.setState({ content: reply.results });
} else {
console.log('no reply from API');
}
});
}
logout() {
localStorage.removeItem('i2x_token');
browserHistory.push('/');
}
render() {
const data = this.state.content;
if (data !== null) {
return (
<div className='container'>
<Header logout={ this.logout } />
<Content data={ this.state.content } />
</div>
);
}
return (
<div className='container'>
<Header logout={ this.logout } />
</div>
);
}
}
export default Home;
defineProperty(window, "localStorage", { value: localStorageMock }); This can be used directly in the test file for a specific, or globally. You can mock localStorage globally for React in Jest by adding the above to the setupTests. js file and adding global.
getItem() The getItem() method of the Storage interface, when passed a key name, will return that key's value, or null if the key does not exist, in the given Storage object.
The getItem() method returns value of the specified Storage Object item. The getItem() method belongs to the Storage Object, which can be either a localStorage object or a sessionStorage object.
localStorage
is part of your Browser which is not available in a unit test, you need to mock it. You can mock the necessary methods in the localStorage
object:
home.test.js
beforeAll(() => {
global.localStorage = {
i2x_token: 'someToken',
getItem: function () {
return 'someToken'
}
};
});
....
I recently had the same issue and I resolved it by using the following: "mock-local-storage": "^1.0.4"
. The package can be found here.
This module mocks the localStorage and the sessionStorage for you, which was hustle free for me. The plug in allows you to add middleware to the store such as redux-thunk
and redux-sagas
.
N.B. I am using Mocha to run my tests.
For other frameworks you can use the following configuration
global.window = {}
import localStorage from 'mock-local-storage'
window.localStorage = global.localStorage
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With