简体   繁体   English

React js - 如何在测试组件时模拟上下文

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM