Vue CLI テスト Tips集
2019/08/17
CaT vol.7 in 秋田 / Short LT
jiyuujin
- Vue/Nuxt/PHP/Scala/Java/Swift
- v-kansai/kansai.ts/..
- Web猫ブログ (webneko.dev)
毎月大阪、京都交互で
初 秋 田
フロントでテストやってますか?
社内向け管理画面が主でした
- Play(Scala) + Vue = SPA構成
- bootstrap-vue / vue-i18n / ..
- 時間、優先度を考えテストはしない😌
とある売上を管理する本部機能を
- CakePHP + Vue = SPA構成
- Vue CLI + i18n + Jest
- プロダクトとしては1年前から、Smartyを使ってたけど
導入部分の話は割愛します🙏
と言いたかったけど。。🥵
初期インストールですんなりイケると思った
- babel7でコード変換できなかった
- babel-coreと諸々のバージョンが一致してなかった
- 通信処理で async - await が使えてなかった
babel.config
module.exports = {
presets: [
'@vue/app',
[
'@babel/preset-env',
{
targets: {
browsers: ['> 1%', 'last 2 versions'],
node: 'current'
},
useBuiltIns: 'entry',
corejs: 3
}
]
],
plugins: [
[
'@babel/plugin-transform-runtime',
{
regenerator: true
}
],
'@babel/plugin-proposal-class-properties',
'@babel/plugin-proposal-export-default-from',
'@babel/plugin-syntax-dynamic-import'
]
}
Babel周りには気を配りましょう
決して複雑な構成では無かったが
.
├── doc_root
│ ├── app
│ ├── tests
│ └── webroot
├── frontend
│ ├── public
│ ├── src
│ │ ├── api
│ │ ├── assets
│ │ ├── components
│ │ ├── plugins
│ │ ├── services
│ │ ├── types
│ │ ├── utils
│ │ └── views
│ └── tests
丁寧にjest.configを書くこと
では実際にテストを書くぞ
そもそも何をテストしようか🤔
文法はESLint/Prettierに任せて
- コンポーネントのマウント
- イベント発火を受け、ステートの変動に矛盾が無いか
- 激重API対策
お世話になるパッケージですが
- @vue/test-utils (default)
- @testing-library/vue
- axios-mock-adapter
render / fireEvent
// @testing-library/vue
import '@testing-library/jest-dom/extend-expect'
import { render, fireEvent } from '@testing-library/vue'
describe('Button', () => {
it('click event', async () => {
const { getByText } = render(Child, {
propsData: {
text: '追加する'
}
})
const button = getByText('追加する')
await fireEvent.click(button)
})
})
CSS frameworkを入れることも容易に
// @vue/test-utils
import { createLocalVue } from '@vue/test-utils'
// bootstrap-vue
import BootstrapVue from 'bootstrap-vue'
const localVue = createLocalVue()
localVue.use(BootstrapVue)
describe('Button', () => {
it('click event', async () => {
const { getByText } = render(Child, {
localVue,
propsData: {
text: '追加する'
}
})
const button = getByText('追加する')
await fireEvent.click(button)
})
})
続いて通信処理ですが
事前に通信処理を切り分けておくと楽
import axios from 'axios';
import { Sale } from '@/types';
export default class SaleService {
public async fetchSummary(
id: number
): Promise<Sale> {
const res = await axios.get(`/summary?id=${id}`);
return res.data;
}
}
serviceにアクセスしてテスト
import SaleService from '@/services/SaleService';
describe('SaleService', () => {
let saleService: SaleService;
beforeEach(() => {
saleService = new SaleService();
});
it('fetch data', async () => {
const responseData = await saleService.fetchSummary(
null
);
expect(responseData.id).toBe(1);
});
})
異常系を含めたテスト
激重APIだからこそ
正しくレスポンスできているか
あえて遅らせてテストしたり
describe('Service', () => {
let mockAxios: MockAdapter
beforeEach(() => {
// あえてモックの返却を遅らせる
mockAxios = new MockAdapter(axios, {
delayResponse: 500
})
})
it('response status === 403', async () => {
mockAxios.onGet(`${BASE_API}1`)
.reply(403)
try {
await getPostID(1)
} catch (error) {
expect(error.message).toEqual('Request failed with status code 403');
}
})
})
この辺りを見てテストを書いてます
- コンポーネントのマウント
- イベント発火を受け、ステートの変動に矛盾が無いか
- フロントとして激重API対策