LoginSignup
15
12

More than 3 years have passed since last update.

Vue.js + Jest + TypeScriptのプロジェクトを作る

Last updated at Posted at 2019-10-05

Vue.js + TypeScriptのプロジェクトにJestを入れて、Vueコンポーネントのメソッドのテストをしたかったのですが、思いのほか詰まりまくったので記事にしておきます。

Vue Test Utilsという公式パッケージを使ってVue.jsとJestを連携させるのですが、Babel 7の変更にJestやvue-test-utilsが追いついていない感じがあって、ドキュメント通りにやっても上手くいきませんでした。Jestのために他のパッケージのバージョンを落とすのも嫌だったので、解決策を調べてみました。

サンプルコードはこちらです。
https://github.com/kecbigmt/vue-test-utils-ts-sample

筆者の環境

  • OS: MacOS High Sierra 10.13.6
  • node: 10.16.3
  • vue-cli: 3.11.0
  • yarn: 1.19.0

手順

以下の流れで説明していきます。

  1. プロジェクト作成
  2. 設定ファイルの編集
  3. テストコードの追加
  4. テスト実行

プロジェクト作成

vue-cliでプロジェクトを作成します。手動でTSをONにします。あとはお好みで。

Terminal
$ vue create vue-test-utils-ts-sample

Vue CLI v3.11.0
? Please pick a preset: Manually select features
? Check the features needed for your project: Babel, TS, Linter
? Use class-style component syntax? Yes
? Use Babel alongside TypeScript (required for modern mode, auto-detected polyfills, transpiling JSX)? Yes
? Pick a linter / formatter config: TSLint
? Pick additional lint features: (Press <space> to select, <a> to toggle all, <i> to invert selection)Lint on save
? Where do you prefer placing config for Babel, PostCSS, ESLint, etc.? In dedicated config files
? Save this as a preset for future projects? No

パッケージのインストール

必要なパッケージをインストールします。計8個のパッケージをまとめて入れています。

Terminal
$ yarn add --dev jest @types/jest @vue/test-utils vue-jest babel-jest ts-jest @babel/core babel-core@^7.0.0-bridge.0 @babel/preset-env
# npmの場合は`npm install -D ...`

以下、備忘録のためにも、何を何のためにインストールしたのかを解説します。
(最初の3つについては省略)

xxx-jest

Terminal
$ yarn add --dev vue-jest babel-jest ts-jest
  • vue-jest: .vueのファイルをJestに読ませるために必要
  • babel-jest: ES2015のような新しめの文法で書いたスクリプトをJestに読ませるために必要
  • ts-jest: .tsのファイルをJestに(ry

@babel/core & babel-core

Terminal
$ yarn add --dev @babel/core babel-core@^7.0.0-bridge.0

babel-jestの依存関係のなかにbabel-coreが入っていています。しかし、Babel 7以降、babel-coreの最新バージョンは@babel/coreとして管理されています。

とはいえ、そのままだとbabel-jestが新しい名前を認識してくれないので、babel-jestに@babel/coreを渡すための繋ぎとして、babel-core@^7.0.0-bridge.0も一緒に入れます。

参考: babel/babel-bridge: A placeholder package that bridges babel-core to @babel/core.

@babel/preset-env

Terminal
$ yarn add --dev @babel/preset-env

vue-cliで作成したプロジェクトでは、babelによるコンパイルを行うときのプリセットとして@vue/appというのを使ってるみたいですが、Jestが.vueファイルを解釈しようとするときに上手くいかないようです。

そのため、Babelの一般的なプリセットである@babel/preset-envをテストのときだけ使います。プリセットの切り替えについて設定ファイルに記述する部分は後ほど紹介します。

ちなみに、筆者の環境では@babel/preset-envを使わないとこんなエラーが出ました。

Terminal
$ yarn run test:unit
# 中略
/path/to/vue-test-utils-ts-sample/node_modules/@babel/runtime-corejs2/helpers/esm/classCallCheck.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){export default function _classCallCheck(instance, Constructor) {
                                                                                             ^^^^^^

    SyntaxError: Unexpected token export

設定ファイルの編集

パッケージのインストールが終わったら、設定ファイルを編集していきます。編集するファイルはpackage.jsonbabel.config.jstsconfig.jsonの3つです。

package.json

以下のように記述を追加します。テスト用のコマンドを追加したり、どのファイルのときに何を使って解釈するのかを設定したりしてます。

package.json
{
  "scripts": {
    "test:unit": "jest"
  }
  // ...
  "jest": {
    "moduleFileExtensions": [
      "js",
      "ts",
      "json",
      "vue"
    ],
    "transform": {
      ".*\\.(vue)$": "vue-jest",
      "^.+\\.js$": "<rootDir>/node_modules/babel-jest",
      "^.+\\.tsx?$": "ts-jest"
    },
    "transformIgnorePatterns": [
      "/node_modules/(?!@babel/runtime-corejs2)"
    ]
  }
}

最後のtransformIgnorePatternsの部分はエラーを回避するために入れました。Babel 7 + Jestの特有のエラーであるようですが、これがないと以下のように出てきます。
(@babel/preset-envが無いときと同じエラーです)

Terminal
$ yarn run test:unit
# 中略
/path/to/vue-test-utils-ts-sample/node_modules/@babel/runtime-corejs2/helpers/esm/classCallCheck.js:1
    ({"Object.<anonymous>":function(module,exports,require,__dirname,__filename,global,jest){export default function _classCallCheck(instance, Constructor) {
                                                                                             ^^^^^^

    SyntaxError: Unexpected token export

参考: あーありがち - 2019-02時点でJestの設定で最後までハマったもの

babel.config.js

Babelのプリセットについて記述します。ここではテストのときだけ@babel/preset-envを使用するよう記述します。

babel.config.js
module.exports = {
  presets: [
    '@vue/app'
  ],
  env: {
    test: {
      presets: [['@babel/preset-env', { targets: { node: 'current' } }]]
    }
  }
}

参考: Testing Single-File Components with Jest | Vue Test Utils

tsconfig.js

最後にこのファイルです。テストコードのなかでJestの関数を使えるようにするために追加します。

tsconfig.json
{
  "compilerOptions": {
    "types": [
      "jest",
      //..
    ],
    //..
  },
  //..
}

テストコードの追加

続いて、テストコードを追加します。ここでは、プロジェクト作成時に自動で生成されるsrc/component/HelloWorld.vueのテストを追加します。

HelloWorld.vueと同じ階層に HelloWorld.spec.ts というファイルを新しく作成します。

ファイルの中には以下のように記述します。

HelloWorld.spec.ts
import { shallowMount } from '@vue/test-utils';
import HelloWorld from './HelloWorld.vue';

describe('HelloWorld.vue', () => {
  test('renders props.msg when passed', () => {
    const msg = 'new message';
    const wrapper = shallowMount(HelloWorld, {
      propsData: { msg },
    });
    expect(wrapper.text()).toMatch(msg);
  });
});

公式ドキュメントではテスト対象ファイルと同じ階層に__tests__というディレクトリを作って、その中にテストファイルを格納することが推奨されています。ですが、自分なりの配置をしても構わないとも記載されています)

テストの内容を軽く説明します。

const msg = 'new message';
const wrapper = shallowMount(HelloWorld, {
  propsData: { msg },
});

まず、msgというpropに"new message"という値を渡した上で、HelloWorldコンポーネントをマウント・レンダリングします。

shallowMount()は@vue/test-utilsの関数。浅くマウント(コンポーネントの中のコンポーネントまでは生成されない)され、レンダリングされたVueコンポーネントを含むWrapperを返します。

shallowMount()やその他の関数についてはAPI | Vue Test Utilsで説明されています。

expect(wrapper.text()).toMatch(msg);

WrapperはVueコンポーネントに関するいろいろな情報を返してくれます。wrapper.text()はコンポーネントに含まれるDOM要素内の文字列(<p>この部分</p>)をすべて繋げて返します。

JestのtoMatch()メソッドを使って、これに"new message"が含まれているかをテストしています。

WrapperについてはWrapper | Vue Test Utilsが参考になります。

テスト実行

用意が整ったので、いよいよテストを実行します。package.jsonで設定した通り、test:unitのコマンドを使用できるようになっています。

Terminal
$ yarn run test:unit # npmの場合は`npm run test:unit`

yarn run v1.19.0
$ jest
 PASS  src/components/HelloWorld.spec.ts
  HelloWorld.vue
    ✓ renders props.msg when passed (19ms)

Test Suites: 1 passed, 1 total
Tests:       1 passed, 1 total
Snapshots:   0 total
Time:        1.842s
Ran all test suites.
✨  Done in 2.87s.

以上です。テストが動くようになりました。

サンプルコードはこちらです。
https://github.com/kecbigmt/vue-test-utils-ts-sample

参考

15
12
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
15
12