我正在尝试测试一个React组件,该组件需要与app.js分开使用react-router。
我有一个使用mixin Router.Navigation进行重定向的组件,如下所示:
router
我试图为此写一个测试,但碰到了一堵墙。除了我无法测试转换以便按预期工作之外,我在Jest测试中也遇到了这条错误消息:
警告:上下文类型失败:Searchbar
未指定必需的上下文https://www.google.com/finance/converter?a=1&from=INR&to=USD&jsoncallback=?
。
有谁知道如何摆脱警告和奖金问题,我如何测试转换是否按预期工作?
我已经在这里和Github上的这个对话进行了研究:http://cdnjs.com/libraries/jquery-ui-timepicker-addon是我发现的最接近问题的人。看起来我需要单独导出路由器,但是在没有警告的情况下运行组件测试似乎需要很多开销https://github.com/rackt/react-router/issues/400
这真的是要走的路吗?
答案 0 :(得分:5)
在React Router的0.13版本中,不推荐使用mixins Navigation
和State
。相反,它们提供的方法存在于对象this.context.router
上。这些方法不再被弃用,但如果您明确使用this.context.router
,则不需要mixin(但您需要直接声明contextTypes
);或者,您可以使用mixin,但不需要直接使用this.context.router
。 mixin方法将为您访问它。
在任何一种情况下,除非您通过React Router渲染组件(通过Router#run
),否则router
对象不会提供给上下文,当然您也无法调用转换方法。警告告诉您的是 - 您的组件希望将路由器传递给它,但它无法找到它。
要单独测试它(不创建路由器对象或通过Router#run
运行组件),您可以在组件的上下文中放置一个模拟的router
对象,在正确的位置,并测试您使用正确的值调用transitionTo
。
答案 1 :(得分:4)
这是我的Jest文件,可以完整回答这个问题。 BinaryMuse的最后一段让我走在正确的轨道上,但我发现代码示例总是最有帮助的,所以这里是供将来参考。
jest.dontMock('./searchbar');
describe('Searchbar', function() {
var React = require('react/addons'),
Searchbar = require('../../components/header/searchbar'),
TestUtils = React.addons.TestUtils;
describe('render', function() {
var searchbar;
beforeEach(function() {
Searchbar.contextTypes = {
router: function() {
return {
transitionTo: jest.genMockFunction()
};
}
};
searchbar = TestUtils.renderIntoDocument(
<Searchbar />
);
});
it('should render the searchbar input', function() {
var searchbarContainer = TestUtils.findRenderedDOMComponentWithClass(searchbar, 'searchbar-container');
expect(searchbarContainer).toBeDefined();
expect(searchbarContainer.props.children.type).toEqual('input');
});
});
});
希望将来可以帮助其他人。
答案 2 :(得分:3)
因为router
严重依赖于React鲜为人知的context
功能,所以你需要像here
var stubRouterContext = (Component, props, stubs) => {
return React.createClass({
childContextTypes: {
makePath: func,
makeHref: func,
transitionTo: func,
replaceWith: func,
goBack: func,
getCurrentPath: func,
getCurrentRoutes: func,
getCurrentPathname: func,
getCurrentParams: func,
getCurrentQuery: func,
isActive: func,
},
getChildContext () {
return Object.assign({
makePath () {},
makeHref () {},
transitionTo () {},
replaceWith () {},
goBack () {},
getCurrentPath () {},
getCurrentRoutes () {},
getCurrentPathname () {},
getCurrentParams () {},
getCurrentQuery () {},
isActive () {},
}, stubs);
},
render () {
return <Component {...props} />
}
});
};
并使用如下:
var stubRouterContext = require('./stubRouterContext');
var IndividualComponent = require('./IndividualComponent');
var Subject = stubRouterContext(IndividualComponent, {someProp: 'foo'});
React.render(<Subject/>, testElement);
答案 3 :(得分:2)
我的答案不是Jest特定的,但它可能会帮助人们遇到同样的问题。
我创建了一个包装router
context
的类。
然后在你的测试中添加
<ContextWrapper><YourComponent/></ContextWrapper>
包装ReactIntl
之类的其他内容会很有用。
请注意,您将失去使用浅层渲染的可能性,但ReactIntl
已经是这种情况。
希望能有所帮助。
ContextWrapper.js
import React from 'react';
export default React.createClass({
childContextTypes: {
router: React.PropTypes.object
},
getChildContext () {
return {
router: {}
};
},
render () {
return this.props.children;
}
});