I'm testing a react HOC which checks if there's a token present in localstorage or not. If there is, it redirects the user to the Home component else the user will be redirected to the Login component.
However, i'm getting this strange error in the last test where it tests for calling componentDidMount
SecurityError
at HistoryImpl._sharedPushAndReplaceState (node_modules/jsdom/lib/jsdom/living/window/History-impl.js:87:15)
at HistoryImpl.pushState (node_modules/jsdom/lib/jsdom/living/window/History-impl.js:69:10)
at History.pushState (node_modules/jsdom/lib/jsdom/living/generated/History.js:72:31)
app.test.js
import React from 'react';
import { shallow, mount } from 'enzyme';
import { expect } from 'chai';
import sinon from 'sinon';
import App from '../containers/App.jsx';
describe('<App />', () => {
beforeAll(() => {
global.localStorage = {
i2x_token: 'someToken',
getItem() {
return 'someToken';
}
};
});
it('renders without exploding', () => {
shallow(<App />);
});
it('renders children when passed in', () => {
const wrapper = shallow(
<App>
<div className='unique' />
</App>,
);
expect(wrapper.contains(<div className='unique' />)).to.equal(true);
});
it('calls componentDidMount', () => {
sinon.spy(App.prototype, 'componentDidMount');
const wrapper = mount(<App />);
expect(App.prototype.componentDidMount).to.have.property('callCount', 1);
App.prototype.componentDidMount.restore();
});
});
`
app.jsx
import React, { Component } from 'react';
import { browserHistory } from 'react-router';
class App extends Component {
componentWillMount() {
if (localStorage.i2x_token) {
browserHistory.push('/home');
} else {
browserHistory.push('/');
}
}
render() {
return (
<main>
{React.Children.toArray(this.props.children)}
</main>
);
}
}
App.propTypes = {
children: React.PropTypes.node,
};
export default App;
package.json
"dependencies": {
"express": "^4.15.2",
"react": "^15.4.2",
"react-dom": "^15.4.2",
"react-router": "3.0.0",
"whatwg-fetch": "^2.0.3"
},
"devDependencies": {
"babel-core": "^6.24.1",
"babel-jest": "^19.0.0",
"babel-loader": "^7.0.0",
"babel-polyfill": "^6.23.0",
"babel-preset-es2015": "^6.24.1",
"babel-preset-react": "^6.24.1",
"chai": "^3.5.0",
"cross-env": "^3.1.3",
"css-loader": "^0.28.0",
"enzyme": "^2.8.2",
"eslint": "^3.19.0",
"eslint-config-airbnb": "^14.1.0",
"eslint-plugin-import": "^2.2.0",
"eslint-plugin-jsx-a11y": "^4.0.0",
"eslint-plugin-react": "^6.10.3",
"file-loader": "^0.11.1",
"jest": "^19.0.2",
"moment": "^2.18.1",
"moment-timezone": "^0.5.13",
"node-sass": "^4.5.2",
"react-addons-test-utils": "^15.5.1",
"sass-loader": "^3.2.0",
"sinon": "^2.1.0",
"style-loader": "^0.16.1",
"webpack": "^2.2.1",
"webpack-dev-server": "^2.4.2"
}
The issue linked here leads to a long rabbit hole but I finally found the solution. If you're using jest with jsdom, the fix is to add this to your configuration:
{
// This configures the jsdom document with a URL.
testURL: 'http://localhost',
}
In my case I was using jsdom directly (without jest) and created jsdom like so:
const document = jsdom('', {
url: 'http://localhost/',
});
global.document = document;
@kumar303 thanks so much for sharing, you've saved my sanity ! ;-)
(node:6392) UnhandledPromiseRejectionWarning: SecurityError: Could not parse url argument "../../ListMapView" to pushState against base URL "about:blank".
at HistoryImpl._sharedPushAndReplaceState (D:KD1KrossDeliveryWebAppnode_modulesjsdomlibjsdomlivingwindowHistory-impl.js:73:15)
at HistoryImpl.pushState (D:KD1KrossDeliveryWebAppnode_modulesjsdomlibjsdomlivingwindowHistory-impl.js:54:10)
at History.pushState (D:KD1KrossDeliveryWebAppnode_modulesjsdomlibjsdomlivinggeneratedHistory.js:88:21)
at D:KD1KrossDeliveryWebAppnode_moduleshistorycreateBrowserHistory.js:175:23
at Object.confirmTransitionTo (D:KD1KrossDeliveryWebAppnode_moduleshistorycreateTransitionManager.js:44:7)
at Object.push (D:KD1KrossDeliveryWebAppnode_moduleshistorycreateBrowserHistory.js:166:23)
at D:KD1KrossDeliveryWebAppsrcscenesaccountloginlogin.Container.js:149:50
at
import { connect } from 'react-redux';
import { withRouter } from 'react-router-dom';
export default withRouter(connect(mapStateToProps, mapDispatchToProps)(Login));
`
if (this.props.user && this.props.user.userRole !== "" && this.props.user.loggedIn) {
let url = loginUrl;
Api.Get(url, this).then((responseData) => {
if (responseData.success) {
if (this.props.user.userRole === Constants.Admin) {
this.props.history.push("../Notifications");
} else if (responseData.status === "Confirmation Pending") {
this.props.history.push("../../Verification");
} else if (this.props.user.userRole === Constants.CUSTOMER) {
this.props.history.push("../../Customer/CustomerLanding");
}else if (this.props.user.partyRoleId > 0) {
this.props.history.push("../../ListMapView");
}
}
});
}
`
I was missing to mention tesst url in package.json file
"jest": {
"testURL" : "http://localhost"
},
Most helpful comment
The issue linked here leads to a long rabbit hole but I finally found the solution. If you're using
jestwithjsdom, the fix is to add this to your configuration: