# Test Renderer

如何引入

import TestRenderer from 'react-test-renderer'; // ES6
const TestRenderer = require('react-test-renderer'); // ES5 with npm

# 概览

这个 package 提供了一个 React 渲染器,用于将 React 组件渲染成纯 JavaScript 对象,无需依赖 DOM 或原生移动环境。

这个 package 提供的主要功能是在不依赖浏览器或 jsdom 的情况下,返回某个时间点由 React DOM 或者 React Native 平台渲染出的视图结构(类似与 DOM 树)快照。

示例:

import TestRenderer from 'react-test-renderer';

function Link(props) {
  return <a href={props.page}>{props.children}</a>;
}

const testRenderer = TestRenderer.create(
  <Link page="https://www.facebook.com/">Facebook</Link>
);

console.log(testRenderer.toJSON());
// { type: 'a',
//   props: { href: 'https://www.facebook.com/' },
//   children: [ 'Facebook' ] }

你可以使用 Jest 的快照测试功能来自动保存当前 JSON 树结构到一个文件中,并在测试中检查它是否被修改: 了解更多

你也可以通过遍历输出来查找特定节点,并对它们进行断言。

import TestRenderer from 'react-test-renderer';

function MyComponent() {
  return (
    <div>
      <SubComponent foo="bar" />
      <p className="my">Hello</p>
    </div>
  )
}

function SubComponent() {
  return (
    <p className="sub">Sub</p>
  );
}

const testRenderer = TestRenderer.create(<MyComponent />);
const testInstance = testRenderer.root;

expect(testInstance.findByType(SubComponent).props.foo).toBe('bar');
expect(testInstance.findByProps({className: "sub"}).children).toEqual(['Sub']);

# TestRenderer

  • TestRenderer.create()
  • TestRenderer.act()

# TestRenderer instance

  • testRenderer.toJSON()
  • testRenderer.toTree()
  • testRenderer.update()
  • testRenderer.unmount()
  • testRenderer.getInstance()
  • testRenderer.root

# TestInstance

  • testInstance.find()
  • testInstance.findByType()
  • testInstance.findByProps()
  • testInstance.findAll()
  • testInstance.findAllByType()
  • testInstance.findAllByProps()
  • testInstance.instance
  • testInstance.type
  • testInstance.props
  • testInstance.parent
  • testInstance.children

# 参考

# TestRenderer.create()

TestRenderer.create(element, options);

通过传来的 React 元素创建一个 TestRenderer 实例。它并不使用真实的 DOM,但是它依然将组件树完整地渲染到内存,以便于你对它进行断言。此时将返回一个 TestRenderer 实例

# TestRenderer.act()

TestRenderer.act(callback);

react-dom/test-utils 中的 act() 相似,TestRender.act 为断言准备一个组件。可以使用 act() 来包装 TestRenderer.createtestRenderer.update

import {create, act} from 'react-test-renderer';
import App from './app.js'; // The component being tested

// 渲染组件
let root; 
act(() => {
  root = create(<App value={1}/>)
});

// 对根元素进行断言
expect(root.toJSON()).toMatchSnapshot();

// 更新 props
act(() => {
  root.update(<App value={2}/>);
})

// 对根元素进行断言
expect(root.toJSON()).toMatchSnapshot();

# testRenderer.toJSON()

testRenderer.toJSON()

返回一个已渲染的的树对象。该树仅包含特定平台的节点,例如 和它们的 props,但并不包含任何用户编写的组件。这对于 快照测试 非常方便。

# testRenderer.toTree()

testRenderer.toTree()

返回一个已渲染的的树对象。它所表示的内容比 toJSON() 提供的内容要更加详细,并且包含用户编写的组件。除非你要在测试渲染器(test renderer)之上编写自己的断言库,否则你可能并不需要这个方法。

# testRenderer.update()

testRenderer.update(element)

使用新的根元素重新渲染内存中的树。它模拟根元素的一次 React 更新。如果新的元素和之前的元素有相同的 type 和 key,该树将会被更新;否则,它将重挂载一个新树。

# testRenderer.unmount()

testRenderer.unmount()

卸载内存中的树,会触发相应的生命周期事件。

# testRenderer.getInstance()

testRenderer.getInstance()

如果可用的话,返回与根元素相对应的实例。如果根元素是函数定义组件,该方法无效,因为函数定义组件没有实例。

# testRenderer.root

testRenderer.root

返回根元素“测试实例”对象,它对于断言树中的特定节点十分有用。你可以利用它来查找其他更深层的“测试实例”。

# testInstance.find()

testInstance.find(test)

找到一个 test(testInstance) 返回 true 的后代测试实例。如果不只有一个测试实例匹配,将会报错。

# testInstance.findByType()

testInstance.findByType(type)

找到匹配指定 type 的后代测试实例,如果不是只有一个测试实例匹配指定的 type,将会报错。

# testInstance.findByProps()

testInstance.findByProps(props)

找到匹配指定 props的后代测试实例,如果不是正好只有一个测试实例匹配指定的 props,将会报错。

# testInstance.findAll()

testInstance.findAll(test)

找到所有 test(testInstance) 返回 true 的后代测试实例。

# testInstance.findAllByType()

testInstance.findAllByType(type)

找到所有匹配指定 type 的后代测试实例。

# testInstance.findAllByProps()

testInstance.findAllByProps(props)

找到所有匹配指定 props 的后代测试实例。

# testInstance.instance

testInstance.instance

该测试实例相对应的组件实例。它只能用于类定义组件,因为函数定义组件没有实例。它匹配给定的组件内部的 this 的值。

# testInstance.type

testInstance.type

该测试实例相对应的组件的类型。例如,一个 `` 组件有一个 Button 类型。

# testInstance.props

testInstance.props

该测试实例相对应的组件的 props。例如,一个 `` 组件的 props 为 {size: 'small'}

# testInstance.parent

testInstance.parent

该测试实例的父测试实例。

# testInstance.children

testInstance.children

该测试实例的子测试实例。

# 想法

你可以把 createNodeMock 函数作为选项(option)传递给 TestRenderer.create,进行自定义 refs 模拟。createNodeMock 接受当前元素作为参数,并且返回一个模拟 ref 对象的。这十分有利于依赖 refs 组件的测试。

import TestRenderer from 'react-test-renderer';

class MyComponent extends React.Component {
  constructor(props) {
    super(props);
    this.input = null;
  }
  componentDidMount() {
    this.input.focus();
  }
  render() {
    return <input type="text" ref={el => this.input = el} />
  }
}

let focused = false;
TestRenderer.create(
  <MyComponent />,
  {
    createNodeMock: (element) => {
      if (element.type === 'input') {
        // 模拟 focus 函数
        return {
          focus: () => {
            focused = true;
          }
        };
      }
      return null;
    }
  }
);
expect(focused).toBe(true);
Last Updated: 5/13/2023, 8:55:38 PM