Connectクライアントをテストする(フロントエンド)
msw を使ってテストする。msw 自体はMSW(Mock Service Worker)とはで書いた。
npm install --save-dev mswここではブラウザを使わないので、npx msw init public は必要ない。また、MSWで型安全にConnectの通信をモックするのように型安全にできるといいのだが、この記事はv1時代のもので、v2ではうまくいかなかった。
ファイルレイアウト
Section titled “ファイルレイアウト”フロントエンドのディレクトリ構造ベストプラクティスに従って、以下のように配置する。
features/ wallet/ api/ index.test.ts index.ts testing/ mocks/ handlers.ts server.tshandlers
Section titled “handlers”まずはハンドラから書く。
import { http, HttpResponse } from "msw";import { WalletService } from "../../../../../proto/gen/wallet/v1/wallet_pb";
export const handlers = [ http.all( `http://localhost:8080/${WalletService.typeName}/CreateMerchant`, () => { return HttpResponse.json({ id: "999" }, { status: 200 }); }, ),]server
Section titled “server”ハンドラを使ったサーバを書く。
import { setupServer } from "msw/node";import { handlers } from "./handlers.js";
export const server = setupServer(...handlers);クライアント
Section titled “クライアント”クライアントの実装は単純に createClient するだけ。ここで型の検査と変換をしてもいいが、やってない。
import type { Client } from "@connectrpc/connect";import { createClient } from "@connectrpc/connect";import { createConnectTransport } from "@connectrpc/connect-web";import { WalletService } from "../../../../proto/gen/wallet/v1/wallet_pb.js";
export function createWalletClient( baseUrl: string,): Client<typeof WalletService> { const transport = createConnectTransport({ baseUrl }); return createClient(WalletService, transport);}テストは素朴に書く。エラーはErrors | Connectに書かれている通りに返せばいい。
describe("WalletClinet", () => { describe("createMerchant", () => { it("should return a new id", async () => { const { id } = await client.createMerchant({ name: "New Shop", categoryId: "345", }); expect(id).toBe("999"); }); it("should raise an error when something happen", async () => { server.use( http.all( `http://localhost:8080/${WalletService.typeName}/CreateMerchant`, () => { return HttpResponse.json( { code: "invalid_argument", message: "aaa", }, { status: 400 }, ); }, ), ); let error: ConnectError | undefined = undefined; try { await client.createMerchant({ ... }); } catch (e) { if (e instanceof ConnectError) { error = e; } } expect(error?.code).toBe(Code.InvalidArgument); expect(error?.rawMessage).toBe("aaa"); }); });});