Files
react-tutorial/docs/testing.md
2017-04-09 10:10:41 +08:00

5.0 KiB
Raw Blame History

React测试

React组件至少有两个方面需要测试。

  • 给定属性property)和状态state会渲染出什么结果
  • 对于渲染的结果进行某种输入用户的互动有没有可能从状态A转化成状态B

第一类测试可以称为测试结构,第二类测试可以称之为测试行为。

推荐的工具集

  • Shallow rendering
  • Regular test utilities and jsdom when needed
  • mocha + jsdom + expect + expect-jsx + babel-plugin-rewire

测试结构真实DOM测试

mocha-jsdom模块让你可以在describe方法内部或者全局环境,使用jsdom()方法将Node.js环境模拟成一个浏览器环境支持所有DOM和浏览器的APIwindowdocumenthistory等等变量在全局环境下可用。

jsdom的参数useEach表示这些全局变量绑定Mocha的beforeEach/afterEach方法,而不是before/after方法,默认等于false

react-addons-test-utils模块是React官方提供的测试工具库。它的renderIntoDocument方法接受一个React组件作为参数将其渲染成Document对象上面的一个真实DOM结构但是不会将其插入文档。这个方法执行的前提是windowwindow.documentwindow.document.createElement必须在调用React之前就在全局范围之中可以拿到。否则React会认为无法拿到DOM然后诸如setState这样的方法就不可用。

react-dom模块的findDOMNode方法它接受一个React组件作为参数。如果该组件已经加到了DOM那么该方法返回对应的浏览器之中的真实DOM。这个方法主要用于从真实方法取值比如表单项的值。大多数情况从组件的ref属性可以拿到真实DOM不一定要使用findDOMNode方法。如果render方法返回nullfalsefindDOMNode方法也会返回null

findDOMNode()只对已经加载的组件有效即已经放入DOM否则会报错。

import React from 'react';
import {findDOMNode} from 'react-dom';
import {renderIntoDocument} from 'react-addons-test-utils';
import jsdom from 'mocha-jsdom';
import expect from 'expect';

class Label extends React.Component {
  render() {
    return <span>Hello {this.props.name}</span>;
  }
}

class Button extends React.Component {
  render() {
    return <div><Label name={this.props.name} /></div>;
  }
}

describe('Real dom test', () => {
  jsdom({useEach: true});

  it('works', () => {
    let component = renderIntoDocument(<Button name="John" />);
    let DOMNode = findDOMNode(component);
    expect(
      DOMNode.querySelector('span')
        .textContent
    ).toEqual('Hello John');
  });
});

例二。

import React from 'react';
import {
   renderIntoDocument,
  findRenderedDOMComponentWithTag
} from 'react-addons-test-utils';
import jsdom from 'mocha-jsdom';
import expect from 'expect';

class Label extends React.Component {
  render() {
    return <span>Hello {this.props.name}</span>;
  }
}

class Button extends React.Component {
  render() {
    return <div><Label name={this.props.name} /></div>;
  }
}

describe('Real Test Utilities', () => {
  jsdom({useEach: true});

  it('works', () => {
    let component = renderIntoDocument(<Button name="John" />);
    expect(
      findRenderedDOMComponentWithTag(component, 'span')
        .textContent
    ).toEqual('Hello John');
  });
});

例三。

import React from 'react';
import expect from 'expect';
import {createRenderer} from 'react-addons-test-utils';

class Label extends React.Component {
  render() {
    return <span>Hello {this.props.name}</span>;
  }
}

class Button extends React.Component {
  render() {
    return <div><Label name={this.props.name} /></div>;
  }
}

describe('Shallow rendering', () => {
  it('works', () => {
    let renderer = createRenderer();
    renderer.render(<Button name="John" />);
    let actualElement = renderer.getRenderOutput();
    let expectedElement = <div><Label name="John" /></div>;
    expect(actualElement).toEqual(expectedElement);
  });
});

测试行为

import React from 'react';
import expect from 'expect';
import {createRenderer} from 'react-addons-test-utils';

class Label extends React.Component {
  render() {
    return <span>Hello {this.props.name}</span>;
  }
}

class Button extends React.Component {
  render() {
    return <div onClick={this.props.click}><Label name={this.props.name} /></div>;
  }
}

describe('Shallow rendering on* handlers', () => {
  it('works', () => {
    let renderer = createRenderer();
    let hasClicked = false;
    let click = () => hasClicked = true;
    renderer.render(<Button name="John" click={click} />);
    renderer.getRenderOutput().props.onClick();
    expect(hasClicked).toBe(true);
  });
});

参考链接