Jasmine tutorial

# 概要

Jasmineを使ってJavaScriptのテストを書くチュートリアル。rubyで動くjasmine gemを利用する。理由は下記

* ウェブサーバーがついているのでプロダクションアプリを起動しなくてすむ
* Firefox(selenium webdriver)との連携が容易

## testのスコープ

Jasmineでテストするのはあくまでユニットであり開発向けである。受け入れのテストとは分けて考えるべき

# 前準備

ruby1.9/2.0 とbundler

```
$ gem install bundler
```
2.0ではまったらトラブルシューティングの項を参照

# 準備

```ruby:Gemfile
source :gemcutter
gem 'rake'
gem 'jasmine'
```

```
$ bundle instal --path=vendor
```
pathはお好みで指定するべし


# ひな形の作成

```
$ bundle exec jasmine init
 ```

下記のようなファイルストラクチャができる

```
.
├── Gemfile
├── Rakefile
├── public
│   └── javascripts
│       ├── Player.js
│       └── Song.js
├── spec
│   └── javascripts
│       ├── PlayerSpec.js
│       ├── helpers
│       │   └── SpecHelper.js
│       └── support
│           └── jasmine.yml
````

jqueryとjasmine-jqueryを入れる

```
$ curl -O http://code.jquery.com/jquery-1.9.1.min.js
$ mv jquery-1.9.1.min.js public/javascripts/
$ curl -O  https://github.com/velesin/jasmine-jquery/edit/master/lib/jasmine-jquery.js 
$ mv jasmine-jquery.js spec/javascripts/helpers/
```
jasmine-jqueryを使うとfixturesやイベントのspyがやりやすくなる


# 試しに動かす

```
$ bundle exec rake jasmine
```
ウェブサーバーが立ち上がる。表示されたURLにブラウザでアクセスするとテストが実行され、全てグリーンになる。


## Selenium-Webdriverを使う場合

```
$ bundle exec rake jasmine:ci
```

firefoxが立ち上がって、サンプルのtestが実行されて全てグリーンならOK


## トラブルシューティング

rvmを使っててopensslがないエラー

```
$ brew install openssl
$ rvm requirements run
$ rvm uninstall 2.0.0-p0
$ rvm install 2.0.0-p0
```

Jasmine::YAMLなんてクラスないよってエラー
→ Rakefileとエラーしてるファイルの中でrequire 'yaml'と書いてしまう

# その１ シンプルなクラス (というかオブジェクト)

# 実装コード

## 脱線: モジュールパターンと継承 : 
JSのクラス設計はいくつか流派があるが今回はnewを使わないパターンで書く

```javascript
var sample = {}; // namespace

sample.base = function(params) {
   var  _name;
   if(typeof params === "object") {
     _name = params.name;
   } 

   function hello() {
       return "Hello! I'm " + _name;
    }
    return { hello : hello };
};

sample.foo = function (params) {
    var that = sample.base(params),
          _moo,_woo;

    function setWoo (woo) {
         _woo = woo;
    }
    that.setWoo = setWoo;

    function woo() {
         return _woo;
    }
    that.woo = woo;

    return that;
};

```
## テスト

```javascript
describe("sample.foo", function() {
    var foo;
     beforeEach(function() {
         foo = sample.foo({name: "John"});
     });

     it("should say hello", function (){
         var str = foo.hello();
         expect(str).toEqual("Hello! I'm John");
     });

     if("should set/get woo", function () {
          foo.setWoo("hoge");
          expect(foo.woo()).toEqual("hoge");
      });
});

```

# その２: DOMイベントを使ったもの

例えばオンマウスであるdivを表示されるなど

## 実装

```javascript 

sample.ui = function (params) {
  var that = sample.base(params);

  function init() {
      $("#foo").mouseover(function () {
          $("#notice").show();
      });
  }
  that.init = init;

  return that;
};

```

## フィクスチャー

`spec/javascripts/fixtures/`下にテストで使うhtmlを置く

```html:spec/fixtures/foo.html
<div id="foo">FOO!</div>
<div id="notice" style="display:none">don't mouse over me!</div>
```

## テスト

```javascript
describe("ui",function (){
    var ui;
    beforeEach(function(){
        loadFixtures("foo.html"); // fixtureをロード
        ui = sample.ui();
        ui.init(); 
    });

    it("should show notice",function() {
        expect($("#notice")).not.toBeVisible(); // 表示されていない
        $("#foo").trigger("mouseover");
        expect($("#notice")).toBeVisible(); // 表示されている
    })
});
```


## EventSpy