Open9
Mock Service Worker(msw)をNuxt.jsでモックサーバーとして使ってみる
mockServiceWorker.js を作成し、 nuxt の静的なファイルとして配置する。
mockServiceWorker.js が ServiceWorker となり、ブラウザーのリクエストをフックしてくれる。
$ npx msw init static/ --save
これで static/mockServiceWorker.js ファイルが自動的に作成されます。
ブラウザでモック用の API として使う場合
mocks/browser.js
import { setupWorker } from 'msw'
import { handlers } from './handlers'
export const worker = setupWorker(...handlers)
mocks/handlers.js
import { rest } from 'msw'
export const handlers = [
rest.get('/users', (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json([
{
id: 1,
name: 'foo',
},
{
id: 2,
name: 'bar',
}
]),
)
}),
]
Nuxt の plugin から msw を呼び出す
plugins/mock.ts
export default () => {
if (process.env.NODE_ENV === 'development') {
const { worker } = require('../mocks/browser')
worker.start()
console.log('worker started')
}
};
nuxt.config.ts
plugins: [
{ src: '@/plugins/mock', mode: 'client' }
],
これで、 SPA モード、且つ開発環境のみでモックサーバーが起動する。
ここまで書いておいて、 msw のサイトのリンクを貼るのを忘れていた。
$ npm install msw --save-dev
page にサンプルページを追加する
page/mock-sample.vue
<template>
<div class="container">
<div>
<h1 class="title">モックサンプル画面</h1>
<p>{{ value1 }}</p>
<p>{{ value2 }}</p>
</div>
</div>
</template>
<script lang="ts">
import Vue from 'vue';
import { mapActions } from 'vuex'
export type DataType = {
value1: string
};
// via https://qiita.com/is_ryo/items/6fc799ba4214db61d8ab
export default Vue.extend({
data(): DataType {
return {
value1: 'initial value',
}
},
// data をリアクティブに更新するならこちらを使う
async asyncData({ $axios }) {
// この /users がモックサーバーを見に行く
const { data } = await $axios.get(`/users`)
return {
value1: data[0].name
}
},
// Vuex を使うならこちらを使う
async fetch({ store }) {
await store.dispatch('fetchApi')
},
computed: {
value2() {
return this.$store.state.result[1].name
}
},
mounted(): void {
console.log('モック mounted')
},
created(): void {
console.log('モック created')
// asyncData や fetch はいずれ廃止されるので、なるべく使わないほうがよいかもしれない
//this.fetchApi()
},
methods: {
...mapActions({
fetchApi: 'fetchApi'
})
},
});
</script>
<style>
.container {
margin: 0 auto;
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
text-align: center;
}
.title {
font-family: 'Quicksand', 'Source Sans Pro', -apple-system, BlinkMacSystemFont,
'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
display: block;
font-weight: 300;
font-size: 50px;
color: #35495e;
letter-spacing: 1px;
}
</style>
store も追加していく
nuxt.config.ts に axios の module を追加しておく
これをしておかないと this.$axios.get のように使うことができないため。
// Modules: https://go.nuxtjs.dev/config-modules
modules: [
'@nuxtjs/axios',
],
axios: {
// See https://github.com/nuxt-community/axios-module#options
},
tsconfig.json にも追加しておかないと型で怒られる
"types": [
"@nuxt/types",
"@types/node",
"@nuxtjs/axios",
"@types/jest"
]
store/index.ts
import Vue from 'vue'
import { AxiosRequestConfig } from 'axios'
/**
* レスポンス json オブジェクト用インターフェイス
*/
export interface ApiInterface {
id: string
name: string
}
/**
* store 用インターフェイス
*/
export interface StateInterface {
result: (ApiInterface)[]
}
/**
* state
*/
export const state = (): StateInterface => ({
result: [{ id: 'initial id', name: 'initial name' }]
})
/**
* getters
*/
export const getters = {
getResult(state: StateInterface): ApiInterface | undefined {
if (!state.result || state.result.length <= 0) {
return
}
return state.result[0]
}
}
/**
* mutations
*/
export const mutations = {
saveApiResult(state: StateInterface, apiResult: ApiInterface[]): void {
// オブジェクトの key 値の value を変更する場合、 Vue 側に通知がいかないので
// Vue.set 経由で渡す
// Vue.set(state.result, 'key', apiResult)
// 既存の result オブジェクトに追加する場合
// state.result = {
// ...state.result,
// apiResult
// }
// オブジェクトインスタンスをまるっと新しくして result に追加する場合
// state.result = Object.assign({}, state.result, {
// age: 27,
// favoriteColor: 'Vue Green'
// })
// 配列をそのまま result に入れる場合
state.result = apiResult
}
}
/**
* actions
*/
export const actions = {
async fetchApi(
this: Vue,
// @ts-ignore
{ state, commit }: any,
): Promise<void> {
try {
// @ts-ignore
const { data }: any = await this.$axios.get(
'/users',
{
} as AxiosRequestConfig // https://github.com/axios/axios/blob/master/index.d.ts
)
console.log('apiResult:', data)
// 値をストアに保存
commit('saveApiResult', data)
} catch (err) {
console.log(err)
}
}
}
Jest からモックサーバーを使ったスクラップは以下にまとめました。
全体像はこちらにまとめました。