如何模拟react-router上下文



我有一个相当简单的反应组件(链接包装添加'active'类,如果路由是活动的):

import React, { PropTypes } from 'react';
import { Link } from 'react-router';
const NavLink = (props, context) => {
  const isActive = context.router.isActive(props.to, true);
  const activeClass = isActive ? 'active' : '';
  return (
    <li className={activeClass}>
      <Link {...props}>{props.children}</Link>
    </li>
  );
}
NavLink.contextTypes = {
  router: PropTypes.object,
};
NavLink.propTypes = {
  children: PropTypes.node,
  to: PropTypes.string,
};
export default NavLink;

我该如何测试它?我唯一的尝试是:

import NavLink from '../index';
import expect from 'expect';
import { mount } from 'enzyme';
import React from 'react';
describe('<NavLink />', () => {
  it('should add active class', () => {
    const renderedComponent = mount(<NavLink to="/home" />, { router: { pathname: '/home' } });
    expect(renderedComponent.hasClass('active')).toEqual(true);
  });
});

它不起作用,返回TypeError: Cannot read property 'isActive' of undefined。它肯定需要一些路由器模拟,但我不知道如何编写它。

感谢@Elon Szopos的回答,但我设法写一些更简单的东西(以下https://github.com/airbnb/enzyme/pull/62):

import NavLink from '../index';
import expect from 'expect';
import { shallow } from 'enzyme';
import React from 'react';
describe('<NavLink />', () => {
  it('should add active class', () => {
    const context = { router: { isActive: (a, b) => true } };
    const renderedComponent = shallow(<NavLink to="/home" />, { context });
    expect(renderedComponent.hasClass('active')).toEqual(true);
  });
});

我必须将mount更改为shallow,以便不评估Link,这给了我一个与反应路由器TypeError: router.createHref is not a function连接的错误。

我宁愿有"真正的"反应路由器,而不仅仅是一个对象,但我不知道如何创建它

对于react路由器v4,你可以使用<MemoryRouter>。AVA和Enzyme的例子:

import React from 'react';
import PropTypes from 'prop-types';
import test from 'ava';
import { mount } from 'enzyme';
import sinon from 'sinon';
import { MemoryRouter as Router } from 'react-router-dom';
const mountWithRouter = node => mount(<Router>{node}</Router>);
test('submits form directly', t => {
  const onSubmit = sinon.spy();
  const wrapper = mountWithRouter(<LogInForm onSubmit={onSubmit} />);
  const form = wrapper.find('form');
  form.simulate('submit');
  t.true(onSubmit.calledOnce);
});

测试依赖于上下文的组件可能有点棘手。我所做的是编写一个在测试中使用的包装器。

您可以在下面找到包装器:

import React, { PropTypes } from 'react'
export default class WithContext extends React.Component {
  static propTypes = {
    children: PropTypes.any,
    context: PropTypes.object
  }
  validateChildren () {
    if (this.props.children === undefined) {
      throw new Error('No child components were passed into WithContext')
    }
    if (this.props.children.length > 1) {
      throw new Error('You can only pass one child component into WithContext')
    }
  }
  render () {
    class WithContext extends React.Component {
      getChildContext () {
        return this.props.context
      }
      render () {
        return this.props.children
      }
    }
    const context = this.props.context
    WithContext.childContextTypes = {}
    for (let propertyName in context) {
      WithContext.childContextTypes[propertyName] = PropTypes.any
    }
    this.validateChildren()
    return (
      <WithContext context={this.props.context}>
        {this.props.children}
      </WithContext>
    )
  }
}

下面是一个示例用法:

  <WithContext context={{ location: {pathname: '/Michael/Jackson/lives' }}}>
    <MoonwalkComponent />
  </WithContext>
  <WithContext context={{ router: { isActive: true }}}>
    <YourTestComponent />
  </WithContext>

它应该像你期望的那样工作

可以使用https://github.com/pshrmn/react-router-test-context

"创建一个伪上下文对象来复制React Router的上下文。路由器的结构。这对于使用酵素进行浅层单元测试很有用。"

安装后,您将能够执行如下操作:

describe('my test', () => {
  it('renders', () => {
    const context = createRouterContext()
    const wrapper = shallow(<MyComponent />, { context })
  })
})

相关内容

  • 没有找到相关文章

最新更新