欢迎移步我的博客阅读:《React
测试驱动教程》

测试是开发周期中的一个敬服组成部分。没有测试的代码被叫作:遗留代码。对于自身而言,第二回学习
React 和 JavaScript 的时候,感到很有压力。即使您也是刚开端上学
JS/React,并进入他们的社区,那么也说不定会有同一的觉得。想到的会是:

  • 本人应当用哪一个营造工具?
  • 哪一个测试框架相比好?
  • 自身应当学学哪个种类流形式?
  • 自我需求用到流吗?

为了缓解那个烦恼,我说了算写那篇小说。经过多少个钟头的博客小说阅读,查阅 JS
开发者的源码,还有加入 Florida 的
JSConf,终于让自家找到了自己的测试“槽”。先导让自身觉着没有经过测试的 React
程序代码是那样的不标准和芜杂。我想活在一个没有那种感觉的社会风气,但新兴思想,那是颠三倒四的。

本课程所有的代码都得以在本人的 github
仓库
中找到。

让大家早先吧!

设置 Webpack

本学科不是一个教怎么运用
webpack,所以我不会详细说,但紧要的是要打听宗旨的事物。
Webpack 就好像 Rails 中的 Assets Pipeline 一样。在基础层面上而言,在运行
react 应用时,
会在处理你的代码和劳务的左右,只生成一个 bundle.js 在客户端。

因为它是一个格外强劲的工具,所以大家会时常用到。在开班,Webpack
的机能可能会吓到你,
但本身提议你坚贞不屈运用下去,一旦您询问了其中的原理,就会觉得百发百中。而你只需给它一个时机去突显。

经常大家不会喜欢那么些我们不会的,或是害怕的。然则,一旦您制伏早先不适并早先知道它,总会变得很有意思。事实上,那正是我对测试的感想。当先河时脑仁疼它,在熟稔后爱不释手它
🙂

只要感兴趣,那里有一些资源来更多地问询有关 webpack:

  1. Webpack
    Cookbook
    (使用的是
    Babel 5,但对此学习 Webpack 的基本原理而言依然很有用的)
  2. Webpack
    初学者可以看那篇作品
  3. Pete Hunts 所写的 Webpack
    How-to

注意:假诺要不停随本教程实验,指出利用 Node 版本为
v5.1.0。当然版本 >4 的也是足以的。

首先,安装具有关于 webpack 和 babel 的看重。Babel
是一个转译器,允许你在支付时行使 ES6(es2015)和 ES7
的特性,然后将那一个代码转译成浏览器可以辨其他 ES5 代码。

mkdir tdd_react
cd tdd_react
npm init        # follow along with normal npm init to set up project

npm i babel-loader babel-core webpack --save-dev

npm i 是 npm install 的别名。

接下去,让大家设置项目标门道和创造一个 webpack.config.js 文件:

mkdir src                  # where all our source code will live
touch src/main.js          # this will be the entry point for our webpack bundling
mkdir test                 # place to store all our tests
mkdir dist                 # this is where the bundled javascript from webpack will go
touch webpack.config.js    # our webpack configuration file

初始化的 webpack config 会很小。阅读那几个注释,了解下发出了哪些:

// our webpack.config.js file located in project root

var webpack = require('webpack');
var path = require('path');                // a useful node path helper library

var config = {
  entry: ['./src/main.js'],                // the entry point for our app
  output: {
    path: path.resolve(__dirname, 'dist'), // store the bundled output in dist/bundle.js
    filename: 'bundle.js'                  // specifying file name for our compiled assets
  },
  module: {
    loaders: [
      // telling webpack which loaders we want to use.  For now just run the
      // code through the babel-loader.  'babel' is an alias for babel-loader
      { test: /\.js$/, loaders: ['babel'], exclude: /node_modules/ }
    ]
  }
}

module.exports = config;

为了让 babel 更好地干活,大家须要定义哪个 presets
是我们要求采纳的。让大家后续,并且安装 React 和 ES6 预处理所需的东西:

npm i babel-preset-react babel-preset-es2015 --save-dev

现在我们有部分摘取。在 webpack config 文件中,会报告您哪一块是做 bebel
预处理的:

loaders: [
  {
    test: /\.js$/,
    loaders: ['babel'],
    exclude: /node_modules/,
    query: {
      presets: ['react', 'es2015']
    }
  }
]

别的的法门是将他们存在 .babelrc 文件中,那也用在我的档次中。将 babel
预处理存储在 .babelrc 中,对于今后的开发者而言,更便于去找到哪个 babel
预处理是可用的。别的,当大家将 Karma 设置到 webpack 之后,因为
.babelrc 文件的存在,我们就不再必要其他的预处理配置了。

# inside our project root
touch .babelrc

将下边那段粘贴到预处理文件中:

# .babelrc
{
  "presets": ["react", "es2015"]
}

为了确认它能仍旧不能工作,让我们在 main.js 中参与一些 react
代码,并探望所有的包是还是不是正常。接着安装 React 和 React DOM:

npm i react react-dom -S

使用 -S--save 的别名。

创办第三个 React 组件:

# src/main.js
import React, { Component } from 'react';
import { render } from 'react-dom';

class Root extends Component {
  render() {
    return <h1> Hello World </h1>;
  }
}

render(<Root />, document.getElementById('root'));

聪慧的读者就会发觉大家并没有在根部创制一个 index.html
文件。让大家后续,当 bundle.js 编译后,将其内置 /dist 文件夹中:

# /dist/index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8"/>
  </head>
  <body>
    <div id="root"></div>
    <script src="bundle.js"></script>
  </body>
</html>

至极棒,让大家继承。最终,大家可以运作
webpack,看看一切是还是不是正规。若是您没有大局安装
webpack(npm i webpack -g),你也可以用 node modules 情势进行启动:

./node_modules/.bin/webpack

Webpack 将默许情形下寻找一个计划名称为
webpack.config.js。若是您开心,也可以经过分歧 webpack config
作为参数传入。

在 package.json 中开创一个别名,来成功打造工作:

# package.json
... other stuff
"scripts": {
  "build": "webpack"
}

接下去让 webpack-dev-server 提高开发体验:

npm i webpack-dev-server --save-dev

将 webpack dev server 的进口参与到 webpack.config.js 中:

... rest of config
  entry: [
    'webpack/hot/dev-server',
    'webpack-dev-server/client?http://localhost:3000',
    './src/main.js'
  ],
... rest of config

让 script 运行在支付服务器上:

# package.json
... other stuff
scripts: {
  "dev": "webpack-dev-server --port 3000 --devtool eval --progress --colors --hot --content-base dist",
  "build": "webpack"
}

在 script 中选择了 --content-base 标记,告诉 webpack 大家想服务于
/dist 文件夹。大家还定义了 3000 端口,使得更像是 Rails 开发的感受。

最后,在 webpack 配置文件中添加一个 resolve
标记,使进口文件看起来更直观。下边就是安排文件最后的榜样:

var webpack = require('webpack');
var path = require('path');

var config = {
  entry: [
    'webpack/hot/dev-server',
    'webpack-dev-server/client?http://localhost:3000',
    './src/main.js'
  ],
  resolve: {
    root: [
      // allows us to import modules as if /src was the root.
      // so I can do: import Comment from 'components/Comment'
      // instead of:  import Comment from '../components/Comment' or whatever relative path would be
      path.resolve(__dirname, './src')
    ],
    // allows you to require without the .js at end of filenames
    // import Component from 'component' vs. import Component from 'component.js'
    extensions: ['', '.js', '.json', '.jsx']
  },
  output: {
    path: path.resolve(__dirname, 'dist'),
    filename: 'bundle.js'
  },
  module: {
    loaders: [
      {
        test: /\.js?$/,
        // dont run node_modules or bower_components through babel loader
        exclude: /(node_modules|bower_components)/,
        // babel is alias for babel-loader
        // npm i babel-core babel-loader --save-dev
        loader: 'babel'
      }
    ],
  }
}

module.exports = config;

为力保全部工作例行,让大家运行开发服务器,并且认可大家在显示屏上观望“Hello World”。

npm run dev
open http://localhost:3000

您应该看到的是如此的:

Hello World Image

设置 Mocha,Chai,Sinon 和 Enzyme

Mocha:将用于运行大家的测试。
Chai:是大家期待的库。应用越发常见,允许使用 RSpec 一样的语法。
Sinon:将劳动于 mocks/stubs/spies.
Enzyme:将用于测试大家的 React components。AirBnB
写的一个很赏心悦目的测试库。

设置这几个包:

npm i mocha chai sinon --save-dev

比方大家期望可以运用 ES6
编写测试,那么大家须求在运行前对代码举行转译。那么大家须要设置
babel-register:

npm i babel-register --save-dev

加一些 npm scripts 到 package.json 中,让测试更简约:

# ./package.json
... rest of package.json
  "scripts": {
    "test": "mocha --compilers js:babel-register --recursive",
    "test:watch": "npm test -- --watch",
    "build": "webpack",
    "dev": "webpack-dev-server --port 3000 --devtool eval --progress --colors --hot --content-base dist",
  },

大家的测试脚本要运行 mocha,并动用 babel-register
进行转译,然后递归地查看 /test 目录。

最终,大家必要设置 Karma,由此 npm script
会变得不行,但如若不安装,它将会健康干活。npm run test:watch
将会监视程序,并在文件发出修改时再也运行。多么高效!

肯定它能干活,成立一个 hello world 测试 /tests/helloWorld.spec.js

# /test/helloWorld.spec.js
import { expect } from 'chai';

describe('hello world', () => {
  it('works!', () => {
    expect(true).to.be.true;
  });
});

哇…看起来很像 RSpec!

若是每一个测试都要引入 expect,那将变得很麻烦,由此让我们新建一个
test_helper 文件来保存这一个东西:

# /test/test_helper.js
import { expect } from 'chai';
import sinon from 'sinon';

global.expect = expect;
global.sinon = sinon;

然后把它概括到 npm 脚本的运转套件中,并通过
--require ./test/test_helper.js 来声明:

# package.json script section
  "test": "mocha --compilers js:babel-register --require ./test/test_helper.js --recursive",

本人也添加了
sinon,因而它也得以全局可用。现在不论是怎么样时候,我们在写一个新的测试时,都不须要手动引入
expectsinon

Enzyme

现行大家所需的“普通”测试工具都早就设置好了(mocha,chai,sinon),接着让我们设置
Enzyme,并且起先测试 React component!

设置那一个包:

npm i enzyme react-addons-test-utils --save-dev

Enzyme
的关键文档可以在此间找到。如若有时间,我引进阅读
Shallow Rendering 部分。

你会问,什么是 Shallow Rendering?

对大家的话是一种组件调用 render 方法,得到我们得以预知的 React
元素,而无需实际安装组件到 DOM 上。更加多的 React
元素请看这

Enzyme 会将 shallow rendered 组件封装进一个非同日常的 wrapper
中,进而让我们可以测试。即使您用过 Rails,这看起来像是 Capybara 中的
page 对象。

让我们为部分恰如其分的 <Root /> 组件进行 TDD 的驱动开发。

本条 Root 组件会是一个 container,意味着在采取中它可以控制 state
的拍卖。学习 React
中“智能”和“死板”组件之间的差别,对于应用程序连串布局是很要紧的。这篇文章很好地解释了它们

# /tests/containers/Root.spec.js

import React from 'react';                     // required to get test to work.  we can get around this later with more configuration
import { shallow } from 'enzyme';              // method from enzyme which allows us to do shallow render
import Root from '../../src/containers/Root';  // import our soon to be component

describe('(Container) Root', () => {
  it('renders as a <div>', () => {
    const wrapper = shallow(<Root />);
    expect(wrapper.type()).to.eql('div');
  });

  it('has style with height 100%', () => {
    const wrapper = shallow(<Root />);
    const expectedStyles = {
      height: '100%',
      background: '#333'
    }
    expect(wrapper.prop('style')).to.eql(expectedStyles);
  });

  it('contains a header explaining the app', () => {
    const wrapper = shallow(<Root />);
    expect(wrapper.find('.welcome-header')).to.have.length(1);
  });
});

尽管大家用 npm test
运行测试,那会破产。因为大家从没在适宜的岗位创设一个根组件。由此大家得以这么做:

即使在其他时候你想看看那段代码的源代码,可以在 github
仓库

中找到

# /src/containers/Root.js
import React, { Component } from 'react';

const styles = {
  height: '100%',
  background: '#333'
}

class Root extends Component {
  render() {
    return (
      <div style={styles}>
        <h1 className='welcome-header'>Welcome to testing React!</h1>
      </div>
    )
  }
}

export default Root;

再一次运行测试就可以了。

在我们的测试中有广大重复的事物,因而大家还索要重返做一些重构。由于大家尚无给
Root 传入任何的 props,那么大家得以 shallow render
它三遍,然后就在一个 wrapper
中截至了大家拥有的断言。很多时候给定一个一定的 props
后,我发现自己包装的有的测试会在 “sub” describe
块中,然后给一堆断言也有那一个 props。借使你用过 RSpec,就恍如于使用
“context” 块。

describe('(Container) Root', () => {
  const wrapper = shallow(<Root />);

  it('renders as a <div>', () => {
    expect(wrapper.type()).to.eql('div');
  });

  it('has style with height 100%', () => {
    const expectedStyles = {
      height: '100%',
      background: '#333'
    }
    expect(wrapper.prop('style')).to.eql(expectedStyles);
  });

  it('contains a header explaining the app', () => {
    expect(wrapper.find('.welcome-header')).to.have.length(1);
  });
});

尽可能地在你的测试中使用 shallow,但有时候也说不定毫无。例如,如若您要测试
React 生命周期的法门时,就须要真正地将零件安装出来。

接下去让大家测试一个零部件的设置和调用函数,当它安装时,大家可以得到部分揭示在
sinon 上的音讯和正在使用的 spies。

俺们得以假装 Root 组件有一个子组件叫
CommentList,在装置后将调用任意的回调。当通过给定 props
组件安装时,函数被调用,因此大家就可以测试这几个情景。在组件渲染时给评论列表一些
style,然后大家就可以精通 shallow render
是怎样处理这么些样式的了。CommentList 会在一个零件文件夹的
/src/components/CommentList.js 中。因为它不处理数据,由此完全取决于
props,换句话说它是一个笨拙)组件:

import React from 'react';

// Once we set up Karma to run our tests through webpack
// we will no longer need to have these long relative paths
import CommentList from '../../src/components/CommentList';
import {
  describeWithDOM,
  mount,
  shallow,
  spyLifecycle
} from 'enzyme';

describe('(Component) CommentList', () => {

  // using special describeWithDOM helper that enzyme
  // provides so if other devs on my team don't have JSDom set up
  // properly or are using old version of node it won't bork their test suite
  //
  // All of our tests that depend on mounting should go inside one of these
  // special describe blocks
  describeWithDOM('Lifecycle methods', () => {
    it('calls componentDidMount', () => {
      spyLifecyle(CommentList);

      const props = {
        onMount: () => {},  // an anonymous function in ES6 arrow syntax
        isActive: false
      }

      // using destructuring to pass props down
      // easily and then mounting the component
      mount(<CommentList {...props} />);

      // CommentList's componentDidMount should have been
      // called once.  spyLifecyle attaches sinon spys so we can
      // make this assertion
      expect(
        CommentList.prototype.componentDidMount.calledOnce
      ).to.be.true;
    });

    it('calls onMount prop once it mounts', () => {
      // create a spy for the onMount function
      const props = { onMount: sinon.spy() };

      // mount our component
      mount(<CommentList {...props} />);

      // expect that onMount was called
      expect(props.onMount.calledOnce).to.be.true;
    });
  });
});

还有许多,阅读这个注释可以扶助您更好地精晓。看看那个实践,让测试可以经过,然后再回头看看这么些测试,验证下你所知晓的东西。

# /src/components/CommentList.js
import React, { Component, PropTypes } from 'react';

const propTypes = {
  onMount: PropTypes.func.isRequired,
  isActive: PropTypes.bool
};

class CommentList extends Component {
  componentDidMount() {
    this.props.onMount();
  }

  render() {
    return (
      <ul>
        <li> Comment One </li>
      </ul>
    )
  }
}

CommentList.propTypes = propTypes;
export default CommentList;

运行 npm test ,现在那么些套件应该可以透过测试了。

接下去让咱们添加一些 shallow rendered 测试,当给定一个 isActive
props 时,来保管大家的零件使用了适龄的 CSS class。

... previous tests

  it('should render as a <ul>', () => {
    const props = { onMount: () => {} };
    const wrapper = shallow(<CommentList  {...props} />);
    expect(wrapper.type()).to.eql('ul');
  });

  describe('when active...', () => {
    const wrapper = shallow(
      // just passing isActive is an alias for true
      <CommentList onMount={() => {}} isActive />
    )
    it('should render with className active-list', () => {
      expect(wrapper.prop('className')).to.eql('active-list');
    });
  });

  describe('when inactive...', () => {
    const wrapper = shallow(
      <CommentList onMount={() => {}} isActive={false} />
    )
    it('should render with className inactive-list', () => {
      expect(wrapper.prop('className')).to.eql('inactive-list');
    });
  });
});

让它们经过测试:

class CommentList extends Component {
  componentDidMount() {
    this.props.onMount();
  }

  render() {
    const { isActive } = this.props;
    const className = isActive ? 'active-list' : 'inactive-list';

    return (
      <ul className={className}>
        <li> Comment One </li>
      </ul>
    )
  }
}

此时你应该对怎样测试 react 组件已经有了一个很好的通晓了。记得去读书
Enzyme 文档来收获越来越多的灵感。

设置 Karma

设置 Karma
可能会有些不便。坦白讲,那对自我而言也是一件痛苦的工作。平时,当自己付出
React 应用时,我会选拔采用已经创设好的 starter
kit,方便方便。本身丰裕推荐开发时用的 starter
kit

应用 Karma 的市值在于连忙测试重载,能够多浏览器测试和最重大的是 webpack
预处理。一旦大家将 Karma 设置好了,在咱们运行测试程序时,不仅是唯有
babel-loader,而是一切 webpack
config。那为大家提供了过多便于,使得大家的测试环境与开销条件一致。

让大家开头吧…

npm i karma karma-chai karma-mocha karma-webpack --save-dev
npm i karma-sourcemap-loader karma-phantomjs-launcher --save-dev
npm i karma-spec-reporter --save-dev
npm i phantomjs --save-dev

# The polyfills arn't required but will help with browser support issues
# and are easy enough to include in our karma config that I figured why not
npm i babel-polyfill phantomjs-polyfill --save-dev

广大包,我驾驭。相信我落成那些是不行值得的。

对于我们的演示而言,大家将动用
PhantomJS。没有其余什么来头,那本身在
starter kit 中已经使用了。可以遵从自己的喜好利用 Chrome,Firefox 或是
Safari,甚至在 PhantomJS 之上。(那是用 Karma 的一件很酷的事)

在布局 karma 以前先安装 yargs,它能让您利用命令行参数来定制 Karma
的配备。

npm i yargs -S

如今我们得以因此创办一个 Karma config
文件去监视我们的文书,当文件爆发修改时再度运行并连忙地保存。

Karma Config

touch karma.config.js

// ./karma.config.js

var argv = require('yargs').argv;
var path = require('path');

module.exports = function(config) {
  config.set({
    // only use PhantomJS for our 'test' browser
    browsers: ['PhantomJS'],

    // just run once by default unless --watch flag is passed
    singleRun: !argv.watch,

    // which karma frameworks do we want integrated
    frameworks: ['mocha', 'chai'],

    // displays tests in a nice readable format
    reporters: ['spec'],

    // include some polyfills for babel and phantomjs
    files: [
      'node_modules/babel-polyfill/dist/polyfill.js',
      './node_modules/phantomjs-polyfill/bind-polyfill.js',
      './test/**/*.js' // specify files to watch for tests
    ],
    preprocessors: {
      // these files we want to be precompiled with webpack
      // also run tests throug sourcemap for easier debugging
      ['./test/**/*.js']: ['webpack', 'sourcemap']
    },
    // A lot of people will reuse the same webpack config that they use
    // in development for karma but remove any production plugins like UglifyJS etc.
    // I chose to just re-write the config so readers can see what it needs to have
    webpack: {
       devtool: 'inline-source-map',
       resolve: {
        // allow us to import components in tests like:
        // import Example from 'components/Example';
        root: path.resolve(__dirname, './src'),

        // allow us to avoid including extension name
        extensions: ['', '.js', '.jsx'],

        // required for enzyme to work properly
        alias: {
          'sinon': 'sinon/pkg/sinon'
        }
      },
      module: {
        // don't run babel-loader through the sinon module
        noParse: [
          /node_modules\/sinon\//
        ],
        // run babel loader for our tests
        loaders: [
          { test: /\.js?$/, exclude: /node_modules/, loader: 'babel' },
        ],
      },
      // required for enzyme to work properly
      externals: {
        'jsdom': 'window',
        'cheerio': 'window',
        'react/lib/ExecutionEnvironment': true,
        'react/lib/ReactContext': 'window'
      },
    },
    webpackMiddleware: {
      noInfo: true
    },
    // tell karma all the plugins we're going to be using to prevent warnings
    plugins: [
      'karma-mocha',
      'karma-chai',
      'karma-webpack',
      'karma-phantomjs-launcher',
      'karma-spec-reporter',
      'karma-sourcemap-loader'
    ]
  });
};

读书所有的表明五回或一遍推向领悟那么些 config 是做什么样的。使用 Webpack
的一大益处是全体都是普通的 JavaScript
代码,并且我们得以“重构”配置文件。事实上,那多亏绝大部分 starter kit
所做的!

乘胜 Karma 设置达成,为运行测试,末了一件事就是要去立异大家的
package.json:

# package.json
  "scripts" {
    "test": "node_modules/.bin/karma start karma.config.js",
    "test:dev": "npm run test -- --watch",
    "old_test": "mocha --compilers js:babel-register --require ./test/test_helper.js --recursive",
    "old_test:watch": "npm test -- --watch"
  }

本人提议重命名旧的测试 scripts 的前缀,用 ‘old_’ 表示。

最终的 package.json 是这么的:

{
  "name": "react-testing-starter-kit",
  "version": "0.1.0",
  "description": "React starter kit with nice testing environment set up.",
  "main": "src/main.js",
  "directories": {
    "test": "tests",
    "src": "src",
    "dist": "dist"
  },
  "dependencies": {
    "react": "^0.14.6",
    "react-dom": "^0.14.6",
    "yargs": "^3.31.0"
  },
  "devDependencies": {
    "babel-core": "^6.4.0",
    "babel-loader": "^6.2.1",
    "babel-polyfill": "^6.3.14",
    "babel-preset-es2015": "^6.3.13",
    "babel-preset-react": "^6.3.13",
    "babel-register": "^6.3.13",
    "chai": "^3.4.1",
    "enzyme": "^1.2.0",
    "json-loader": "^0.5.4",
    "karma": "^0.13.19",
    "karma-chai": "^0.1.0",
    "karma-mocha": "^0.2.1",
    "karma-phantomjs-launcher": "^0.2.3",
    "karma-sourcemap-loader": "^0.3.6",
    "karma-spec-reporter": "0.0.23",
    "karma-webpack": "^1.7.0",
    "mocha": "^2.3.4",
    "phantomjs": "^1.9.19",
    "phantomjs-polyfill": "0.0.1",
    "react-addons-test-utils": "^0.14.6",
    "sinon": "^1.17.2",
    "webpack": "^1.12.11",
    "webpack-dev-server": "^1.14.1"
  },
  "scripts": {
    "test": "node_modules/.bin/karma start karma.config.js",
    "test:dev": "npm run test -- --watch",
    "build": "webpack",
    "dev": "webpack-dev-server --port 3000 --devtool eval --progress --colors --hot --content-base dist",
    "old_test": "mocha --compilers js:babel-register --require ./test/test_helper.js --recursive",
    "old_test:watch": "npm test -- --watch"
  },
  "repository": {
    "type": "git",
    "url": "tbd"
  },
  "author": "Spencer Dixon",
  "license": "ISC"
}

在测试套件中外加 webpack
预处理,大家现在可以去除这几个在测试内烦人的相对路径声明:

// test/containers/Root.spec.js
import React from 'react';
import { shallow } from 'enzyme';
import Root from 'containers/Root';               // new import statement
// import Root from '../../src/containers/Root';  // old import statement

// test/components/CommentList.spec.js
import React from 'react';
import CommentList from 'components/CommentList';               // new import statement
// import CommentList from '../../src/components/CommentList';  // old import statement

import {
  describeWithDOM,
  mount,
  shallow,
  spyLifecycle
} from 'enzyme';

今天应用那个 starter kit 开发,你必要输入以下这几个命令去运作程序:

npm run dev         # note the addition of run
npm run test:dev    # note the addition of run

假设还有何不知道的地点,可以在 github
上查看该源码

结论

大家曾经创建了一个抓好的测试环境,可以根据你的档次具体需要去改变和进步。在下一回的篇章中,我将花越来越多的年月在更加现象的测试,还有何样测试
Redux,我更爱好 flux 的完结。

虽说自己只使用 React
开发了数月,但自我早就爱上它了。我愿意本课程可以扶持你更深远地领略一些
React 测试的特等实践。有其余难点或臧否随时联系自己。测试是大家的好情人!

初稿链接

相关文章

网站地图xml地图