Open6
Jest+Mock Service Worker(msw)でNuxt.jsのstoreをテストしてみる
msw のモックサーバー記事は
こちらに書きました。
今回は、そのモックサーバーを使いつつ Jest でテストコードを書いていきます。
Jest と @vue/test-utils をインストールする
$ npm install --save-dev jest @vue/test-utils
package.json をチラ見して気がついたんですが、
以下のコマンドを打ったときに、
$ npx msw init static/ --save
こんな感じに自動で追記されてるんですねー
"msw": {
"workerDirectory": "static"
}
Jest でモックを使うための下準備をする
mocks/server.js
// src/mocks/server.js
import { setupServer } from 'msw/node'
import { handlers } from './handlers'
// This configures a request mocking server with the given request handlers.
export const server = setupServer(...handlers)
ブラウザーから使う場合は、 browser.js を追加しましたが、それの node.js 版をここで作成します。
setup/setup.ts
ディレクトリ名は、いつもこうゆう感じにしているので Nuxt の命名っぽくないかもしれません。
必ずモックサーバーを使われるように、ここでセットアップしておきます。
// src/setupTests.js
import { server } from '../mocks/server'
// Establish API mocking before all tests.
beforeAll(() => server.listen())
// Reset any request handlers that we may add during the tests,
// so they don't affect other tests.
afterEach(() => server.resetHandlers())
// Clean up after the tests are finished.
afterAll(() => server.close())
jest.config.js に setupFilesAfterEnv を設定する
module.exports = {
moduleNameMapper: {
'^@/(.*)$': '<rootDir>/$1',
'^~/(.*)$': '<rootDir>/$1',
'^vue$': 'vue/dist/vue.common.js',
},
moduleFileExtensions: ['ts', 'js', 'vue', 'json'],
transform: {
'^.+\\.ts$': 'ts-jest',
'^.+\\.js$': 'babel-jest',
'.*\\.(vue)$': 'vue-jest',
},
collectCoverage: true,
collectCoverageFrom: [
'<rootDir>/components/**/*.vue',
'<rootDir>/pages/**/*.vue',
],
setupFilesAfterEnv: ['./__setup__/setup.ts'], // ここです!
};
テストコードを書く
あくまでも store の部分のみで、 API との通信は msw がモックしてくれているという状態です。
Vue の部分を絡まないテストですが、この store の部分は担保しておきたい!という場合には有効なのかなーと思います。
test/store.test.ts
import { createLocalVue } from '@vue/test-utils';
import axios from 'axios';
import Vuex from 'vuex'
import * as storeIndex from '@/store/index'
// Vue のセットアップ
const localVue = createLocalVue();
localVue.use(Vuex);
describe('storeIndex tests', () => {
let store: any;
beforeEach(() => {
// @ts-ignore
store = new Vuex.Store(storeIndex)
// これをしておかないと this.$axios が使えない
store.$axios = axios;
})
test('apiのレスポンス0のテスト', async (done) => {
// @ts-ignore
await store.dispatch('fetchApi')
// getters 経由でアクセスする場合
expect(store.getters['getResult'].name).toBe('foo');
// 非同期のテストは done しないとずっと完了してくれない
done();
});
test('apiのレスポンス1のテスト', async (done) => {
// @ts-ignore
await store.dispatch('fetchApi')
// state 経由でアクセスする場合
expect(store.state.result[1].name).toBe('bar');
done();
});
});
全体像はこちらにまとめました。