2017-06-21 68 views
0

我有行爲分量,我想測試:如何單元測試組件下反應路由器4

import React from 'react'; 
import {connect} from 'react-redux'; 

import {getModules, setModulesFetching} from 'js/actions/modules'; 
import {setModuleSort} from 'js/actions/sort'; 

import Loading from 'js/Components/Loading/Loading'; 
import Module from './Components/ModuleListModule'; 

export class ModulesList extends React.Component { 
    componentDidMount() { 
     this.props.setModulesFetching(true); 
     this.props.getModules(); 
    } 

    renderModuleList() { 
     if (this.props.isFetching) { 
      return <Loading/>; 
     } 

     if (this._isSelected('name')) { 
      this.props.modules.sort((a, b) => this._compareNames(a, b)); 
     } else if (this._isSelected('rating')) { 
      this.props.modules.sort((a, b) => this._compareRatings(a, b)); 
     } 

     return this.props.modules.map((module) => 
      <Module key={module.id} module={module}/> 
     ); 
    } 

    renderSelect() { 
     return (
      <div className="col"> 
       <label htmlFor="search-sortby">Sort By:</label> 
       <select id="search-sortby" onChange={(event) => this.props.setModuleSort(event.target.value)}> 
        <option value="name" selected={this._isSelected('name')}>Name</option> 
        <option value="rating" selected={this._isSelected('rating')}>Rating</option> 
       </select> 
      </div> 
     ); 
    } 

    render() { 
     return (
      <div id="modules-list"> 
       <div className="p-3 row"> 
        {this.renderSelect()} 
        <div id="search-summary"> 
         {this.props.modules.length} Adventures Found 
        </div> 
       </div> 

       {this.renderModuleList()} 
      </div> 
     ); 
    } 
// Other minor methods left out for brevity 
} 

<Module/>子與之交互陣營路由器是造成麻煩:

import React from 'react' 
import {Link} from 'react-router-dom' 

import ModuleStarRating from 'js/Components/ModuleRating/ModuleStarRating' 

class ModuleListModule extends React.Component { 
    // Once again, unrelated content omitted 
    render() { 
     return (
      <Link to={this.moduleLink()}> 
       <div className="module"> 
        <div className="p-2 row"> 
         <div className="col"> 
          <h5>{this.props.module.name}</h5> 
          <div className="module-subheader"> 
           {this.props.module.edition.name} {this.renderLevel()} {this.renderLength()} 
          </div> 
          <div className="module-summary">{this.props.module.summary}</div> 
         </div> 
         <div className="col-2 text-center"> 
          <ModuleStarRating current={this.currentRating()} readonly/> 
         </div> 
         <div className="col-2 text-center"> 
          <img src={this.props.module.small_cover}/> 
         </div> 
        </div> 
       </div> 
      </Link> 
     ) 
    } 
} 

根據React Router docs,我應該在我的測試中使用<MemoryRouter/>來繞過路由器功能。

import {MemoryRouter} from 'react-router-dom'; 
import {ModulesList} from 'js/Scenes/Home/ModulesList'; 
import React from 'react'; 
import {assert} from 'chai'; 
import {shallow} from 'enzyme'; 
import sinon from 'sinon'; 

describe('ModulesList',() => { 
    it('should sort by name, when requested.',() => { 
     const initialProps = { 
      getModules: sinon.stub(), 
      isFetching: false, 
      modules: [], 
      setModulesFetching: sinon.stub(), 
      sortBy: 'name' 
     }; 

     const wrapper = shallow(
      <MemoryRouter> 
       <ModulesList {...initialProps}/> 
      </MemoryRouter> 
     ); 
     const nextModules = [ 
      { 
       avg_rating: [{ 
        aggregate: 1.0 
       }], 
       edition: { 
        name: "fakeedition" 
       }, 
       id: 0, 
       name: "Z module" 
      }, 
      { 
       avg_rating: [{ 
        aggregate: 1.0 
       }], 
       edition: { 
        name: "fakeedition" 
       }, 
       id: 1, 
       name: "Y module" 
      } 
     ]; 

     wrapper.setProps({modules: nextModules}); 
     assert.equal(wrapper.render().find('#search-summary').text(), '3 Adventures Found'); 
    }); 
}); 

但是這個測試失敗。調用酶的ShallowWrapper.setProps()將不會有所需的效果,因爲道具沒有被應用到我的組件,它們被應用於<MemoryRouter/>。但我不能忽略<MemoryRouter/>,因爲如果我這樣做,我得到這個錯誤:

Warning: Failed context type: The context `router` is marked as required in `Link`, but its value is `undefined`. 
in Link (created by ModuleListModule) 
in ModuleListModule 
in div 

TypeError: Cannot read property 'history' of undefined 

How can I setup my test such that I can call setProps() and the component actually updates?

回答

1

從事過這幾天和一個解決方案上來。我拿起a third party library來模擬Redux商店,但其餘的我用谷歌搜索拼湊起來。

/* global describe, it */ 
import {MemoryRouter} from 'react-router-dom'; 
import {ModulesList} from 'js/Scenes/Home/ModulesList'; 
import {Provider} from 'react-redux'; 
import React from 'react'; 
import {assert} from 'chai'; 
import configureStore from 'redux-mock-store'; 
import {shallow} from 'enzyme'; 
import sinon from 'sinon'; 

describe('ModulesList'() => { 
    it('should sort by name, when requested.',() => { 
     const storeFactory = configureStore([]); 
     const store = storeFactory({}); 
     # This is the harness my component needs in order to function in the 
     # test environment. 
     const TestModulesList = (props) => { 
      return (
       <Provider store={store}> 
        <MemoryRouter> 
         <ModulesList {...props}/> 
        </MemoryRouter> 
       </Provider> 
      ); 
     }; 

     const initialProps = { 
      getModules: sinon.stub(), 
      isFetching: false, 
      modules: [], 
      setModulesFetching: sinon.stub(), 
      sortBy: 'name' 
     }; 

     const wrapper = shallow(<TestModulesList {...initialProps}/>); 
     const nextModules = [/* omitted */]; 
     wrapper.setProps({modules: nextModules}); 

     assert.equal(wrapper.render().find('#search-summary').text(), '2 Adventures Found'); 
    }); 
}); 
相關問題