如何在客户端使用 vitest 和 vitest-mock-extend 模拟 tRPC 过程

Ben*_*rth 5 typescript vitest trpc.io

我正在尝试模拟 tRPC 过程,因此我不需要运行 tRPC 后端应用程序来运行前端单元测试。我尝试过使用vitest-mock-extendedmock函数mockDeeptrpc 客户端仍然尝试通过网络发出请求,并收到连接拒绝错误。vitest-mock-extended曾为 trpc 后端应用程序工作过。

适用于普通课程

// When userService doesn't use tRPC, it's easy to mock.
const userService = mock<UserService>();
// Works. Typescript suggests all the test functions
userService.createUser.mockResolvedValueOnce({"name": "Fake test user"});
Run Code Online (Sandbox Code Playgroud)

不适用于 tRPC 过程

// When using tRPC, typescript doesn't find mockResolvedValueOnce
const userService = mock<typeof context.services.trpcClient.userService>();
// Doesn't work. only `query` or `mutation` is shown.
userService.createUser.mutation.mockResolvedValueOnce({"name": "Fake test user"});
userService.getUser.query.mockResolvedValueOnce({"name": "Fake test user"});
Run Code Online (Sandbox Code Playgroud)

我正在使用 tRPC、typescript、vitest 和vitest-mock-extended

mockDeep 尝试示例

// When using tRPC, typescript doesn't find mockResolvedValueOnce
const userService = mock<typeof context.services.trpcClient.userService>();
// Doesn't work. only `query` or `mutation` is shown.
userService.createUser.mutation.mockResolvedValueOnce({"name": "Fake test user"});
userService.getUser.query.mockResolvedValueOnce({"name": "Fake test user"});
Run Code Online (Sandbox Code Playgroud)

有没有人在客户端成功模拟了 trpc 请求,例如反应/打字稿应用程序。由于测试是由 vitest 运行的,因此这实际上是一个 Node/jsdom 环境。

Ben*_*rth 4

我发现msw-trpc允许您以 tRPC 类型安全的方式使用 msw。

如果您只使用HTTPLink ,它就可以工作。不幸的是,它不支持 WebSockets(我在 1 个项目中使用 WsLink 和 tRPC),因此我创建了一个Github Issue。或者,您可以尝试组合mock-socket和包装类来使用您的 tRPC AppRouter 类型。

他们还没有记录如何在 vitest 中使用它,所以我是这样做的。安装依赖项:pnpm add -D vitest vitest-mock-extended msw msw-trpc.

测试中如何使用

import { AppRouter } from "../trpc/appRouter";
import { setupServer } from "msw/node";
import { createTRPCMsw } from "msw-trpc";
import { beforeEach, describe, it, vi } from "vitest";
import { mockDeep } from 'vitest-mock-extended';
import { trpcClient } from "./trpcClient";

// You probably want to put this in a `setupTests.ts` so it runs in all tests.
vi.mock("./trpcClient", () => {
  return {
    trpcClient: mockDeep(),
  };
});

export const trpcMsw = createTRPCMsw<AppRouter>();
// You can create the responses, and change it for each test in vitest/jest.
const server = setupServer();
// Put any handlers you want to work for all tests.

describe("Example class", () => {
  beforeEach(() => {
    server.resetHandlers(); // resets to the original handlers, which I did not set.
  });

  it("parses and loads products json into local SQLite database", async () => {
    server.use(
      trpcMsw.product.getProduct.query(async (req, res, ctx) => {
        // body is deprecated in msw, but the alternative req.json() is not typed...
        // const body = await req.json();
        // Do something with body.
        const body = req.body;
        return res(ctx.status(200), ctx.data(undefined));
      })
    );

    // Run some code, then run assertions.
  });

  // more tests...
});
Run Code Online (Sandbox Code Playgroud)