diff --git a/docs/ja/README.md b/docs/ja/README.md index 3ed66651c..726f89c65 100644 --- a/docs/ja/README.md +++ b/docs/ja/README.md @@ -55,6 +55,7 @@ * [contains](api/wrapper-array/contains.md) * [exists](api/wrapper/exists.md) * [destroy](api/wrapper-array/destroy.md) + * [filter](api/wrapper-array/filter.md) * [is](api/wrapper-array/is.md) * [isEmpty](api/wrapper-array/isEmpty.md) * [isVueInstance](api/wrapper-array/isVueInstance.md) @@ -67,6 +68,7 @@ * [コンポーネント](api/components/README.md) * [TransitionStub](api/components/TransitionStub.md) * [TransitionGroupStub](api/components/TransitionGroupStub.md) + * [RouterLinkStub](api/components/RouterLinkStub.md) * [セレクタ](api/selectors.md) * [createLocalVue](api/createLocalVue.md) * [config](api/config.md) diff --git a/docs/ja/SUMMARY.md b/docs/ja/SUMMARY.md index e9ee918bb..382e83492 100644 --- a/docs/ja/SUMMARY.md +++ b/docs/ja/SUMMARY.md @@ -53,6 +53,7 @@ * [contains](api/wrapper-array/contains.md) * [exists](api/wrapper/exists.md) * [destroy](api/wrapper-array/destroy.md) + * [filter](api/wrapper-array/filter.md) * [is](api/wrapper-array/is.md) * [isEmpty](api/wrapper-array/isEmpty.md) * [isVueInstance](api/wrapper-array/isVueInstance.md) @@ -65,6 +66,7 @@ * [コンポーネント](api/components/README.md) * [TransitionStub](api/components/TransitionStub.md) * [TransitionGroupStub](api/components/TransitionGroupStub.md) + * [RouterLinkStub](api/components/RouterLinkStub.md) * [セレクタ](api/selectors.md) * [createLocalVue](api/createLocalVue.md) * [config](api/config.md) diff --git a/docs/ja/api/README.md b/docs/ja/api/README.md index 8f56ddbf4..0c78b3246 100644 --- a/docs/ja/api/README.md +++ b/docs/ja/api/README.md @@ -41,6 +41,7 @@ * [contains](./wrapper-array/contains.md) * [exists](./wrapper/exists.md) * [destroy](./wrapper-array/destroy.md) + * [filter](./wrapper-array/filter.md) * [is](./wrapper-array/is.md) * [isEmpty](./wrapper-array/isEmpty.md) * [isVueInstance](./wrapper-array/isVueInstance.md) @@ -53,6 +54,7 @@ * [コンポーネント](./components/README.md) * [TransitionStub](./components/TransitionStub.md) * [TransitionGroupStub](./components/TransitionGroupStub.md) + * [RouterLinkStub](./components/RouterLinkStub.md) * [セレクタ](./selectors.md) * [createLocalVue](./createLocalVue.md) * [config](./config.md) diff --git a/docs/ja/api/components/RouterLinkStub.md b/docs/ja/api/components/RouterLinkStub.md new file mode 100644 index 000000000..177a82533 --- /dev/null +++ b/docs/ja/api/components/RouterLinkStub.md @@ -0,0 +1,20 @@ +# RouterLinkStub + +Vue Router の `router-link` コンポーネントをスタブするためのコンポーネントです。 + +レンダリングツリーにある router-link コンポーネントを見つけるためにこのコンポーネントを使用することができます。 + +- **使い方:** + +スタブとしてマウンティングオプションにセットします。 + +```js +import { mount, RouterLinkStub } from '@vue/test-utils' + +const wrapper = mount(Component, { + stubs: { + RouterLink: RouterLinkStub + } +}) +expect(wrapper.find(RouterLinkStub).props().to).toBe('/some/path') +``` diff --git a/docs/ja/api/wrapper-array/filter.md b/docs/ja/api/wrapper-array/filter.md new file mode 100644 index 000000000..e9345cb6a --- /dev/null +++ b/docs/ja/api/wrapper-array/filter.md @@ -0,0 +1,22 @@ +# filter(predicate) + +`Wrapper` オブジェクトを判別する関数を使用して `WrapperArray` をフィルタリングします。 + +このメソッドの動作は [Array.prototype.filter](https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/filter) に似ています。 + +- **引数:** + - `{function} predicate` + +- **戻り値:** `{WrapperArray}` + +predicate 関数が true を返す `Wrapper` インスタンスを含む新しい `WrapperArray` インスタンスを返します。 + +- **例:** + +```js +import { shallow } from '@vue/test-utils' +import Foo from './Foo.vue' + +const wrapper = shallow(Foo) +const filteredDivArray = wrapper.findAll('div').filter(w => !w.hasClass('filtered')) +``` diff --git a/docs/ja/api/wrapper/props.md b/docs/ja/api/wrapper/props.md index 31c0c470e..9897bf02b 100644 --- a/docs/ja/api/wrapper/props.md +++ b/docs/ja/api/wrapper/props.md @@ -9,15 +9,14 @@ - **例:** ```js +import { mount } from '@vue/test-utils' +import { expect } from 'chai' import Foo from './Foo.vue' -import Bar from './Bar.vue' -const wrapper = mount(Component, { - context: { - props: { show: true }, - children: [Foo, Bar] +const wrapper = mount(Foo, { + propsData: { + bar: 'baz' } }) - -expect(wrapper.is(Component)).toBe(true) +expect(wrapper.props().bar).toBe('baz') ``` diff --git a/docs/ja/guides/testing-SFCs-with-jest.md b/docs/ja/guides/testing-SFCs-with-jest.md index 5bef1c339..e49d53d2f 100644 --- a/docs/ja/guides/testing-SFCs-with-jest.md +++ b/docs/ja/guides/testing-SFCs-with-jest.md @@ -11,7 +11,7 @@ Jest は Facebook が開発したテストランナであり、ユニットテ まず Jest と `vue-test-utils` をインストールします: ```bash -$ npm install --save-dev jest vue-test-utils +$ npm install --save-dev jest @vue/test-utils ``` 次に、`package.json` にスクリプトを定義する必要があります。 diff --git a/docs/ja/guides/using-with-vue-router.md b/docs/ja/guides/using-with-vue-router.md index 9dc6e6cdb..1de60f6d8 100644 --- a/docs/ja/guides/using-with-vue-router.md +++ b/docs/ja/guides/using-with-vue-router.md @@ -18,6 +18,8 @@ shallow(Component, { }) ``` +> Vue Router を localVue にインストールすると `$route` と `$router` が読み取り専用プロパティーとして localVue に追加されます。これは VueRouter をインストールした localVue を使用しているコンポーネントをマウントする時、 `mock` オプションで `$route` と `$router` を上書きすることができないことを意味します。 + ## `router-link` または `router-view` を使用するコンポーネントテスト Vue Router をインストールする時、`router-link` と `router-view` コンポーネントが登録されます。これは、それらをアプリケーションにインポートする必要がなく、アプリケーションのどこでも使用することができます。 diff --git a/docs/ja/guides/using-with-vuex.md b/docs/ja/guides/using-with-vuex.md index 5d02d726e..615283ab0 100644 --- a/docs/ja/guides/using-with-vuex.md +++ b/docs/ja/guides/using-with-vuex.md @@ -2,7 +2,9 @@ このガイドでは、`vue-test-utils` でコンポーネントで Vuex をテストする方法について、見ていきます。 -## アクションのモック +## コンポーネント内の Vuex のテスト + +### アクションのモック それではいくつかのコードを見ていきましょう。 @@ -107,7 +109,7 @@ describe('Actions.vue', () => { 素晴らしい!今、アクションをモック化できるので、ゲッタのモックについて見ていきましょう。 -## ゲッタのモック +### ゲッタのモック ``` html @@ -176,7 +178,7 @@ describe('Getters.vue', () => { これは素晴らしいですが、もしゲッタが状態の正しい部分を返しているのを確認したい場合はどうしますか? -## モジュールによるモック +### モジュールによるモック [モジュール](https://vuex.vuejs.org/en/modules.html)はストアを管理しやすい塊に分けるために便利です。それらはゲッタもエクスポートします。テストではこれらを使用することができます。 @@ -259,8 +261,131 @@ describe('Modules.vue', () => { }) ``` -### リソース -- [このガイド向けの例](https://github.com/eddyerburgh/vue-test-utils-vuex-example) +## Vuex ストアのテスト + +Vuex ストアをテストする方法が2つあります。1つ目はゲッタとミューテーションとアクションを別々に単体テストする方法です。2つ目はストアを生成してそれをテストする方法です。 + +Vuex ストアをテストする方法を説明するためにシンプルなカウンターストアを用意します。このストアには `increment` ミューテーションと `counter` ゲッタがあります。 + +```js +// mutations.js +export default { + increment (state) { + state.count++ + } +} +``` + +```js +// getters.js +export default { + evenOrOdd: state => state.count % 2 === 0 ? 'even' : 'odd' +} +``` + +### ゲッタとミューテーションとアクションを別々にテストする + +ゲッタとミューテーションとアクションはすべて JavaScript の関数です。それらは `vue-test-utils` と Vuex を使用しなくてもテストすることができます。 + +ゲッタとミューテーションとアクションを別々にテストする利点は単体テストを詳細に記述することができることです。テストが失敗すると、コードの何が原因か正確に知ることができます。欠点は `commit` や `dispatch` のような Vuex の関数のモックが必要なことです。これは不正なモックが原因で単体テストはパスしてプロダクションは失敗する状況を作り出す可能性があります。 + +mutations.spec.js と getters.spec.js という名前のテストファイルを2つ作成します。 + +最初に increment ミューテーションをテストします。 + +```js +// mutations.spec.js + +import mutations from './mutations' + +test('increment increments state.count by 1', () => { + const state = { + count: 0 + } + mutations.increment(state) + expect(state.count).toBe(1) +}) +``` + +今度は `evenOrOdd` ゲッタを次の手順でテストします。 `state` モックを作成します。 `state` を引数としてゲッタ関数を実行します。そして、それが正しい値を返したか確認します。 + +```js +// getters.spec.js + +import getters from './getters' + +test('evenOrOdd returns even if state.count is even', () => { + const state = { + count: 2 + } + expect(getters.evenOrOdd(state)).toBe('even') +}) + +test('evenOrOdd returns odd if state.count is even', () => { + const state = { + count: 1 + } + expect(getters.evenOrOdd(state)).toBe('odd') +}) + +``` + +### 実行可能なストアのテスト + +Vuexストアをテストするもう1つの方法はストアの設定を使って実行可能なストアを生成することです。 + +実行可能なストアを生成してテストすることの利点は Vuex の関数をモックする必要がない事です。 + +欠点はテストが失敗した時、問題がある箇所を見つけることが難しいことです。 + +テストを書いてみましょう。ストアを生成する際は、 Vue のコンストラクタが汚染されることを避けるために `localVue` を使用します。このテストは store-config.js の export を使用してストアを生成します。 + +```js +// store-config.js + +import mutations from './mutations' +import getters from './getters' + +export default { + state: { + count: 0 + }, + mutations, + getters +} +``` + +```js +import { createLocalVue } from '@vue/test-utils' +import Vuex from 'vuex' +import storeConfig from './store-config' +import { cloneDeep } from 'lodash' + +test('increments count value when increment is commited', () => { + const localVue = createLocalVue() + localVue.use(Vuex) + const store = new Vuex.Store(cloneDeep(storeConfig)) + expect(store.state.count).toBe(0) + store.commit('increment') + expect(store.state.count).toBe(1) +}) + +test('updates evenOrOdd getter when increment is commited', () => { + const localVue = createLocalVue() + localVue.use(Vuex) + const store = new Vuex.Store(cloneDeep(storeConfig)) + expect(store.getters.evenOrOdd).toBe('even') + store.commit('increment') + expect(store.getters.evenOrOdd).toBe('odd') +}) +``` + +ストアをストアの設定から生成する前に `cloneDeep` を使用しています。こうする理由は Vuex はストアを生成するためにオプションオブジェクトを変更するからです。どのテストでも確実に汚染されていないストアを使うために `storeConfig` オブジェクトを複製する必要があります。 + +## リソース + +- [コンポーネントをテストする例](https://github.com/eddyerburgh/vue-test-utils-vuex-example) +- [ストアをテストする例](https://github.com/eddyerburgh/testing-vuex-store-example) - [localVue](../api/options.md#localvue) - [createLocalVue](../api/createLocalVue.md)