Posted at

Vue Test UtilsのAPIまとめ(mountとshallowMount)


はじめに

現在Vueのテストを勉強中なのでVue Test Utilsの機能を順番にまとめていこうと思います。

今回はそんな中でもmountとshallowMountについての記録を残しておきます

こちらのドキュメントを参照させていただいています。

Vue Test Utils


mount


マウントされて描画された Vue コンポーネントを含む Wrapper を生成します。


とあります。

Wrapperを生成することでこちらのWrapperメソッドを使用することができます。今回はその一部を使用してテストをしてみます。

import { mount } from '@vue/test-utils'

import Foo from './Foo.vue'

describe('Foo', () => {
it('renders a div', () => {
const wrapper = mount(Foo)
expect(wrapper.contains('div')).toBe(true)
})
})

最初の例です。Wrapperを生成することによってcontainsメソッドを使用することができるようになります。

上記ではdiv要素を含んでいるかどうかをテストしています。divが含まれているがtrueが成り立ちます。

import { mount } from '@vue/test-utils'

import Foo from './Foo.vue'

describe('Foo', () => {
it('renders a div', () => {
const wrapper = mount(Foo, {
propsData: {
color: 'red'
}
})
expect(wrapper.props().color).toBe('red')
})
})

次のコンポーネントではオプションを渡しています。

propsDataに特定のデータをオブジェクトで指定することでpropsをコンポーネントに流し込むことができます。

上記の例ではwrapperでpropsを取り出し、その中のcolorというプロパティがredという文字列であるということを保証するためのコードです。

import { mount } from '@vue/test-utils'

import Foo from './Foo.vue'

describe('Foo', () => {
it('renders a div', () => {
const wrapper = mount(Foo, {
attachToDocument: true
})
expect(wrapper.contains('div')).toBe(true)
wrapper.destroy()
})
})

続いてDomへのattachです。


true に設定されている場合、描画時にコンポーネントは DOM にアタッチされます。


とオプションの説明に書かれていますが、説明が適当すぎて意味が分かりません笑

英語ドキュメントには補足も書かれていました。


When attaching to the DOM, you should call wrapper.destroy() at the end of your test to remove the rendered elements from the document and destroy the component instance.


wrapper.destroy()でテストの最後にDomから要素を取り除いてあげましょう。ちょをっと上記コードに補足をいれました。

でないと後のテストに影響してしまいます。基本はdefaultのfalseでいいと思います。使いみちを誰か教えてください...

import { mount } from '@vue/test-utils'

import Foo from './Foo.vue'
import Bar from './Bar.vue'
import FooBar from './FooBar.vue'

describe('Foo', () => {
it('renders a div', () => {
const wrapper = mount(Foo, {
slots: {
default: [Bar, FooBar],
fooBar: FooBar,
foo: '<div />'
}
})
expect(wrapper.contains('div')).toBe(true)
})
})

名前付きのスロットを指定できる。これで1つのwrapperコンポーネントに対して共通のコンポーネントを挟み、別コンポーネントを複数種類入れ込むことが可能。

import { mount } from '@vue/test-utils'

import Foo from './Foo.vue'

describe('Foo', () => {
it('renders a div', () => {
const $route = { path: 'http://www.example-path.com' }
const wrapper = mount(Foo, {
intercept: {
$route
}
})
expect(wrapper.vm.$route.path).toBe($route.path)
})
})

グローバルプロパティのスタブ。

テキストやUser Tokenを入れておいたり、共通の定数を入れておくのに便利そう。

import { mount } from '@vue/test-utils'

import Foo from './Foo.vue'
import Bar from './Bar.vue'
import Faz from './Faz.vue'

describe('Foo', () => {
it('renders a div', () => {
const wrapper = mount(Foo, {
stubs: {
Bar: '<div class="stubbed" />',
BarFoo: true,
FooBar: Faz
}
})
expect(wrapper.contains('.stubbed')).toBe(true)
expect(wrapper.contains(Bar)).toBe(true)
})
})

コンポーネントのスタブ.

スタブとはテスト用に用意した代わりの部品です。

あるラッパーコンポーネントを検証しようとしたときに、その子コンポーネントまで全て検証していくのは大変です。テストしたいのはあくまでもラップしているコンポーネントだったり、指定したコンポーネントだけになります。

全てのコンポーネントについて完全にテストするのは勧めないという旨が公式からも出ています。

Stubを利用してコンポーネントやpropsを借り置きし検証をしましょう。


shallowMount

続いてshallowMountです。wrapperのmountをshallowMountに変えただけなのでサンプルは割愛します。以下の1つだけです。

import { shallowMount } from '@vue/test-utils'

import Foo from './Foo.vue'

describe('Foo', () => {
it('renders a div', () => {
const wrapper = shallowMount(Foo)
expect(wrapper.contains('div')).toBe(true)
})
})

公式の説明を見てみると


mountのようにマウントされて描画された Vue コンポーネントを含む Wrapper を生成しますが、 子コンポーネントはスタブされたコンポーネントです。


と書いています。

スタブに関しては先程も説明したとおりですが、テスト用に用意した代わりの部品です。

ここで注意です。

import { mount } from '@vue/test-utils'

import Foo from './Foo.vue'
import Bar from './Bar.vue'
import Faz from './Faz.vue'

describe('Foo', () => {
it('renders a div', () => {
const wrapper = shallMount(Foo, {
stubs: {
Bar: '<div class="stubbed" />',
BarFoo: true,
FooBar: Faz
}
})
expect(wrapper.contains('.stubbed')).toBe(true)
expect(wrapper.contains(Bar)).toBe(true)
})
})

mountでやったように上記のようにすることはしません。なぜなら元から子のコンポーネントは仮おきしてしまっているからです。


まとめ

今回はmountとshallowMountの違いを調べました。

結論としてmountは子コンポーネントをまとめてテストしたい場合、shallMountは子コンポーネントのテストはせずにゆるくテストする場合に使用するのが良さそうですね。 

何か間違いがあれば指摘していただきたいです。これからもごりごりテストの勉強を進めていきます