鈍足ランナーのIT日記

走るのが好きな5流のITエンジニアのブログ。

趣味の範囲は広いけど、どれも中途半端なクソブロガー楽しめるWebアプリを作ってあっと言わせたい。サーバーサイドPerl(Mojolicious)、クライアントサイドVue.js。Arduinoにも触手を伸ばす予定。

vscode+jestでユニットテスト(デバッグ)

ndenv環境を使っているので設定を変更(.vscode/launch.json)

{
    "version": "0.2.0",
    "configurations": [
        {
            "type": "node",
            "request": "launch",
            "name": "Launch Program",
            "program": "${workspaceRoot}/node_modules/jest/node_modules/.bin/jest",
            "runtimeArgs": ["--inspect-brk"],
            "args": ["--runInBand", "--verbose", "--config=${workspaceRoot}/test/unit/jest.conf.js"],
            "runtimeExecutable": "${env:HOME}/.ndenv/shims/node",
            "console": "integratedTerminal",
            "internalConsoleOptions": "neverOpen"
        }
    ]
}

console出力しないと慌てたけれど

こちらにサンプルがありましたとさぁ。

github.com

vuexを使ったコンポーネントのテスト

頭の中はテストのことでいっぱいです。

medium.com

vuetify.jsを使ったアプリの単体テスト

v-textfield

idをつけた要素がそのまま、input要素にマッピングされるためにテストは素直にかける

<v-text-field id="name" v-model="name" required></v-text-field>
  <div class="input-group input-group--dirty input-group--required input-group--text-field primary--text">
    <div class="input-group__input">
      <input id="name" required="required" tabindex="0" type="text">
    </div>
    <div class="input-group__details">
      <!---->
    </div>
  </div>

v-checkbox

idをつけた要素が見当たらないし、input要素にマッピングされないため要素の特定が難しい

<v-checkbox id="flag" v-model="flag"></v-checkbox>
  <div tabindex="0" role="checkbox" aria-checked="false" class="input-group checkbox input-group--selection-controls accent--text">
    <div class="input-group__input">
      <i aria-hidden="true" class="icon icon--selection-control material-icons">check_box_outline_blank</i>
      <div class="input-group--selection-controls__ripple"></div>
    </div>
    <div class="input-group__details"><!----></div>
  </div>

テストコード

とりあえずこんな按配でコードを書いた。(avoriaz+jest)

import { mount } from 'avoriaz'
import Vue from 'vue'
import Vuetify from 'vuetify'
import Hello from '@/components/Hello'

Vue.use(Vuetify)

describe('Hello.vue', () => {
  it('should input name', () => {
      const wrapper = mount(Hello)
      const name = wrapper.find('input#name')[0]
      name.trigger('focus')
      name.element.value = 'TARO'    
      expect(wrapper.vm.name)
      .toEqual('TARO')
    })
    it('should input flag', () => {
      const wrapper = mount(Hello)
      console.log(wrapper.html())
      const flag = wrapper.find('.input-group--selection-controls__ripple')[0]
      flag.trigger('click')
      expect(wrapper.vm.flag)
        .toEqual(true)
    })
})

Vue+jestでテスト

以下のエラーが出てテストが通らない。

    console.error node_modules/vue/dist/vue.runtime.common.js:1715
      /Users/dokechin/work/gratan/src/assets/hero.jpeg:1
      ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){����
                                                                                               ^

jestで何か設定が足りないようです。

この辺だろうか・・
webpackのテンプレートに以下のプルリクを発見

github.com

これで、上記エラーは消えた。

次のエラーが現れる

        Failed to write coverage reports:
        ERROR: TypeError: metrics.isEmpty is not a function

これはhttps://github.com/facebook/jest/issues/5772

rm -rf node_modules
rm package-lock.json
npm install

次のエラー現れる

 Failed to write coverage reports:
        ERROR: TypeError: Cannot read property 'decl' of undefined
        STACK: TypeError: Cannot read property 'decl' of undefined
    at /Users/dokechin/work/gratan/node_modules/istanbul-reports/lib/lcovonly/index.js:32:38
    at Array.forEach (<anonymous>)
    at LcovOnlyReport.onDetail (/Users/dokechin/work/gratan/node_modules/istanbul-reports/lib/lcovonly/index.js:30:28)
    at LcovReport.(anonymous function) [as onDetail] (/Users/dokechin/work/gratan/node_modules/istanbul-reports/lib/lcov/index.js:21:24)
    at Visitor.(anonymous function) [as onDetail] (/Users/dokechin/work/gratan/node_modules/istanbul-lib-report/lib/tree.js:34:30)
    at ReportNode.Node.visit (/Users/dokechin/work/gratan/node_modules/istanbul-lib-report/lib/tree.js:123:17)
    at /Users/dokechin/work/gratan/node_modules/istanbul-lib-report/lib/tree.js:116:23
    at Array.forEach (<anonymous>)
    at visitChildren (/Users/dokechin/work/gratan/node_modules/istanbul-lib-report/lib/tree.js:115:32)
    at ReportNode.Node.visit (/Users/dokechin/work/gratan/node_modules/istanbul-lib-report/lib/tree.js:126:5)

そもそも、PWAテンプレートにjestサポートがないのが・・

前回のポストの後
vuetifyのユニットテストやっぱり、jestを使いたい - 鈍足ランナーのIT日記

Webpackテンプレートはjestをサポートしているのに、PWAテンプレートが
サポートしていないのがおかしい何とかしたいと思いたった。

技術のない私でもできるのか?
と思ったけれどやって見ると
そんなに難しくなかった。Webpackテンプレートを見ながら
取り込むだけだった。
とても勉強になった。
プルリクも久しぶりに送った。

しかーし。vue cliは3.0が開発中ですでに動かせる状態との情報が・・
これだとjestも選択的に取り込めるんだろうなぁ。と予想されます。

vue cli3.0の勉強をぼちぼちしてみよう。

vuetifyのユニットテストやっぱり、jestを使いたい

v-checkboxのユニットテストをしようとしたら、なかなかうまくいかない。
それはv-checkboxを展開したHTMLにinputタグが見えてこない。(階層が深いため?)
vuetify.jsのv-checkboxのテストソースを見たらjest.fn()を使っていて
jestを使ってテストしていた。

vue-cli(PWA)付属のユニットテストはkarmaを使ったテストになっているので
それをjestベースに書き換えてしようするようにしたい

npm install で以下のモジュールをインストール

  • jest
  • vue-jest
  • babel-jest
  • jest-serializer-vue
  • babel-plugin-transform-vue-jsx
  • babel-plugin-syntax-jsx
  • babel-plugin-dynamic-import-node

vue-cli(webpack)付属のユニットテストはjestベースなので、そちらのユニットテストのフォルダにある
jest.conf.jsとsetup.js,.babelrcをコピーして持ってきた。
とりあえず、これで起動できたけれど、jest用に一部書き換えないといけないようだ。
expectでエラーになっている。

to.contain()

toContain

equal

toBe

vuetifyのunitテストを動かす

背景

vue-cli で作ったwebpackサンプル+vuetifyで簡単なテストを動かそうとしているのですが、
[Vue warn]: $listeners is readonly.ワーニングが大量に出てしまう。。
なんでだろう。。

vue-test-utils?

まだベータバージョンだからかな。vue-test-utilsを捨てて、avoriazにして見たら嘘のようにエラーが消えた。

とりあえず環境は・・

うろ覚えだけど、一応書き留めておく。不足しているかもしれません。

モジュールのインストール

vuetifyをテストするには、polyfillというのが必要見たい。
あとはテストにasync,awaitを記述したいのでその辺のモジュールも必要になりました。

npm install --save-dev avoriaz
npm install --save-dev babel-plugin-transform-async-to-generator
npm install --save-dev babel-polyfill
npm install --save-dev babel-preset-stage-3

.babelrcの編集

stage-2と描いてあるところをstage-3へ(async,awaitを使うため)

index.jsの編集

testの起点のindex.jsの先頭行に以下の記載。

import 'babel-polyfill'

あとはテストを書くだけ

import { mount } from 'avoriaz'
import Vue from 'vue'
import Vuetify from 'vuetify'
import Shop from '@/components/Shop'
import VueI18n from 'vue-i18n'
import { store } from '../../../src/store/store.js'

Vue.use(Vuetify)
Vue.use(VueI18n)

const data = require('../../../src/i18n/message.json')

const i18n = new VueI18n({
  locale: 'ja',
  messages: data
})

describe('Shop.vue', () => {
  it('should render correct contents', () => {
    const wrapper = mount(Shop, {i18n, store})
 // 以下テストがつづく・・・

asyncはnode7.10.1から使える

https://node.green

これを見るとので7.10.1からasyncの機能が使えるはず。
今回はnodeのバージョン6でやろうとしていたので、トランスパイルでasync系を変換する必要があった。
結局node9.11.1にしたら必要なモジュールが減った。大分スッキリした。

npm install --save-dev avoriaz
npm install --save-dev babel-polyfill

トランスパイル周りの知識がイマイチよくわかっていないなぁ。
変換前のnode環境、変換後のnode環境。
node9.11.1はasyncを変換しなくても動くからトランスパイルが不要になるということなんだろうけど・・・