[英]React js - How to mock Context when testing component
I'm trying to test a component which inherits context from a root component, without loading/rendering everything from the root down.我正在尝试测试一个从根组件继承上下文的组件,而不是从根向下加载/渲染所有内容。 I've tried and searched for examples on how to mock the context but can't find anything (at least that doesn't use jest).
我已经尝试并搜索了有关如何模拟上下文的示例,但找不到任何内容(至少不使用玩笑)。
Here's a simplified example of what I'm trying to achieve.这是我要实现的目标的简化示例。
Is there a simple way I can mock reactEl.context for the test?有没有一种简单的方法可以模拟 reactEl.context 进行测试?
/**
* Root Element that sets up & shares context
*/
class Root extends Component {
getChildContext() {
return {
language: { text: 'A String'}
};
}
render() {
return (
<div>
<ElWithContext />
</div>
);
}
}
Root.childContextTypes = { language: React.PropTypes.object };
/**
* Child Element which uses context
*/
class ElWithContext extends React.Component{
render() {
const {language} = this.context;
return <p>{language.text}</p>
}
}
ElWithContext.contextTypes = { language: React.PropTypes.object }
/**
* Example test where context is unavailable.
*/
let el = React.createElement(ElWithContext)
element = TestUtils.renderIntoDocument(el);
// ERROR: undefined is not an object (evaluating 'language.text')
describe("ElWithContext", () => {
it('should contain textContent from context', () => {
const node = ReactDOM.findDOMNode(element);
expect(node.textContent).to.equal('A String');
});
})
I went into the same issue as you did and found out two ways of doing it.我遇到了和你一样的问题,并找到了两种方法。
The first one is a basic copycat of your own way: Create a wrapper around my component and inject it with a dynamic context.第一个是您自己方式的基本复制品:围绕我的组件创建一个包装器并为它注入动态上下文。 I put the source code below for those interested, because it's ES6 unlike your example.
我将源代码放在下面供感兴趣的人使用,因为它与您的示例不同的是 ES6。 But it's just to show how it would be done in ES6 and I do NOT recommend anyone using it (I haven't actually tested it myself) .
但这只是为了展示在 ES6 中它是如何完成的,我不推荐任何人使用它(我自己还没有实际测试过) 。
src/testUtils/mockWithContext.js src/testUtils/mockWithContext.js
import React, { Component } from 'react';
import wrapDisplayName from 'recompose/wrapDisplayName';
import hoistStatics from 'recompose/hoistStatics';
export const defaultContext = {
permissions: [
],
user: {
id: '1',
display_name: 'Default user',
email: '<your.email>+default.user@gmail.com', // Trick with "+" for infinite aliases using gmail.
username: 'default_user',
created: '2016-08-01T15:50:13.246Z',
},
};
export const defaultContextType = {
permissions: React.PropTypes.array,
user: React.PropTypes.shape({
id: React.PropTypes.string.isRequired,
display_name: React.PropTypes.string.isRequired,
email: React.PropTypes.string.isRequired,
username: React.PropTypes.string.isRequired,
created: React.PropTypes.string.isRequired,
}),
};
/**
* HOC for context
*/
const withContext = ({ context = defaultContext, contextType = defaultContextType }) => (WrappedComponent) => {
class WithContext extends Component {
getChildContext() {
return context;
}
render() {
return <WrappedComponent {...this.props} />;
}
}
WithContext.displayName = wrapDisplayName(WrappedComponent, 'WithContext');
WithContext.WrappedComponent = WrappedComponent;
WithContext.childContextTypes = contextType;
return WithContext;
};
export default hoistStatics(withContext);
As I said, I wrote it, but didn't test it because I found a much better way of doing context-injecting when trying to write tests for this mock.正如我所说,我写了它,但没有测试它,因为在尝试为此模拟编写测试时,我发现了一种更好的上下文注入方法。
Using Enzyme library, which is definitely built to support React components testing, there is the ability to shallow
/ mount
/ static
render your component, for testing purpose.使用绝对支持 React 组件测试的 Enzyme 库,可以
shallow
/ mount
/ static
渲染您的组件,用于测试目的。 And each of these methods allow a second argument: the context.这些方法中的每一个都允许第二个参数:上下文。
SimpleComponent.js简单组件.js
const SimpleComponent = React.createClass({
contextTypes: {
name: React.PropTypes.string,
},
render() {
return <div>{this.context.name}</div>;
},
});
SimpleComponent.test.js简单组件.test.js
const context = { name: 'foo' };
const wrapper = mount(<SimpleComponent />, { context });
expect(wrapper.text()).to.equal('foo');
wrapper.setContext({ name: 'bar' });
expect(wrapper.text()).to.equal('bar');
wrapper.setContext({ name: 'baz' });
expect(wrapper.text()).to.equal('baz');
Pretty straight-forward.很直接。 I didn't use it yet but it looks like what I (and you) wanted to do.
我还没有使用它,但它看起来像我(和你)想要做的。 I guess I'll just have to throw my own implementation to the garbage.
我想我只需要把我自己的实现扔进垃圾桶。
http://airbnb.io/enzyme/docs/api/ReactWrapper/setContext.html http://airbnb.io/enzyme/docs/api/ReactWrapper/setContext.html
I went with a solution of creating a wrapping component with context.我采用了一种创建带有上下文的包装组件的解决方案。 Not sure if this is a great approach but is working for me right now:
不确定这是否是一个很好的方法,但现在对我有用:
/**
* Helper function to wrap component with a component that has context
*/
function wrapWithContext(context, contextTypes, children, React){
const wrapperWithContext = React.createClass({
childContextTypes: contextTypes,
getChildContext: function() { return context },
render: function() { return React.createElement('div', null, children) }
});
return React.createElement(wrapperWithContext);
}
/**
* Usage
*/
// in setup function of test framework
const el = React.createElement(ElWithContext);
const context = { language: { text: 'A String' } };
const contextTypes = { language: React.PropTypes.object };
const wrapper = wrapWithContext(context, contextTypes, [el], React);
const ElWithContext = TestUtils.renderIntoDocument(wrapper);
// do tests
describe('ElWithContext', () => {
it('should contain textContent from context', () => {
const node = ReactDOM.findDOMNode(element);
expect(node.textContent).to.equal('A String');
});
})
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.