我正在尝试测试跟随组件,该组件基于在几个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
和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
(即使它的字面名称为“ mock-store”)也不会真正调用任何reducer来返回新的“ mock store”状态致电store.dispatch(myAction())
。我可以测试myAction.spec.js
中的状态更改,但是仍然无法模拟HOC在getDerivedStateFromProps
中接收更新后的状态/属性
据我所知,我编写的测试涵盖了两种情况,其中组件加载的初始状态为authenticated=true/false
,并且可以按预期运行,但是当我查看覆盖率结果时,{{1 }}功能未包含在这些测试中。
我将如何编写测试以模拟存储状态下getDerivedStateFromProps
布尔值的变化,并断言authentication
组件收到Authenticated
中的变化(以前是{{1 }})以确保我在测试中涵盖了这一点?