react-routerのテストに関して

2015-04-14T00:00:00+09:00 JavaScript React.js

参考: https://github.com/rackt/react-router/blob/master/modules/components/__tests__/Link-test.js

react-routerを使ってのルーティング要件をテストしたい場合、TestLocationっていうのがある模様なのでそれを使っても出来るらしい

っていう事でさらっとやってみた

js/app.js

var React  = require("react"),
    Router = require("react-router"),
    routes = require("./routes");

Router.run(routes, function(Handler) {
  React.render(
    <Handler /> ,
    document.querySelector("#app")
  );
});

この部分はテストで書くのでスルーな方向で

js/routes.js

var React        = require("react"),
    Router       = require("react-router"),
    Route        = Router.Route,
    RouteHandler = Router.RouteHandler,
    DefaultRoute = Router.DefaultRoute,
    Top          = require("./Top"),
    User         = require("./User");

var Root = React.createClass({
  render: function() {
    return (
      <RouteHandler />
    );
  }
});

var routes = (
  <Route path="/" name="app" handler={Root}>
    <Route path="/user/:id" name="user" handler={User} />
    <DefaultRoute handler={Top} />
  </Route>
);

module.exports = routes;

/user/:idでUserハンドラーを作用させ、それを<Link>を使って転移出来るようにするだけなシンプルなルーティング定義なだけなので

js/Top.js

var React = require("react")
    Router = require("react-router"),
    Link   = Router.Link;

var Top = React.createClass({
  render: function() {
    return (
      <div>
        <Link to="user" params={% raw %}{{ id: 1 }}{% endraw %}>hoge</Link>
        <Link to="user" params={% raw %}{{ id: 2 }}{% endraw %}>fuga</Link>
      </div>
    );
  }
});

module.exports = Top;

上記でも書いたようにTopからは<Link>を使ってUserハンドラーが作用するURLへ転移する。でDynaminc Segmentationを使ってパラメーターを設定して取得できるような感じ

js/User.js

var React = require("react");

var User = React.createClass({
  contextTypes: {
    router: React.PropTypes.func
  },
  render: function() {
    var params = this.context.router.getCurrentParams();

    return (
      <span>user: {params.id}</span>
    );
  }
});

module.exports = User;

んまぁDynamic Segmentationなパラメーターを受け取ってレンダリングするだけ

まぁここまでが検証するアプリケーションの概要となるコード。でこの画面転移で描画されるデータを検証するテストを書く

js/_tests_/Router-test.js

jest.dontMock("../Top");
jest.dontMock("../User");
jest.dontMock("../routes");

var React        = require("react/addons"),
    TestUtils    = React.addons.TestUtils,
    Router       = require("react-router"),
    TestLocation = Router.TestLocation,
    routes       = require("../routes");


describe("Router", function() {
  it("route  test", function() {
    var div = document.createElement("div");
    var loc = new TestLocation(["/"]);
    var steps = [];

    steps.push(function() {
      TestUtils.Simulate.click(div.querySelector("a:first-child"), { button: 0 });
    });

    steps.push(function() {
      // 先のTest.Simulate.clickにより転移されたパスは/user/1であるかを検証
      expect(loc.getCurrentPath()).toEqual("/user/1");

      // Userがレンダリングするデータを検証
      expect(div.querySelector("span").textContent).toEqual("user: 1");

      // Topに戻る
      loc.replace("/");
    });

    steps.push(function() {
      TestUtils.Simulate.click(div.querySelector("a:last-child"), { button: 0 });
    });

    steps.push(function() {
      // 先のTest.Simulate.clickにより転移されたパスは/user/2であるかを検証
      expect(loc.getCurrentPath()).toEqual("/user/2");

      expect(div.querySelector("span").textContent).toEqual("user: 2");
    });

    Router.run(routes, loc, function(Handler) {
      React.render(<Handler />, div, function() {
        steps.shift()();
      });
    });
  });
});

画面が切り替わる毎にRouter.runな部分が動作するので事前に作っておいた<div>なDOMにReact.renderを行った後にテストステップを引き出して実行していくような感じでやれば出来る模様。まぁほとんど公式の参考コードを写経しただけですけど

てな感じでreact-routerを使ってルーティングよる画面転移に及ぶデータ検証的な感じで使えそうな感じも。ただこういうやり方した場合にテストステップ内で検証エラーが起きたりすると不要な部分の長いStackTraceまで出てしまうので若干何が原因かが特定しにくくなるんじゃないかと(個人差かも知れませんが)

んまぁもっとテスト方法が改善できる方法あればレポートするかと思いますんで

React.jsのCSSアニメーション jestのrunAllTimers/runOnlyPendingTimers