1

我正在尝试测试以下组件,该组件基于几个 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-rendererand编写了以下测试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收到了变化,以确保我在测试中涵盖了这一点?getDerivedStateFromPropscomponentWillReceiveProps

4

0 回答 0