用开玩笑酶测试反应路由器 v4

Posted

技术标签:

【中文标题】用开玩笑酶测试反应路由器 v4【英文标题】:Testing react router v4 with jest enzyme 【发布时间】:2018-07-22 04:59:17 【问题描述】:

我正在尝试使用反应路由器 v4 和开玩笑酶进行简单测试。

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/>

【问题讨论】:

【参考方案1】:

为什么在shallow 中调用console.log?我以前从未见过这个... 尝试将&lt;App /&gt; 组件包装在&lt;Route /&gt; 中,并在其中搜索一些标签。 例如。假设你有这个简单的组件:

<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 不应该在浅层。我已经更新了问题并将 包裹在 周围,我收到了一条新的错误消息。我正在使用 react-boiler-plate (/App/tests/index.test.js) @johnwick0831 感谢您的编辑!您能否尝试使用mount 而不是shallow 作为渲染方法?我认为shallow需要用在非常简单的测试中,包含路由的测试并不简单。 使用 mount 引入了许多新问题。要重现该问题,请克隆 react-boiler-plate。在 /app/tests/ 从上面创建测试。您会注意到,如果您使用 mount,它会提供一些关于“找不到所需的 intl 对象。 需要存在于组件祖先中”的错误消息。不太确定问题出在哪里,我希望有人可以克隆该项目并在他们有额外时间的情况下进行此测试... 感谢您的详细回答。我同意这对于单元测试来说似乎过于复杂,并且注入的依赖项太多。您的建议是测试 类,以便给定某些 initialEntries 它路由到正确的组件? @johnwick0831 我认为通过以这种方式设置任务,您不是在尝试测试 类,而是在尝试测试 react 路由器本身的功能:) 在我的实践中,我让路由器负责路由,并使用路由器提供的不同道具(如this.props.match.params)通过模拟此类道具来测试我的组件。【参考方案2】:

不需要所有&lt;MemoryRouter&gt;&lt;Route&gt; 标签的超级简单方法

在您的 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);   
  ); 
);

【讨论】:

回复超晚,但我认为他想确认路由器呈现预期的内容 没有你的代码测试 react-router

以上是关于用开玩笑酶测试反应路由器 v4的主要内容,如果未能解决你的问题,请参考以下文章

在“if”语句中没有调用模拟函数 - 用玩笑和酶反应应用程序测试?

突出显示反应路由器 v4 中的默认链接

使用玩笑的反应单元测试失败

如何使用新的反应路由器钩子测试组件?

如何将上下文 api 与反应路由器 v4 一起使用?

反应路由器 v4 默认页面(未找到页面)