使用Jest Enzyme测试React Router v4

6

我正在尝试使用React Router v4和Jest Enzyme进行简单的测试。

describe('<App />', () => {

  it('renders a static text', () => {

    const wrapper = shallow(
    <MemoryRouter initialEntries={['/']} initialIndex={0}>
      <App/>
    </MemoryRouter>

    console.log(wrapper.html());
  );

  });
});

当我尝试console.log(wrapper.html())时,会得到以下结果:
Invariant Violation: [React Intl] Could not find required `intl` object. <IntlProvider> needs to exist in the component ancestry.

我正在使用 react-boiler-plate 项目。我只想测试当我给它'/'路径时,主页能否呈现一些文本。
任何帮助都会受到感激!谢谢!
编辑:
这是测试:
it('test', () => {
    const wrapper = shallow(
      <MemoryRouter initialEntries={['/']} initialIndex={0}>
        <Route path="/" render={() => <App/>}/>
      </MemoryRouter>,
    );

    console.log(wrapper.find(App).html());
  });

这是App类:

export default function App() {
  return (
    <AppWrapper>
      <Helmet
        titleTemplate="%s - React.js Boilerplate"
        defaultTitle="React.js Boilerplate"
      >
        <meta name="description" content="A React.js Boilerplate application"/>
      </Helmet>
      <Header/>
      <Switch>
        <Route exact path="/" component={HomePage}/>
        <Route path="/features" component={FeaturePage}/>
        <Route
          path="/catalog"
          render={() => <div>hi</div>}
        />
        <Route path="" component={NotFoundPage}/>
      </Switch>
      <Footer/>
    </AppWrapper>
  );
}

运行测试时出现的错误信息:

**Error: Method “html” is only meant to be run on a single node. 0 found instead.**

我希望这个页面可以匹配,我能够使用console.log输出结果:
<Route exact path="/" component={HomePage}/>
2个回答

5

为什么在shallow内部调用console.log?我以前从未见过这样做... 尝试将您的<App />组件包装在<Route />中,并搜索其中的标签。 例���。假设您有以下简单组件:

<App>
  <h1>Hi there!</h1>
</App>

测试可以像这样:

describe('<App />', () => {

  it('renders a static text', () => {

    const wrapper = shallow(
      <MemoryRouter initialEntries={['/']} initialIndex={0}>
        <Route path="/" render={() => <App />} />
      </MemoryRouter>
    );
    console.log(wrapper.find(App).html());
  });
});

更新 事实上,react-boilerplate 添加了过多的包装和依赖项。因此,为了成功测试,我们需要用不同的方法来克服它们...

以下是我完成的方式(完整内容在react-boilerplate/app/tests/simple.test.js中):

import React from 'react';
import { mount } from 'enzyme';
import { MemoryRouter, Route, browserHistory } from 'react-router-dom';
import { IntlProvider } from 'react-intl';
import { Provider } from 'react-redux';

import configureStore from '../configureStore';
import App from '../containers/App';
import { HomePage } from '../containers/HomePage';

describe('test of initial load', () => {
  it('test', () => {
    const store = configureStore({}, browserHistory);
    const wrapper = mount(
      <MemoryRouter initialEntries={['/']} initialIndex={0}>
        <IntlProvider locale="en"> // to add Intl support
          <Provider store={store} > // to provide store for numeric connected components
            <Route path="/" render={() => <App />} />
          </Provider>
        </IntlProvider>
      </MemoryRouter>
    );
    process.nextTick(() => { // to wait for loadible component will be imported
      console.log(wrapper.find(HomePage).html());
    });
  });
});

我认为这更像是集成测试而不是单元测试... console.log 的输出结果:
    console.log app/tests/simple.test.js:24
  <article><!-- react-empty: 38 --><div><section class="sc-bxivhb jwizic"><h2 class="H2__H2-dhGylN kpbCLA"><span>Start your next react project in seconds</span></h2><p><span>A highly scalable, offline-first foundation with the best DX and a focus on performance and best practices</span></p></section><section class="Section__Section-jEbZoY eivjmS"><h2 class="H2__H2-dhGylN kpbCLA"><span>Try me!</span></h2><form class="Form__Form-PASBS cEpjmP"><label for="username"><span>Show Github repositories by</span><span class="AtPrefix__AtPrefix-ivHByA dZcxpA"><span>@</span></span><input type="text" class="Input__Input-ixjKAz jCPlXI" id="username" placeholder="mxstbr" value=""></label></form><!-- react-empty: 54 --></section></div></article>

抱歉,那是一个打字错误 - console.log 不应该在 shallow 中。我已经更新了问题,并在 <Route> 周围包装了 <App>,然后我得到了一个新的错误消息。我正在使用 react-boiler-plate (/App/tests/index.test.js)。 - johnwick0831
@johnwick0831 谢谢你的编辑!你能否尝试使用mount而不是shallow作为渲染方法?我认为shallow应该只用于非常简单的测试,而包含路由的测试并不简单。 - Andrew Miroshnichenko
使用mount会引入许多新问题。要重现此问题,请克隆react-boiler-plate。并在/app/tests/中创建上述测试。您会注意到,如果使用mount,它将提供一些关于“无法找到所需的intl对象”的错误消息。 <IntlProvider>需要存在于组件祖先中。不太确定问题是什么,希望有人可以克隆该项目并尝试运行此测试,如果他们有多余的时间... - johnwick0831
感谢您详细的回答。我同意这似乎对于单元测试来说过于复杂,并且有太多注入的依赖项。您对如何测试<App>类以便在给定某些initialEntries时它可以路由到正确的组件有什么建议吗? - johnwick0831
让我们在聊天中继续这个讨论:http://chat.stackoverflow.com/rooms/165118/discussion-between-andrew-miroshnichenko-and-johnwick0831。 - Andrew Miroshnichenko
显示剩余2条评论

-1

无需使用所有<MemoryRouter><Route>标签即可轻松完成此操作。

在您的App组件中,将export添加到您的类上。

export class App extends Component {
  render() {
    return (
      <div>Hi, there</div>
    );
  }
}

然后在您的spec.js文件中,只需按如下方式导入要测试的组件:

import React from 'react'; 
import {shallow} from 'enzyme'; 
import { App } from './App';

describe ('App component', () => {

  it('renders App', () => {
     const wrapper = shallow(<App optInValue={true} authenticated={true}/>);

     expect(wrapper.length).toEqual(1);   
  }); 
});

3
非常晚的回复,但我认为他想确认路由器是否呈现了预期的内容。 - Leon
1
不要测试你的代码,react-router。 - Alan Yong

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接