フロントエンド開発といえば。
react アプリの初期化( npm init vite@latest <アプリ名> )

mswでreactアプリのモック

● reactアプリの作成( msw-ts-app というサンプルアプリを作成します )

npm init vite@latest msw-ts-app
cd msw-ts-app
npm install

● mswのインストール

npm i -D msw

● モックの定義

・1. URLとそれに対する処理を紐づける handlers.ts を作成する

mkdir src/mocks
vi src/mocks/handlers.ts

handlers.ts を以下の内容で保存する

import { rest } from 'msw';
import mockUser from 'mocks/resolvers/mockUser';

const handlers = [
  rest.get('/users/', mockUsers),
  rest.get('/users/:id', mockUser),
];

export default handlers;

・2. 処理内容を記述する resolvers/xxxxx.ts を作成する

・2-1 Userの型を作成する

mkdir src/models
vi src/models/User.ts

以下の内容で保存

export type User = {
  id: number;
  username: string;
  age: number;
};

・2-2 mockUserリゾルバを作成する

mkdir src/mocks/resolvers
vi src/mocks/resolvers/mockUser.ts

mockUser.ts を以下の内容で保存する

import { ResponseResolver, MockedRequest, restContext } from 'msw';
import { User } from '../../models/User';

const users: User[] = [
  {
    id: 1,
    username: '山田 太郎',
    age: 25,
  },
  {
    id: 2,
    username: '斎藤 次郎',
    age: 37,
  },
  {
    id: 3,
    username: '山田 花子',
    age: 41,
  },
];

const mockUser: ResponseResolver<MockedRequest, typeof restContext> = (
  req,
  res,
  ctx
) => {
  // パスパラメーターの取得
  const { id } = req.params;
  const user: User | undefined = getMockUserData(Number(id));
  return res(ctx.json(user));
};

const getMockUserData = (id: number): User | undefined => {
  // idでusersを検索
  const user = users.find((user) => user.id === id);
  return user;
};

export default mockUser;

続けて mockUsers.ts を以下の内容で保存する

vi src/mocks/resolvers/mockUser.ts
import { ResponseResolver, MockedRequest, restContext } from 'msw';
import { User } from '../../models/User';

const users: User[] = [
  {
    id: 1,
    username: '山田 太郎',
    age: 25,
  },
  {
    id: 2,
    username: '斎藤 次郎',
    age: 37,
  },
  {
    id: 3,
    username: '山田 花子',
    age: 41,
  },
];

const mockUser: ResponseResolver<MockedRequest, typeof restContext> = (
  req,
  res,
  ctx
) => {
  // クエリパラメーターの取得
  const perPage = req.url.searchParams.get('perPage');
  const user: User[] = getMockUserList(Number(perPage));
  return res(ctx.json(user));
};

const getMockUserList = (perPage: number): User[] => {
  return users.slice(0, perPage);
};

export default mockUser;

・3. サービスワーカーを設定する browser.ts を作成する

vi src/mocks/browser.ts

browser.ts を以下の内容で保存する

import { setupWorker } from 'msw';
import handlers from 'mocks/handlers';

const worker = setupWorker(...handlers);

export default worker;

・4. main.tsx に mswを追加する

src/main.tsx に以下を追加

import React from 'react';
import ReactDOM from 'react-dom/client';
import App from './App.tsx';
import './index.css';

// msw(追加)
import worker from './mocks/browser';

// msw(追加)
if (process.env.NODE_ENV === 'development') {
  void worker.start();
}

ReactDOM.createRoot(document.getElementById('root')!).render(
  <React.StrictMode>
    <App />
  </React.StrictMode>
);

・5. サービスワーカーを public ディレクトリに生成する

次の準備されているコマンドを実行するだけでOKです

npx msw init public/ --save

これで準備が整いました。

● アプリを起動して msw の挙動を確認する

1. msw起動の確認

npm run dev

http://localhost:5174/ へアクセスして、ブラウザの console を確認する

[MSW] Mocking enabled.

と表示されていれば起動は成功しています。

2. 実際に reactアプリでデータを取得して表示する。

vi src/useUser.ts
import { useEffect, useState } from 'react';
import { User } from './models/User';

export function useUser(id: number) {
  const [data, setData] = useState<User | undefined>(undefined);

  useEffect(() => {
    const fetchDataAsync = async () => {
      try {
        const url = `/users/${id}`;
        const res = await fetch(url);
        const data = await res.json();
        setData(data);
      } catch (e) {
        throw new Error('fetch error');
      }
    };

    fetchDataAsync();
  }, [id]);

  return { data };
}
vi src/useUsers.ts
import { useEffect, useState } from 'react';
import { User } from './models/User';

export function useUsers(perPage: number) {
  const [users, setUsers] = useState<User | undefined>(undefined);

  useEffect(() => {
    const fetchDataAsync = async () => {
      try {
        const url = `/users/?perPage=${perPage}`;
        const res = await fetch(url);
        const users = await res.json();
        setUsers(users);
      } catch (e) {
        throw new Error('fetch error');
      }
    };

    fetchDataAsync();
  }, [perPage]);

  return { users };
}

App.tsx を以下のように変更する

import { useRef, useState } from 'react';
import './App.css';
import { useUser } from './useUser';
import { useUsers } from './useUsers';

function App() {
  const [id, setId] = useState<number>(1);
  const { data } = useUser(id);
  const { users } = useUsers(2);
  const ref = useRef<HTMLInputElement>(null);

  const handleGetUser = () => {
    if (ref.current?.value) setId(Number(ref.current.value));
  };

  return (
    <>
      <h1>app</h1>
      <hr />
      <pre style={{ textAlign: 'left' }}>{JSON.stringify(users, null, 2)}</pre>
      <hr />
      <div>
        id : <input type="text" ref={ref} onChange={handleGetUser} />
      </div>
      <pre style={{ textAlign: 'left' }}>{JSON.stringify(data, null, 2)}</pre>
    </>
  );
}
export default App;

添付ファイル1
app.png ( 13.8 KBytes ) ダウンロード
No.2393
09/07 10:47

edit

添付ファイル