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

huangapple go评论89阅读模式
英文:

How to mock tRPC procedures with vitest and vitest-mock-extended on client side

问题

I'm trying to mock tRPC procedures so I don't need to run the tRPC backend application to run frontend unit tests. I've tried to use vitest-mock-extended's mock and mockDeep functions. The trpc client still tries to make a request over the network, and gets a connection refused error. vitest-mock-extended has worked for the trpc backend application.

Works with normal classes

  1. // When userService doesn't use tRPC, it's easy to mock.
  2. const userService = mock<UserService>();
  3. // Works. TypeScript suggests all the test functions
  4. userService.createUser.mockResolvedValueOnce({"name": "Fake test user"});

Doesn't work with tRPC procedures

  1. // When using tRPC, TypeScript doesn't find mockResolvedValueOnce
  2. const userService = mock<typeof context.services.trpcClient.userService>();
  3. // Doesn't work. Only `query` or `mutation` is shown.
  4. userService.createUser.mutation.mockResolvedValueOnce({"name": "Fake test user"});
  5. userService.getUser.query.mockResolvedValueOnce({"name": "Fake test user"});

I'm using tRPC, TypeScript, vitest, and vitest-mock-extended.

mockDeep attempt example

  1. const userService = mockDeep<typeof context.services.trpcClient.userService>>();
  2. missionManager.createUser.mutation.mockResolvedValueOnce({...});
  3. missionManager.createUser.query.mockResolvedValueOnce({...});

Has anyone successfully mocked trpc requests on the client side for e.g. a react/typescript application? Since tests are run by vitest, this is actually a Node/jsdom environment.

英文:

I'm trying to mock tRPC procedures so I don't need to run the tRPC backend application to run frontend unit tests. I've tried to use vitest-mock-extended's mock and mockDeep functions. The trpc client still tries to make a request over the network, and get's a connection refused error. vitest-mock-extended has worked for the trpc backend application.

Works with normal classes

  1. // When userService doesn&#39;t use tRPC, it&#39;s easy to mock.
  2. const userService = mock&lt;UserService&gt;();
  3. // Works. Typescript suggests all the test functions
  4. userService.createUser.mockResolvedValueOnce({&quot;name&quot;: &quot;Fake test user&quot;});

Doesn't work with tRPC procedures

  1. // When using tRPC, typescript doesn&#39;t find mockResolvedValueOnce
  2. const userService = mock&lt;typeof context.services.trpcClient.userService&gt;();
  3. // Doesn&#39;t work. only `query` or `mutation` is shown.
  4. userService.createUser.mutation.mockResolvedValueOnce({&quot;name&quot;: &quot;Fake test user&quot;});
  5. userService.getUser.query.mockResolvedValueOnce({&quot;name&quot;: &quot;Fake test user&quot;});

I'm using tRPC, typescript, vitest and vitest-mock-extended.

mockDeep attempt example

  1. const userService = mockDeep&lt;typeof context.services.trpcClient.userService&gt;&gt;();
  2. missionManager.createUser.mutation.mockResolvedValueOnce({...});
  3. missionManager.createUser.query.mockResolvedValueOnce({...});

Has anyone successfully mocked trpc requests on the client side for e.g. a react/typescript application. Since tests are run by vitest, this is actually a Node/jsdom environment.

答案1

得分: 4

I found msw-trpc which will allow you to use msw in a tRPC type-safe way. It works if you only use HTTPLink. Unfortunately, it doesn't support WebSockets (I use WsLink with tRPC in 1 project) so I created a Github issue. Alternatively, you could try combining mock-socket and a wrapper class to use your tRPC AppRouter type.

They haven't documented how to use it in vitest, so here's how I do it. Install dependencies: pnpm add -D vitest vitest-mock-extended msw msw-trpc.

How to use in tests

  1. import { AppRouter } from &quot;../trpc/appRouter&quot;;
  2. import { setupServer } from &quot;msw/node&quot;;
  3. import { createTRPCMsw } from &quot;msw-trpc&quot;;
  4. import { beforeEach, describe, it, vi } from &quot;vitest&quot;;
  5. import { mockDeep } from &#39;vitest-mock-extended&#39;;
  6. import { trpcClient } from &quot;./trpcClient&quot;;
  7. // You probably want to put this in a `setupTests.ts` so it runs in all tests.
  8. vi.mock(&quot;./trpcClient&quot;, () =&gt; {
  9. return {
  10. trpcClient: mockDeep(),
  11. };
  12. });
  13. export const trpcMsw = createTRPCMsw&lt;AppRouter&gt;();
  14. // You can create the responses, and change it for each test in vitest/jest.
  15. const server = setupServer();
  16. // Put any handlers you want to work for all tests.
  17. describe(&quot;Example class&quot;, () =&gt; {
  18. beforeEach(() =&gt; {
  19. server.resetHandlers(); // resets to the original handlers, which I did not set.
  20. });
  21. it(&quot;parses and loads products json into local SQLite database&quot;, async () =&gt; {
  22. server use trpcMsw.product.getProduct.query(async (req, res, ctx) =&gt; {
  23. // body is deprecated in msw, but the alternative req.json() is not typed...
  24. // const body = await req.json();
  25. // Do something with body.
  26. const body = req.body;
  27. return res(ctx.status(200), ctx.data(undefined));
  28. })
  29. );
  30. // Run some code, then run assertions.
  31. });
  32. // more tests...
  33. });
英文:

I found msw-trpc which will allow you to use msw in a tRPC type-safe way.

It works if you only use HTTPLink. Unfortunately, it doesn't support WebSockets (I use WsLink with tRPC in 1 project) so I created a Github issue. Alternatively, you could try combining mock-socket and a wrapper class to use your tRPC AppRouter type.

They haven't documented how to use it in vitest, so here's how I do it. Install dependencies: pnpm add -D vitest vitest-mock-extended msw msw-trpc.

How to use in tests

  1. import { AppRouter } from &quot;../trpc/appRouter&quot;;
  2. import { setupServer } from &quot;msw/node&quot;;
  3. import { createTRPCMsw } from &quot;msw-trpc&quot;;
  4. import { beforeEach, describe, it, vi } from &quot;vitest&quot;;
  5. import { mockDeep } from &#39;vitest-mock-extended&#39;;
  6. import { trpcClient } from &quot;./trpcClient&quot;;
  7. // You probably want to put this in a `setupTests.ts` so it runs in all tests.
  8. vi.mock(&quot;./trpcClient&quot;, () =&gt; {
  9. return {
  10. trpcClient: mockDeep(),
  11. };
  12. });
  13. export const trpcMsw = createTRPCMsw&lt;AppRouter&gt;();
  14. // You can create the responses, and change it for each test in vitest/jest.
  15. const server = setupServer();
  16. // Put any handlers you want to work for all tests.
  17. describe(&quot;Example class&quot;, () =&gt; {
  18. beforeEach(() =&gt; {
  19. server.resetHandlers(); // resets to the original handlers, which I did not set.
  20. });
  21. it(&quot;parses and loads products json into local SQLite database&quot;, async () =&gt; {
  22. server.use(
  23. trpcMsw.product.getProduct.query(async (req, res, ctx) =&gt; {
  24. // body is deprecated in msw, but the alternative req.json() is not typed...
  25. // const body = await req.json();
  26. // Do something with body.
  27. const body = req.body;
  28. return res(ctx.status(200), ctx.data(undefined));
  29. })
  30. );
  31. // Run some code, then run assertions.
  32. });
  33. // more tests...
  34. });

huangapple
  • 本文由 发表于 2023年4月4日 05:01:09
  • 转载请务必保留本文链接:https://go.coder-hub.com/75923729.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定