ember-railsとember-mochaとTeaspoonでTDDなフロントエンド開発環境をつくる


## はじめに

emberはフロントエンドフレームワークですが、そのままで使うよりember-cliというコマンドラインツールでrailsの様に開発するのがベストな方法と言えます。

### ember-cliの利点

- es6で書ける
- 命名規約があるのでファイル名が統一される
- その他のフロントエンド開発のようにnpmとかbowerの資産を使えるビルドシステムが備わっている
- ユニットテストが書きやすい

等があります。

僕はこの中ではテストが書きやすいというのが大きいと思います。
どうしてもフロントエンドのユニットテストというとmodelばかりでviewに近くなるとcapybara等でインテグレーションテストになることが多いと思いますが、やはりユニットテストがかけると開発のモチベーションやメンテナンス性が違うと思うからです。

### ember-railsの利点

しかしながら、ember-cliはフロントエンド単体の開発には適していますがrailsを使った既存のwebアプリに組み込むとなると、追加でフロント用のサーバーを立てたり、API認証の仕組みを入れたり、いろいろ面倒です。
そんな時に便利なのがember-railsです。

- ember:bootstrap等のジェネレーターがある(componentやmodel用のもあります)
- railsのエコシステムに乗れるので今までのjavascriptの扱いとさほど変わらない

等が利点だと思います。

これでrailsのフロントエンド開発にemberを簡単に使えるんですが、特に公式のREADMEにはテストについては言及されていないです。
ember-cliでは手厚くテストがサポートされている感じなのに、rails環境で出来ないなんてもったいないので調べてみました。

## ember-mocha

まずはテストフレームワークについて、公式のフレームワークとしてはember-qunitが推奨されていますがember-mochaを使うという選択肢もあります。
railsのテストではrspecを使っているので似たような感じで書けるmochaが使えると嬉しいところです。

ということでember-mochaを使うことにしました。
しかし、ember-qunitでも同じように導入できると思います。

railsで使うためにはrails-assetsを利用します

```Gemfile
+ source "https://rails-assets.org"

  group :development, :test do
+   gem 'rails-assets-ember-mocha'
  end
```

## Teaspoon

Teaspoonはrailsのjavascriptユニットテストにとても便利なgemです。
始め方も簡単で以下のようにすれば環境が整います。

```Gemfile
  group :development, :test do
    gem 'rails-assets-ember-mocha'
+   gem 'teaspoon'
  end
```

```bash
$ bundle install
$ bin/rails generate teaspoon:install --framework=mocha --coffee
```

これで必要なディレクトリとファイルが揃いまいした。

## spec/javascripts/spec_helper.coffee

正直環境を作ると言ってもここのファイルにちょこっとコードを書き足すだけです
デフォルトのコメントが長いので省略していますが以下のようにすればokです

```coffeescript:spec_helper.coffee
# require support/expect
# require support/sinon
#= require support/chai
# require support/your-support-file
#
#= require application
#= require ember-mocha/ember-mocha

window.expect = chai.expect

window.setupApplication = ->
  setResolver(Ember.DefaultResolver.create(namespace: App))

setupApplication()

App.setupForTesting()
```

## Componentのテスト

App.XHogeComponentというcomponentがある場合は

spec/javascripts/components/x-hoge_spec.coffee というファイルを作成して以下のように書きます

```handlebars:components/x-hoge.hbs
# templateはこのようになっているとする
<span>{{item.name}}</span>
```

```coffeescript:x-hoge_spec.coffee
describeComponent 'x-hoge', 'XHogeComponent', {
 needs: ['template:components/x-hoge']
}, ->

  beforeEach ->
    @item = Ember.Object.create(name: 'sample name')
    @component = @subject()
    Ember.run =>
      @component.set('item', @item)
      @component.appendTo('#ember-testing')
    
  afterEach ->
    @component.destroy()

  it 'is exists', ->
    expect(@$().text()).to.equal('sample name')
```

@subject()という関数の戻り値で対象のcomponentのインスタンスが返ってきますのであとはpropertyをsetする等はEmber.run()の中にクロージャを渡して実行させます。

viewのテストが公式ドキュメントに載っていないのはなぜだろう？と悩んでいたのですが、viewは基本使わずにcomponentのみで実装する方がいいみたいですね

参考：https://speakerdeck.com/tomdale/ember-2-dot-0-in-practice?slide=27


## 複数のApplicationがある場合

複数のEmber.Applicationを作成している場合は```setupApplication```にあたるものを複数作成しておいて各テストファイルの```beforeSetup```の中で呼び出すようにします

```coffeescript:spec_helper.coffee
window.setupHoge = ->
  setResolver(Ember.DefaultResolver.create(namespace: Hoge))
  
window.setupFuga = ->
  setResolver(Ember.DefaultResolver.create(namespace: Fuga))
```

Hoge.XHogeComponentのテストの場合

```coffeescript:x-hoge-component_spec.coffee
describeComponent 'x-hoge', 'XHogeComponent', {
  needs: ['template:hoge/components/x-hoge'],
  beforeSetup: -> setupHoge()
}, ->

  beforeEach ->
    @component = @subject()

  it 'is exists', ->
    expect(@component).to.be.ok
```

## Teaspoonでテストを走らせる

localhost:3000/teaspoonにアクセスすると通常のブラウザで実行できるようですが、CIする場合のコマンドはこちらです

```
$ RAILS_ENV=test bin/rake teaspoon
```

RAILS_ENV=testを指定しておかないとdevelopmentで動作するので注意が必要です。

## まとめ

テストもきっちり書けるemberがよく出来ているので素材を組み合わせるだけですが、Backbone.js等で辛くなりがちがユニットテストが書けるのはいいですね。