はじめに
はじめまして、河村康治です。HITOTSUアドベントカレンダーの4日目担当します!!
普段はバックエンドを主にやっているのですが、E2Eテストの知見を深めていきたいなと思っています。なので、今回のカレンダーではE2Eのフロントエンド周りを中心に投稿していきます!!
今回の記事では、Mockサーバを利用したフロントエンドのテストです。バックエンド開発中にフロントエンドのテストが進められるなど、何かと便利なMSWを紹介します!!
やりたい事
通常時はAPIサーバと連動する。テスト時のみServiceWorkerが起動し固定値が返却される。
これにより、APIサーバに依存する事なく、API連動時のフロントの挙動を確認する事ができるようになります。
MSWとは
ServiceWorkerを利用したMockサーバです。ネットワーク層でリクエストをインターセプトし値を返却します。そのため、アプリケーションの挙動はそのままで、テストや開発、デバッグで利用されているライブラリです。
Hands-onスタート
環境情報
## typescriptでプロジェクト作成
yarn create react-app msw_test2 --template typescript
## mswのインストール
~/develop/react$ yarn add --dev msw
## mockServiceWorke.jsをコマンドで作成
npx msw init public/ --save
## mswとは関係ないが、Hands-onで使うライブラリ
yarn add @tanstack/react-query
yarn add axios
~/develop/react/msw_test$ tree -I node_modules
.
├── README.md
├── package.json
├── public
│ ├── favicon.ico
│ ├── index.html
│ ├── logo192.png
│ ├── logo512.png
│ ├── manifest.json
│ ├── mockServiceWorker.js
│ └── robots.txt
├── src
│ ├── App.css
│ ├── App.test.tsx
│ ├── App.tsx
│ ├── api
│ │ └── login.ts
│ ├── components
│ │ └── Login.tsx
│ ├── index.css
│ ├── index.tsx
│ ├── logo.svg
│ ├── mocks
│ │ ├── browser.ts
│ │ └── handler.ts
│ ├── react-app-env.d.ts
│ ├── reportWebVitals.ts
│ └── setupTests.ts
├── tsconfig.json
└── yarn.lock
5 directories, 24 files
{
"name": "msw_test",
"version": "0.1.0",
"private": true,
"dependencies": {
"@tanstack/react-query": "^4.14.3",
"@testing-library/jest-dom": "^5.14.1",
"@testing-library/react": "^13.0.0",
"@testing-library/user-event": "^13.2.1",
"@types/jest": "^27.0.1",
"@types/node": "^16.7.13",
"@types/react": "^18.0.0",
"@types/react-dom": "^18.0.0",
"axios": "^1.1.3",
"msw": "^0.47.4",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"typescript": "^4.4.2",
"web-vitals": "^2.1.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test",
"eject": "react-scripts eject"
},
"eslintConfig": {
"extends": [
"react-app",
"react-app/jest"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"msw": {
"workerDirectory": "public"
}
}
// 今回は、REACT_APP_ENVがtestの時のみmswが起動するように設定。
REACT_APP_ENV=test
ソースコード
mockの設定
import {setupWorker} from 'msw';
import {handlers} from './handler';
// 指定されたリクエストハンドラを持つサービスワーカーを設定する
export const worker = setupWorker(...handlers);
import {rest} from 'msw';
export const handlers = [
rest.get('https://jsonplaceholder.typicode.com/todos/1', (req, res, ctx) => {
return res(
ctx.status(200),
ctx.json({
userId: 2,
id: 2,
title: 'Mockですよ!!!',
completed: false,
})
);
}),
];
アプリケーション側
import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App';
import {QueryClient, QueryClientProvider} from '@tanstack/react-query';
const queryClient = new QueryClient();
// テスト環境の時のみ、ServiceWorkerを登録する
if (process.env.REACT_APP_ENV === 'test') {
const {worker} = require('./mocks/browser');
worker.start();
}
const root = ReactDOM.createRoot(document.getElementById('root') as HTMLElement);
root.render(
<React.StrictMode>
<QueryClientProvider client={queryClient}>
<App />
</QueryClientProvider>
</React.StrictMode>
);
import React from 'react';
import {Login} from './components/Login';
function App() {
return <Login />;
}
export default App;
import {useFetchAPI} from '../api/login';
export const Login = () => {
const {isLoading, isError, data} = useFetchAPI();
if (isLoading) {
return <div>Loading...</div>;
}
if (isError) {
return <span>Error...</span>;
}
return (
<div>
ユーザID:{data.userId}
<br />
ID:{data.id}
<br />
タイトル:{data.title}
<br />
完了:{data.completed ? '完了' : '未完了'}
<br />
</div>
);
};
import axios from 'axios';
import {useQuery} from '@tanstack/react-query';
export const getAPI = async () => {
const baseUrl = 'https://jsonplaceholder.typicode.com/todos/1';
const {data} = await axios.get<User>(baseUrl);
return data;
};
export const useFetchAPI = () => {
return useQuery(['test'], () => getAPI());
};
export type User = {
userId: number;
id: number;
title: string;
completed: boolean;
};
動作確認
今回は、JSONPlaceholderを利用しています。
通常はJSONPlaceholderを実行し、テスト環境の時はServiceWorkerを実行する事になります。
これが出ていればOKです!!!
ちなみに、MSWが起動している時は、Console画面に「[MSW] Mocking enabled.」と表示されます。
最後に
今回はMSWの導入について記載しました。次回移行の記事では、JestやPlayWrightでのMSW導入の話に繋げていきたいと思います!!