我正在尝试测试以下组件,该组件基于几个 React 培训站点上非常常见的“ProtectedRoute”HOC/包装器示例。基本概念是在<Route>
级别包装受保护的组件,以便重定向未经身份验证的用户。
//Authenticated.js
import React from 'react';
import PropTypes from 'prop-types';
import { history } from 'store';
import { bindActionCreators } from 'redux';
import { connect } from 'react-redux';
export default function (Component) {
class Authenticated extends React.Component {
constructor(props){
super(props);
this.state = {
authenticated: props.authenticated
}
}
static getDerivedStateFromProps(props) {
return {
authenticated: props.authenticated
}
}
componentDidMount() {
this._checkAndRedirect();
}
componentDidUpdate() {
this._checkAndRedirect();
}
_checkAndRedirect() {
const { authenticated, redirect } = this.props;
if (!authenticated) {
redirect();
}
}
render() {
return (
<div>
{ this.props.authenticated ? <Component {...this.props} /> : null }
</div>
);
}
}
const mapStoreStateToProps = (store) => {
return {
authenticated: store.auth.authenticated
};
};
const mapDispatchToProps = dispatch => bindActionCreators({
redirect: () => history.push('/')
}, dispatch)
Authenticated.propTypes = {
authenticated: PropTypes.bool,
redirect: PropTypes.func.isRequired
}
return connect(
mapStoreStateToProps,
mapDispatchToProps
)(Authenticated);
}
到目前为止,我已经使用react-test-renderer
and编写了以下测试redux-mock-store
:
//Authenticated.spec.js
import React from 'react';
import { Provider } from 'react-redux';
import { Router, Route } from 'react-router-dom';
import { createMemoryHistory } from "history";
import renderer from 'react-test-renderer';
import mockStore from 'tests/mockStore';
import Authenticated from 'components/common/Authenticated';
import Home from 'components/Home';
describe('Authenticated', () => {
it('displays protected component if authenticated', () => {
const AuthenticatedComponent = Authenticated(Home);
const store = mockStore({ auth: { authenticated: true } });
store.dispatch = jest.fn();
const history = createMemoryHistory();
history.push('/admin')
const component = renderer.create(
<Provider store={store}>
<Router history={history} >
<AuthenticatedComponent />
</Router>
</Provider>
);
expect(component.toJSON()).toMatchSnapshot();
expect(history.location.pathname).toBe("/admin");
});
it('redirects to login if not authenticated', () => {
const AuthenticatedComponent = Authenticated(Home);
const store = mockStore({ auth: { authenticated: false } });
store.dispatch = jest.fn();
const history = createMemoryHistory();
const component = renderer.create(
<Provider store={store}>
<Router history={history} >
<AuthenticatedComponent />
</Router>
</Provider>
);
expect(component.toJSON()).toMatchSnapshot();
expect(history.location.pathname).toBe("/");
});
});
这两个测试都运行良好,并按预期通过,但是我现在有兴趣测试以下真实世界场景:
用户当前已登录,authenticated=true
在商店中。一段时间后,他们的 cookie 过期。对于我们的示例,假设我们定期使用服务器检查 auth 的状态,它会触发一些动作来触发,导致商店的新状态导致authenticated=false
.
除非我从未遇到过示例,否则我相当确定redux-mock-store
(即使它的字面意思是“模拟商店”)在您调用store.dispatch(myAction())
. 我能够测试状态变化myAction.spec.js
,但我仍然无法模拟接收更新状态/道具的 HOCgetDerivedStateFromProps
据我所知,我编写的测试涵盖了组件以authenticated=true/false
初始状态加载并按预期工作的两种情况,但是当我查看覆盖结果时,getDerivedStateFromProps
这些测试并未涵盖该功能。
我将如何编写一个测试来模拟authentication
商店状态中布尔值的变化并断言组件(以前)Authenticated
收到了变化,以确保我在测试中涵盖了这一点?getDerivedStateFromProps
componentWillReceiveProps