Vue.js入門 ―最速で作るシンプルなWebアプリケーション

第6回 Vue.jsの高度なアプリケーション開発

この記事を読むのに必要な時間:およそ 8.5 分

テスト

実際のアプリケーション開発においては単体テスト,E2Eテストをすることでアプリケーションが正しく動作しているかどうか検証を行います。単体テストとE2Eテストの環境が今回は既にセットアップされているのですぐに着手できます。Vue.jsにおけるコンポーネントの単体テストを試してみましょう。

$ npm run unit

このコマンドを実行すると,セットアップされたKarmawebpackおよびPhantomJSといったツールや実行環境によってtest/unit/配下にある単体テストコードが実行されテスト結果が出力されます。以下はその内容のテスト結果の部分抜粋です。

  Hello.vue
    ✗ should render correct contents
        null is not an object (evaluating 'vm.$el.querySelector('.hello h1').textContent')
        webpack:///test/unit/specs/Hello.spec.js:10:45 <- index.js:165:46

テストが失敗していることがわかります。これは,vue-cliによって初期セットアップされたHelloコンポーネントの単体テストの実行結果です。解説にあたってHelloコンポーネントの実装内容を変更したので,それにともなってテストが失敗しています。

ここで変更したHelloコンポーネントの動作内容を検証する単体テストを実装してみましょう。エディタでtest/unit/specs/Hello.spec.jsを開いて以下のように単体テストを実装します。

// Vue.js本体とHelloコンポーネントをインポートする
import Vue from 'vue'
import Hello from 'src/components/Hello'

describe('Helloコンポーネント', () => {
  it('デフォルトメッセージが正しく描画されていること', () => {
    const Ctor = Vue.extend(Hello)
    const vm = new Ctor().$mount()
    expect(vm.$el.textContent).to.equal('メッセージ: こんにちは!')
  })

  it('msgプロパティで指定した文字列値で正しく描画されていること', () => {
    const Ctor = Vue.extend(Hello)
    // 初期プロパティ値の変更は,propsData経由で行う
    // 公式ドキュメントを参照: https://jp.vuejs.org/v2/api/#propsData
    const vm = new Ctor({ propsData: { msg: 'ようこそ!' } }).$mount()
    expect(vm.$el.textContent).to.equal('メッセージ: ようこそ!')
  })

  it('親コンポーネント経由でmsgプロパティに指定された文字列で正しく描画されていること', done => {
    const vm = new Vue({
      data: { message: '' },
      components: { Hello },
      // render関数で実装されている内容は
      // templateオプションに'<hello :msg="message"></hello>'に指定するのと同義
      render (h) { return h('hello', { props: { msg: this.message } }) }
    }).$mount()
    // マウント後,コンポーネントの状態値(props/data)の変更に対するDOMの更新検証は,
    // 非同期に更新されるため,Vue.nextTickを使用する
    vm.message = 'ようこそ!'
    Vue.nextTick(() => {
      expect(vm.$el.textContent).to.equal('メッセージ: ようこそ!')
      done()
    })
  })
})

上記の単体テストコードは,本稿のvue-cliでセットアップされたMochaChaiという単体テスト向けのライブラリを使用しています。

いくつかDOMを操作するブラウザ環境に依存したコードが入っていますが,それ以外はNode.jsでも実行できるシンプルな単体テストになっていて難しくはありません。Helloコンポーネントは単一ファイルコンポーネントで実装されており,オブジェクトに変換されるので,公式ドキュメントに従って上記の単体テストの実装のようにコンポーネントをインポートして,動作を検証するコードを実装するだけです。

単体テストを実装したので,npm run unitコマンドで検証してみましょう。以下に抜粋するような検証がパスしているテスト結果が出力されることを確認できましたでしょうか?

  Helloコンポーネント
    ✓ デフォルトメッセージが正しく描画されていること
    ✓ msgプロパティで指定した文字列値で正しく描画されていること
    ✓ 親コンポーネント経由でmsgプロパティに指定された文字列で正しく描画されていること

PhantomJS 2.1.1 (Mac OS X 0.0.0): Executed 3 of 3 SUCCESS (0.02 secs / 0.012 secs)
TOTAL: 3 SUCCESS

今回は単体テストのみでしたが,Nightwatchを利用したE2Eテストも可能になっています。今回は解説しませんが,こちらも初期のテストコードがtest/e2e/specs配下にセットアップされているので,こちらにテストを実装してアプリケーションの動作検証をするとよいでしょう。

デバッグ

JavaScriptによるフロントエンドのアプリケーション開発においてデバッグにはいろいろ方法がありますが,そのうちの1つとしてコンソール出力(console.log)による,いわゆるプリントデバッグがあります。しかしながら,Vue.jsにおいてはコンポーネントの組合せによってツリー構造をもったUIとしてアプリケーションが構築されるため,この方法では非常に非効率です。Vue.jsは公式にvue-devtoolsというGoogle Chrome向けに拡張機能を提供しています。これを利用するとデバッグの効率が大きく上昇するでしょう。

本稿で作成しているアプリケーションをvue-devtoolsでデバッグしているときの画面の様子は図4のようになります。

図4 vue-devtools

図4 vue-devtools

上記のようにvue-devtoolsは,Web開発者がよく使用するDevtoolsに統合されておりVue.jsのコンポーネントをツリー形式でグラフィカルに確認することができます。また,コンポーネントの状態値(コンポーネントオプションのprops/data)の値も確認することができるため大変便利です。Vuexにも対応しているので,Vuexのstoreのデバッグも対応可能です。vue-devtoolsを利用してVue.jsアプリケーションのデバッグの生産性を高めることをお勧めします。

ビルド

単一ファイルコンポーネントを実装し,単体テストによるコンポーネントの動作検証,デバッグを学びました。いよいよリリースするためにビルドを行います。

一般にJavaScriptによるフロントエンドエンドのアプリケーションはビルドにwebpackやbrowserifyなどのツールを使用します。これらを使うことでJavaScriptはもちろん,HTML,CSSそして画像/フォントなどのアプリケーションの動作に必要なリソース一式をリリース可能なアセットとしてバンドリングできます。こういったリソースのバンドリングはいかにツールを使ったとしても,Babelなどのトランスパイラの設定,JavaScriptコードのミニファイ化/ソースマップ出力,警告メッセージをはじめとするデバッグコードの除去などの諸々の設定が必要になります。多くの場合は大変な作業です。

vue-cliで生成したVue.jsアプリケーションプロジェクトは,こういったビルドに必要なための設定作業がほぼゼロになるようになっています。具体的には,ビルド設定ファイルおよびビルドスクリプトをwebpack/browserifyのツールに応じてbuildディレクトリ配下に出力します。このため設定作業の必要はなく,すぐビルドできます。

それでは以下のコマンドでビルドしてみましょう。

$ npm run build

ビルド結果内容をビルドが完了し,結果が出力されます(出力メッセージ内容は実行環境によって異なります)⁠

  Tip:
  Built files are meant to be served over an HTTP server.
  Opening index.html over file:// won't work.

⠋ building for production...cp: no such file or directory: static/*
Hash: 9c4ed13ce128ce3a2c03
Version: webpack 1.14.0
Time: 9823ms
                                                  Asset       Size  Chunks             Chunk Names
             static/js/manifest.c2ec5fc9f5c8f45dafe2.js  832 bytes       0  [emitted]  manifest
                  static/js/app.357c6f5c0fd1d34a3280.js    10.7 kB    1, 0  [emitted]  app
               static/js/vendor.db94a67cc8fd496820cf.js    74.2 kB    2, 0  [emitted]  vendor
    static/css/app.8d55793912407d0c8dcc48d76dc73b3b.css  259 bytes    1, 0  [emitted]  app
         static/js/manifest.c2ec5fc9f5c8f45dafe2.js.map    8.86 kB       0  [emitted]  manifest
              static/js/app.357c6f5c0fd1d34a3280.js.map    29.7 kB    1, 0  [emitted]  app
static/css/app.8d55793912407d0c8dcc48d76dc73b3b.css.map  660 bytes    1, 0  [emitted]  app
           static/js/vendor.db94a67cc8fd496820cf.js.map     604 kB    2, 0  [emitted]  vendor
                                             index.html  450 bytes          [emitted]

上記コマンドで,アプリケーションのリソース一式がビルドされたアセットはdistディレクトリに出力されます。こうしてビルドされたアセットを,Vue.jsアプリケーションとしてHTTPサーバにデプロイして配信可能になります。

著者プロフィール

川口和也(かわぐちかずや)

株式会社 CUUSOO SYSTEM 最高技術責任者。

Vue.jsコアチームメンバーとしてVue.js関連のOSS活動を積極的に行っている。日本Vue.jsユーザーグループvuejs-jpの代表であり,国内の普及啓もう活動も進めている。最近は自称emojineerとしてemojiを使ったソフトウェア開発プロセスにも関心がある。

GitHub:kazupon
Twitter:@kazu_pon