Flash Advent Calendar 1日目 - JavaScriptでの開発環境の構築 -

当時は`grunt`が主流で、`gulp`が出始めた頃でした。
JSで本格的な開発をするにあたってどちらで進めるか悩んだのですが
折角だから新しい`gulp`を使ってみようという安易な理由で`gulp`を選びましたw

また、当時はJSでテストを全然書いてなかったので
デグレに苦しめられていて。。。この機会にテスト駆動で開発してみようと思ったのも`gulp`を選んだ理由の一つでもあります。


# 目次
1. Node.jsを準備する
2. gulp & karmaを準備する


# 1 Node.jsを準備する
nvmでNode.jsは管理する
※バージョンが古いですが、2015年位のお話なので、悪しからず

```linux
cd ~
git clone https://github.com/creationix/nvm.git ~/.nvm
source ~/.nvm/nvm.sh
nvm install v8.9.3
nvm alias default v8.9.3
```
自分のhomeディレクトリにnvmをcloneして起動
macを起動した時に自動でNode.jsが起動するよう設定

```linux
vim ~/.bash_profile 

## 下記の設定を追記する
[[ -s ~/.nvm/nvm.sh ]] && . ~/.nvm/nvm.sh
nvm use default
npm_dir=${NVM_PATH}_modules
export NODE_PATH=$npm_dir

## 追記した内容を反映
source ~/.bash_profile
```

# 2 gulp & karma
グローバル`gulp`と`karma`をインストール

```linux
npm install -g gulp karma
```


プロジェクトに必要なpackageをインストール

|package|用途|
|:-----------------|:------------------|
|gulp|gulp本体|
|gulp-concat|複数のJSファイルを一個のJSにしてくれる|
|gulp-uglify-es|一個にまとめたJSをminfyする(es6対応)|
|karma|karma本体|
|karma-coverage|レポートを出すためのモジュール|
|karma-jasmine|karmaでjasmineを使えるようにする|
|karma-spec-reporter|コンソールを見やすくする|
|jasmine|jasmine本体|
|browser-sync|Browsersync本体|
|karma-chrome-launcher|Chromeでテスト|
|karma-firefox-launcher|FireFoxでテスト|
|karma-safari-launcher|Safariでテスト|


必要そうなパッケージをまるっとインストール

```linux
npm install browser-sync gulp gulp-concat gulp-uglify-es jasmine jasmine-core karma karma-chrome-launcher karma-coverage karma-firefox-launcher karma-jasmine karma-spec-reporter --save-dev
```


## gulpfile.jsを設定

```gulpfile.js
var gulp    = require("gulp");
var browser = require("browser-sync").create();
var concat  = require("gulp-concat");
var uglify  = require("gulp-uglify-es");
var Server  = require("karma").Server;

/**
 * server setting
 */
gulp.task("server", function ()
{
    browser.init({
        server: {
            baseDir: "./",
            index: "index.html"
        }
    });
});

/**
 * browser reload
 */
gulp.task("reload", function ()
{
    browser.reload();
});

/**
 * output js file
 */
gulp.task("output", function ()
{
    return gulp.src([
            "src/**/*.js"
        ])
        .pipe(concat("output.js")) // 複数のJSを一個にまとめる
        .pipe(uglify()) // 圧縮
        .pipe(gulp.dest(".")); // 圧縮したファイルを出力
});

/**
 * default setting
 */
gulp.task("default", ["server"], function ()
{
    gulp.watch(["src/**/*.js"], ["tdd"]);
    gulp.watch(["output.js"], ["reload"]);
});

/**
 * test-driven development
 */
gulp.task("tdd", function (done)
{
    new Server({
        configFile: __dirname + "/karma.conf.js",
        singleRun: false
    }, done)
        .on("run_complete", function (browsers, results)
        {
            if (results.failed) {
                throw new Error("failed");
            }
            gulp.start.apply(gulp, ["output"]);
        })
        .on("error", function (err) {
            done(err);
        })
        .start();
});

/**
 * Run test once and exit
 */
gulp.task("test", function (done)
{
    new Server({
        configFile: __dirname + "/karma.conf.js",
        singleRun: true
    }, done).start();
});
```

## karma.conf.jsを設定

```karma.conf.js
// Karma configuration
// Generated on Wed Sep 06 2017 20:07:29 GMT+0900 (JST)

module.exports = function(config)
{
  config.set({

    // base path that will be used to resolve all patterns (eg. files, exclude)
    basePath: '',


    // frameworks to use
    // available frameworks: https://npmjs.org/browse/keyword/karma-adapter
    frameworks: ['jasmine'],


    // list of files / patterns to load in the browser
    files: [
        "src/**/*.js",
        "test/**/*.js"
    ],


    // list of files to exclude
    exclude: [
    ],


    // preprocess matching files before serving them to the browser
    // available preprocessors: https://npmjs.org/browse/keyword/karma-preprocessor
    preprocessors: {
        'src/**/*.js': ['coverage']
    },


    // test results reporter to use
    // possible values: 'dots', 'progress'
    // available reporters: https://npmjs.org/browse/keyword/karma-reporter
    reporters: ['spec', 'coverage'],


    coverageReporter: {
      type: 'html',
      dir: 'coverage/'
    },


    // web server port
    port: 9876,


    // enable / disable colors in the output (reporters and logs)
    colors: true,


    // level of logging
    // possible values: config.LOG_DISABLE || config.LOG_ERROR || config.LOG_WARN || config.LOG_INFO || config.LOG_DEBUG
    logLevel: config.LOG_INFO,


    // enable / disable watching file and executing tests whenever any file changes
    autoWatch: true,


    // start these browsers
    // available browser launchers: https://npmjs.org/browse/keyword/karma-launcher
    browsers: ['ChromeHeadless', 'FirefoxHeadless'],


    // Continuous Integration mode
    // if true, Karma captures browsers, runs the tests and exits
    singleRun: false,


    // Concurrency level
    // how many browser should be started simultaneous
    concurrency: Infinity
  });
};
```

これで準備完了です。

起動コマンド

```linux
gulp
```

テストだけを起動

```linux
gulp test
```

今になってですが、本当にこの時にテスト駆動を導入してよかったと思います。
複数人で開発ができたのも、テストでデグレが起きにい状況だったからと思います。

今日の記事は下記の記事の抜粋となります。

[gulp + karmaでテスト駆動開発](https://qiita.com/ienaga/items/cfe3a596c9e5b7e675ed)
[ChromeとFireFoxのHeadless機能を使ってブラウザーテスト駆動開発](https://qiita.com/ienaga/items/7a215c7081e2045d172c)

明日は実際にどのようなテストケースを書いてるかを記事にできたらと思います。