使用react-router,如何测试连接的组件?

时间:2018-07-12 13:22:35

标签: unit-testing redux react-router

我正在使用酶和代码进行测试。我正在尝试测试由react-router-dom生成的路由。只要路由是未经修饰的“未连接”路由,我就没有任何问题。但是,如果路由是“已连接”的还原路由,则测试会失败。首先是我的路线组件。

请注意,<PrivateRoute />只是一个HOC,它会在发送路由之前首先检查用户是否被授权。出于测试目的,您可以将它们与react-router-dom中的其他<Route />一样。

const Routes = () => {
  return (
    <Switch>
      <Route exact path='/' component={WelcomeScreen} />
      <Route path='/auth' component={Authorize} />
      <PrivateRoute path='/text_editor' component={TextEditor} />
      <PrivateRoute path='/files' component={FileSearch} />
      <Route component={SplashPage} />
    </Switch>
  )
}

这是对我的“未经修饰”路线之一的测试。 该测试顺利通过

 it('should direct to the home page', () => {
    const wrapper = mount(
      <MemoryRouter initialEntries={['/']}>
        <Routes />
      </MemoryRouter>
    )
    expect(wrapper.find('WelcomeScreen')).to.have.length(1);
  })

但是,当我在连接的路由上运行相同的测试时......

it('should direct to the authorized page', () => {
    const wrapper = mount(
      <MemoryRouter initialEntries={['/auth']}>
        <Routes />
      </MemoryRouter>
    )
    expect(wrapper.find('Connect(Authorized')).to.have.length(1);
  })

测试因错误而爆炸:

  

永久违反:在上下文或以下环境中均找不到“存储”   “连接(授权)”的道具。可以将根组件包装在   ,或显式传递“ store”作为道具   “连接(授权)”。

因此,我重构了测试,以使用redux-mock-store包括一个模拟商店...

 it('should direct to the authorize page', () => {
    const mockStore = configureStore()
    const store = mockStore({ state: '' })

    const component = mount(
      <Provider store={store}>
        <MemoryRouter initialEntries={['/auth']}>
          <Routes />
        </MemoryRouter>
      </Provider>
    )

    expect(component.find('Connect(Authorize)')).to.have.length(1);
  })

但是现在我的错误信息是:

  

TypeError:无法将对象转换为原始值

我现在不知如何将商店传递给连接的组件以测试其存在?是否有人对测试连通路线的最佳方法有任何想法?

1 个答案:

答案 0 :(得分:2)

酶的支架进行完整渲染。它比浅层要慢得多,并且除了组件本身之外,还会渲染任何子级。如您所知,完整渲染还要求为组件可能需要的所有内容提供模拟。  这样调用mount最终比单元测试更接近端到端测试。

单元测试实际上是关于测试特定于该组件的内容。在这种情况下,您只需要测试您是否已正确配置Route元素。任何子组件都有自己的测试,应该在它们来自的库中测试Switch和Route。

这是我如何对类似组件进行单元测试的一个示例:

// users.js
import * as React from 'react';
import { Route, Switch } from 'react-router-dom';

import EditUser from './editUser';
import UserList from './userList';

export default function Users() {
  return (
    <Switch>
      <Route exact={true} path="/users" component={UserList}/>
      <Route exact={true} path="/users/createuser" component={EditUser}/>
      <Route path="/users/:id" component={EditUser}/>
    </Switch>
  );
}


// users.test.js
import { shallow } from 'enzyme';
import * as React from 'react';

import EditUser from './editUser';
import UserList from './userList';
import Users from './users';

describe("Users", () => {

  describe('component', () => {

    let element;

    beforeEach(() => {
      element = <Users />
    });

    it('renders as expected', () => {
      const component = shallow(element);
      expect(component).toMatchSnapshot();
    });

    it('routes /users to UserList', () => {
      const component = shallow(element);
      expect(component.find('Route[exact=true][path="/users"]').first().prop('component')).toBe(UserList);
    });

    it('routes /users/createuser to EditUser', () => {
      const component = shallow(element);
      expect(component.find('Route[exact=true][path="/users/createuser"]').first().prop('component')).toBe(EditUser);
    });

    it('routes /users/:id to EditUser', () => {
      const component = shallow(element);
      expect(component.find('Route[path="/users/:id"]').first().prop('component')).toBe(EditUser);
    });

  });

});

像这样的单元测试仅针对组件本身,使您的测试保持隔离,针对性和快速。您可以确保在端到端测试中所有内容都融合在一起并正常运行。