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);
});
});
Link.test.js import React from 'react'; import renderer from 'react-test-renderer'; import { Link } from 'react-router-dom'; test('Link matches snapshot', () => { const component = renderer. create( <Link to="#" /> ); let tree = component. toJSON(); expect(tree). toMatchSnapshot(); });
To add the link in the menu, use the <NavLink /> component by react-router-dom . The NavLink component provides a declarative way to navigate around the application. It is similar to the Link component, except it can apply an active style to the link if it is active.
const linkToTest = screen. getByRole("link", { name: /link to test/i }) // I used regex here as a value of name property which ignores casing expect(linkToTest. getAttribute("href")). toMatchInlineSnapshot();
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.
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);
});
});
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With