7

I am having a nightmare finding a good solution for testing a React Router link. It is passing on the 'renders Categories properly' however zero links are being passed through to the test, I have tried so many different things and have still got nowhere.

Below is what i am trying to test:

Component

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

class Categories extends React.Component {

constructor(props, context){
    super(props);
    context.router
}

render() {
    return (
        <nav className="categories">
          <ul>
              <li><Link to="devices">Devices</Link></li>
              <li><Link to="cases">Cases</Link></li>
              <li><Link to="layouts">Layouts</Link></li>
              <li><Link to="designs">Designs</Link></li>
          </ul>
        </nav>
    );
  }
}

Categories.contextTypes = {
 router: React.PropTypes.func.isRequired
};

export default Categories;

StubRouterContext

import React from 'react';
import objectAssign from 'object-assign';

var stubRouterContext = (Component, props, stubs) => {
function RouterStub() { }

objectAssign(RouterStub, {
  makePath () {},
  makeHref () {},
  transitionTo () {},
  replaceWith () {},
  goBack () {},
  getCurrentPath () {},
  getCurrentRoutes () {},
  getCurrentPathname () {},
  getCurrentParams () {},
  getCurrentQuery () {},
  isActive () {},
  getRouteAtDepth() {},
  setRouteComponentAtDepth() {}
 }, stubs)

return React.createClass({
childContextTypes: {
    router: React.PropTypes.func,
    routeDepth: React.PropTypes.number
},

getChildContext () {
    console.log('blah');
  return {
    router: RouterStub,
    routeDepth: 0
  };
},

render () {
  return <Component {...props} />
}
});
};

export default stubRouterContext;

Component Test

var expect = require('chai').expect;

var React = require('react/addons');
var Categories = require('../app/src/js/components/Categories.React.js');
var stubRouterContext = require('../test-utils/stubRouterContext.js');
var TestUtils = React.addons.TestUtils;

describe('Categories', function() {
  var categoriesWithContext = stubRouterContext(Categories);

  it('renders Categories properly', function() {
  var categories = TestUtils.renderIntoDocument(<categoriesWithContext />, {});
});

it('renders 4 links', function() {
  var catLinks = TestUtils.scryRenderedDOMComponentsWithTag(categoriesWithContext, 'a');
  expect(catLinks).to.have.length(4);
});
});

2 Answers 2

1

I had exactly the same problem. In the latest versions of react-router, you do not need context to render link elements so this isn't a problem. However, if you are stuck on pre API 1.0 versions as I am, the stubRouterContext approach works well.

The only reason OP and I found that our wrapper was rendering empty is the use of a camelCase component name.

var categoriesWithContext = stubRouterContext(Categories); becomes var CategoriesWithContext = stubRouterContext(Categories);.

Therfore var categories = TestUtils.renderIntoDocument(<categoriesWithContext />,{}); becomes var categories = TestUtils.renderIntoDocument(<CategoriesWithContext />,{});.

Explanation of this approach is here - https://gist.github.com/sebmarkbage/f1f4ba40816e7d7848ad.

Sign up to request clarification or add additional context in comments.

Comments

1

The first thing I notice is that you're not re-rendering "categoriesWithContext" in the second test.

it('renders 4 links', function() {
  var categories = TestUtils.renderIntoDocument(<categoriesWithContext />, {});
  var catLinks = TestUtils.scryRenderedDOMComponentsWithTag(categories, 'a');
  expect(catLinks).to.have.length(4);
});

Though I haven't run your code myself, the next thing I notice is the way you're fetching the links. In a test I have, I must dig through the hierarchy manually.

Try this.

it('renders 4 links', function() {
  var categories = TestUtils.renderIntoDocument(<categoriesWithContext />, {});
  var ul = TestUtils.findRenderedDOMComponentWithTag(categories, 'ul');
  var lis = TestUtils.scryRenderedDOMComponentsWithTag(ul, 'li');
  lis.forEach(function(li) {
    // this should throw if <a/> is not found
    var a = TestUtils.findRenderedDOMComponentWithTag(li, 'a');
    // but write an explicit expectation anyway
    expect(a);
  });
});

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.