前回の続き。それではテストを書いてみましょう。テストするにもテストするモジュールがないので(「こんちは!」のテストをしてもしょうがない)、なにか簡単なアプリをつくってみましょう。今回はショップカートを作ってみることにします。

調味料を販売するショップサイトを想定してみます。サイトのトップページにアクセスすると、取り扱い中の調味料がずらりと表示され、ユーザーがカートに入れて商品を選べる、とりあえずそこまでのスペックを設計して、モジュールとして実装してみましょう。

スペックはspecフォルダに書きます。

~/tutorials/project% mkdir spec && cd spec

スペックファイルの命名規則は、とりあえずモジュール名Spec.coffeeにしてみます。karmaからテストを行う際に、このファイル名のルールに従って自動的にスペックファイルが読み込まれテストが実行されます。

ショップカートのサイトですので、とりあえず「ショーケース(showcase)」と「カート(cart)」のモジュールを作ることにします。この二つのモジュールのスペックをそれぞれshowcaseSpec.coffeecartSpec.coffeeファイルで設計してゆきましょう。具体的なモジュールの実装はこのスペックファイルを書きながら同時進行で進めていきます。まずは思いつくままに書いてみます。

#showcaseSpec.coffee

showcase= require "showcase"
describe "showcase", ->
  it "1. 取り扱い中のアイテムの一覧を表示する"
  it "2. 各アイテムの行にはタイトルとデフォルトの数量と金額を表示する"
  it "3. アイテムを選択するとカートに商品が入り、ショーケース内の商品の数量がひとつ減る"
  it "4. 数量指定のない商品についてはいくつでもカートに入れられる"
  it "5. カートに入れられる商品の上限はデフォルト数量までとする"
#cartSpec.coffee

cart= require "cart"
describe "cart", ->
  it "1. カートの中は最初は空である"
  it "2. 商品がカートに入れられたらそのタイトルごとに分類しリスト表示し、それぞれの数量を表示する"
  it "3. カートの中身が変わるごとに合計金額を更新して表示する"
  it "4. あるタイトルのアイテムの数量を変更すると、それに応じてショーケースのアイテムの数量も更新する"
  it "5. あるタイトルのアイテムを一括して削除することができる"
  it "6. 中身を空にすることができる"

ここで、モジュールの名前解決のルールをwebpackに伝えておきましょう。

#webpack.config.coffee
path= require "path"

module.exports= 
  #中略#
  resolve:
    extensions: ["", ".coffee", ".js"]
    root:[path.resolve "./app"]

こうすることで、./appディレクトリがモジュール探索のルートとして新たに追加されます。また、requireする際に、拡張子.coffeeも省略できます。

もう一つ、webpackの設定を追加しておきます。今回は多くのモジュールがBackbone.jsに依存するので、モジュール内に自動的にbackboneモジュールが読み込まれるようにwebpackを設定します(ついでにunderscoreとjqueryも入れておきます)。これにはwebpackのビルトインプラグインのProvidePluginを使用します:

#wepback.config.coffee
path= require "path"
webpack= require "webpack"

module.exports= 
  #中略#

  plugins:[
    new webpack.ProvidePlugin
      $: "jquery"
      Backbone: "backbone"
      _: "underscore"
  ]

こうすると、”Backbone”という名前の変数には、自動的にbackboneモジュールのexportsがアサインされますので、モジュール内でrequireする必要がなくなります。

設計に戻ります。

showcaseSpec.coffeeで具体的にモジュールを設計してゆきます。
今回はBackbone.jsを使いますので、showcaseモジュールには、ビューオブジェクト(showcase.view)と、コレクションオブジェクト(showcase.items)を1つずつ用意しておけばよさそうです。“1. 取り扱い中のアイテムの一覧を表示する”は、showcase.collectionをリセットしたときの状態、ということになりそうです。

なにかしらリセットするためのデータが必要なようです。テスト用のダミーデータはspec/fixture.yamlの中に準備しておき、テストの度に使用することにしましょう。showcaseSpec.coffeeでbeforeEach関数を呼んでおきます:

#showcaseSpec.coffee
showcase= require "showcase"
beforeEach -> @fixture= require "./fixture.yaml" #追加
describe "showcase", ->
 it "1. 取り扱い中のアイテムの一覧を表示する"
 #....


spec/fixture.yamlは以下

#spec/fixture.yaml
blackPepper:
 title: 胡椒
 status: true
 price: 300
 amount: 20
kumin:
 title: クミン
 status: true
 price: 400
 amount: 3
coriander:
 title: コリアンダー
 price: 450
 amount: 8
turmeric:
 title: ターメリック
 status: true
 price: 250
cayennePepper:
 title: カイエンヌペッパー
 status: true
 price: 280
 amount: 0
cardamon:
 title: カルダモン
 status: false
 price: 420

ここで、yamlデータをバンドルに含める必要が出てきました。yaml-loaderとjson-loader(あ、これは前回いれてますね)をインストールし、webpackにその旨伝えておきましょう:

% npm i -D yaml-loader json-loader
#webpack.config.coffee
loaders:[
  {test: /\.coffee$/, loader:"coffee"}
  {test: /\.yaml$/, loader:"json!yaml"}#これを追加
]

上のloadersの2行目は「.yamlファイルはyaml-loaderでjson形式に変換しそれをjson-loaderでjs形式に変換してロードする」という意味になります。ローダーは!でチェーンできるわけですね。

さらに、"1. 取り扱い中のアイテムの一覧を表示する"の詳細な仕様を書いておきましょう:

showcaseSpec.coffeeは以下のようになりました:

#showcaseSpec.coffee
showcase= require "showcase"
beforeEach ->@fixture= require "./fixture.yaml" 
describe "showcase", ->
  it "1. 取り扱い中のアイテムの一覧を表示する", ->
    availableItems= _.filter (_.values @fixture), (item)->item.status is on
    showcase.items.reset availableItems
    assert showcase.items.length > 0 #なにかしらアイテムは必ず表示される
    assert showcase.items.every (item)->item.status is on #表示されるアイテムは全て取り扱い中である
  it "2. 各アイテムの行にはタイトルとデフォルトの数量と金額を表示する"
  it "3. アイテムを選択するとカートに商品が入り、ショーケース内の商品の数量がひとつ減る"
  it "4. 数量指定のない商品についてはいくつでもカートに入れられる"
  it "5. カートに入れられる商品の上限はデフォルト数量までとする"

今度はshowcaseモジュールを書いてみましょう。app/showcase/index.coffeeに書きます:

#app/showcase/index.coffee
class Item extends Backbone.Model
 defaults:
   status: off
class Collection extends Backbone.Collection
 model: Item
module.exports.items= new Collection

cartモジュール(app/cart/index.coffee)はからっぽにしておきます:

#app/cart/index.coffee
module.exports={}

、、、これでひとまず、スペックとモジュールが最低限そろいました。

テストはkarmaコマンドを使って行います。karmaはwebpack同様設定ファイルで細かい設定が出来ますので、そちらを書いておきましょう。ファイル名はデフォルトでkarma.conf.coffeeです(注:webpackは「webpack.config.coffee」です、間違えやすいです!!)、webpack同様プロジェクトのルートに置きます:

#~/tutorials/project/karma.conf.coffee
module.exports= (config)->
  config.set
    frameworks: ["mocha"]
    files:["spec/**/*Spec.coffee"]
    preprocessors:
      "spec/**/*Spec.coffee":["webpack"]
    webpack: require("./webpack.config.coffee")
    browsers:["PhantomJS"]

さて!これで、やっとテストを起動できそうです。次回に・・・。