ぼくのかんがえたさいきょうのnpm test

この記事は自身への備忘録と共にテスト駆動するのに便利なんじゃないかという普段使う`npm test`の中身を簡単な説明付きで書きます。

対象は気軽にテストをしながらサーバで直接開発したい人向け。
タスクランナーとかには触りませんがうちはこうしてるよってのあれば教えてください！！！！！

# package.json

まずは使ってるpackage.jsonの中身。

```json:package.json
{
  "scripts": {
    "test": "npm run lint && npm run cover",
    "lint": "eslint *.js",
    "_comment": "istanbulコマンドでmochaも実行している",
    "cover": "NODE_ENV=test istanbul cover --report text _mocha",
    "mocha": "NODE_ENV=test mocha"
  },
  "devDependencies": {
    "eslint": "^2.5.3",
    "istanbul": "^0.4.3",
    "mocha": "^2.4.5",
    "should": "^8.3.0"
  }
}
```

### scripts
scriptsに書いてあるキー名で`npm run [キー名]`を実行するとそのキー名の内容が直接shellとして実行されます。
一部キー名には…例えば`test`など使用する時は`npm test`のように`run`を省略できます。
この省略できるキー名に集約する形でコマンドを複数個書けばまとめて実行できて大変便利だと思います。

その他`npm-scripts`の仕様については[公式サイト](https://docs.npmjs.com/misc/scripts)をご覧下さい。

### devDependencies

通常のライブラリとして使うわけではないけどテスト実行したりグローバルには必要ない場合は`--save-dev`でインストールしてここに追記します。
テストやタスクランナーなど`npm-scripts`で使うツール類はここに入れておくのが良いと思います。
`npm-scripts`で実行する際に自動的に`node_modules/.bin`へPATHが追加されるのでツールのPATHなど気にしないで`npm-scripts`で実行できます。

## npm test

```
npm run lint && npm run cover
```

`npm test`での中で`npm run lint`と`npm run cover`を`&&`でつなぐことで`npm run lint`が成功しないと`npm run cover`が実行されないようになっています。
shellのワンライナーで書く時の小技ですが便利です。

### npm run lint

```
eslint *.js /lib/*.js
```
ご存知ECMAScriptなどのRuluも有る上に独自Ruleも作れちゃうという便利なコード規約ツール！
[ESLint](http://eslint.org/)様です。
皆崇め奉れ（横暴

コマンドだけ書いてますが[Rulu](http://eslint.org/docs/rules/)のOnOffを書いた`.eslintrc`が必要です。
package.jsonにもRuleは書けるけど`vim`の`syntastic`でも使えるように`.eslintrc`です。

以下サンプルで自分で使ってるRuleです。
複数人いるプロジェクトだと宗教戦争になりかねないので[Best Practices](http://eslint.org/docs/rules/#best-practices)あたりを起点に話し合うと良いんじゃないでしょーか。
これも「うちはこうしてるよー」てのはあれば是非教えて下さい

```json:.eslintrc
{
    "extends": "eslint:recommended",
    "env": {
      "node"    : true,
      "mocha"   : true,
      "es6"     : true,
      "browser" : true
    }, "rules" : {
      /***
       *** Rule Document : http://eslint.org/docs/rules/
       ***/
      "camelcase" : ["error", {             // キャメルケース強制
        "properties" : "always"
      }],
      "require-jsdoc" : ["error", {         // JSDocを記述するように強制
        "require": {
            "FunctionDeclaration": true,
            "MethodDefinition": true,
            "ClassDeclaration": true
        }
      }],
      "valid-jsdoc" : ["error", {           // JSDoc形式で型を表現を強制
        "requireReturn": false,
        "preferType": {
          "String": "string",
          "Object": "object",
          "Number": "number",
          "Function": "function",
          "Void": "void",
        }
      }],
      "quotes" : ["error",                   // シングルクオートの強制
                  "single",
                  "avoid-escape"
      ],
      "key-spacing": ["error", {             // JSONオブジェクトのキー名との間にスペースをいれるかどうか
        "singleLine" : {       // 一行の場合
          "beforeColon": true,
          "afterColon": true
        },
        "multiLine" : {        // 複数行の場合
          "beforeColon": true,
          "afterColon" : true,
          "align"      : "colon"
        }
      }],
      "no-magic-numbers": ["error", {        // 変数に代入されていない値の使用禁止
        "ignoreArrayIndexes": true
      }],
      "eqeqeq"          : "error",           // === !==など比較演算子にはより厳密性の高い演算子の強制
      "block-scoped-var": "error",           // ブロックスコープ内でのvar宣言を禁止
      "complexity"      : ["error", {        // 循環的複雑度の最大値強制
        "maximum": 4
      }],
      "curly": "error",                      // 括弧の強制。つけないでif,whileなど禁止
      "default-case": "error",               // switch構文でdefaultを強制
      "dot-location": ["error", "property"], // ドットの位置を強制
      "guard-for-in": "error",               // for-in内でのkeyをhasOwnPropertyでチェックするのを強制
      "no-eval": "error",                    // eval禁止
      "block-spacing": "error",              // ブロック内側のスペースを強制
      "brace-style": "error",                // http://eslint.org/docs/rules/brace-style
      "comma-spacing": ["error", {           // カンマの後ろに空白を強制
        "before" : false,
        "after"  : true
      }],
      "id-length": ["error", {               // 変数名の文字列長の強制
        "min": 2,
        //"max": 16, // 最大文字列長なし。
        "properties": "never",
        "exceptions": []   //除外変数名
      }],
      "indent": ["error", 2],                // インデント2個ずつの強制
      "space-before-function-paren": [       // 関数とブロックの間のスペースを強制
        "error",
        "never"
      ],
      "space-before-blocks": "error",        // ブロックの前にスペースを強制
      "prefer-const": "error",               // 一度も変更されていない宣言をconstに強制
      "no-var": "error",                     // varによる宣言禁止
      "arrow-body-style": ["error"],         // ()=>{}アロー関数スタイル
      "arrow-spacing": "error",              // アロー関数の前後にスペースを強制 () => {}
      "strict": ["error"],                   // 'use strict';を強制
      "no-warning-comments": ["warn", {      // コメント内のワードを検出し警告
        "terms": [ //検出ワードリスト
          "todo",     //あとで手を付ける
          "fixme",    //既知の不具合がある
          "hack"      //あまり綺麗じゃない解決策
        ],
        "location": "anywhere"
      }],
      "semi":["error"],                      // セミコロンの強制
    }
}
```

### npm run mocha

```
NODE_ENV=test mocha
```

肝心のテストツールの`mocha`です。
`mocha`の使い方は簡単。
プロジェクトルートに`test`ってディレクトリを作成してその配下にテストを書いたJavascriptを置いておくだけ。
上記の簡単なコマンドで実行可能です。
Express4だと`NODE_ENV=test`にしておくことで余計な標準出力が軽減されたりするので入れてます。

`mocha`の記事は多いので多くは語りません。

### npm run cover

```
NODE_ENV=test istanbul cover --report text _mocha
```

カバレッジリポートツールの`istanbul`です。
`mocha`と連動させてます。

`--report text`を付加すると各ファイルごとの細かいカバレッジが標準出力されます。
リポートに`--report html`を追加するとcoverageディレクトリにHTML吐いてくれるのでGUIで開発してる人にはこちらのreportのがいいかもしれませんね。

`istanbul`で`_mocha`(mocha入れると付いてくるバイナリ。カバレッジツール用？)を実行。
動作は通常の`mocha`と変わらないので通常通りテスト実行結果を出力してくれます。
実行結果出力後各テストで使用したモジュールたちのカバー率が表示される形になります。
サンプル![無題.png](https://qiita-image-store.s3.amazonaws.com/0/81557/4e4664cb-afd4-0948-0e1c-149e9d80581e.png)

うわっ………私のカバレッジ低すぎ…？

# 最後に

他の人は`npm test`にどんな夢を詰めているんだろうと思ってしまって仕方がないのでまずは自分を出してみました。
是非皆さんの「さいきょうの`npm test`」を教えてください。



ビルドとかも考えられたこちらの記事おすすめです。
[ぼくのかんがえたさいきょうのES6プロジェクトテンプレート](http://qiita.com/mohayonao/items/9b0655b8b4979bffda31)

gulpやgruntなんていらんかったんや！npm-scriptsの使い方を詳細に説明されてたので参考になりました
[[意訳]私がGulpとGruntを手放した理由](http://qiita.com/chuck0523/items/dafdbd19c12efd40e2de)