msw-trpc

repository·main·Indexed 42 days ago

https://github.com/maloguertin/msw-trpc

A utility for Mock Service Worker (MSW) that provides tRPC support, allowing developers to create type-safe MSW handlers directly from their tRPC router. It enables mocking tRPC API calls in tests using functions like createTRPCMsw to maintain full type inference from the AppRouter. Version 2.0.1 requires tRPC server v11 and MSW v2; tRPC batching is currently not supported.

Tokens
2.7K
Snippets
12
Records
14
Agent score
54%

What's inside msw-trpc

  1. Create tRPC MSW handlers with createTRPCMsw

    main

    Use createTRPCMsw to generate a proxy object that infers types from your tRPC AppRouter. This proxy allows you to define MSW handlers for your queries and mutations using a syntax similar to the tRPC client.

    Note: You must provide a links configuration (similar to a tRPC client) to createTRPCMsw.

    import { createTRPCMsw } from 'msw-trpc'
    import type { AppRouter } from 'path/to/your/router'
    
    export const trpcMsw = createTRPCMsw<AppRouter>({ 
      links: [ /* your tRPC links here */ ] 
    })
  2. Configure createTRPCMsw

    main

    The createTRPCMsw function accepts a configuration object of type TRPCMswConfig to define how the mocked requests are handled and how data is transformed.

    Configuration Options:

    • links: An array of tRPC Link objects (required). This is used to define the transport layer, just as you would in a tRPC client.
    • transformer: An optional TRPCCombinedDataTransformer (e.g., superjson) to handle data serialization/deserialization.
    interface TRPCMswConfig {
      links: Link[]
      transformer?: TRPCCombinedDataTransformer
    }
  3. Use msw-trpc to mock tRPC queries and mutations

    main

    Once trpcMsw is created, you can use its .query() and .mutation() methods to define handlers for your MSW server. The methods accept a function that returns the mocked data.

    • trpcMsw.[path].query(() => data): Mocks a tRPC query.
    • trpcMsw.[path].mutation((input) => data): Mocks a tRPC mutation.
    import { setupServer } from 'msw/node'
    import { trpcMsw } from './your-trpc-msw-file'
    
    const server = setupServer(
      trpcMsw.userById.query(() => ({ id: '1', name: 'Uncle bob' })),
      trpcMsw.createUser.mutation((name) => ({ id: '2', name }))
    )
  4. Configure `trpc.query` and `trpc.mutation` options

    main

    The opts object (of type TRPCMswConfig) passed to trpc.query and trpc.mutation supports the following configuration:

    • links: An array of Link functions. Currently, only a single link is supported. The library will throw an error if zero or more than one link is provided.
    • transformer: (Optional) A TRPCCombinedDataTransformer used to serialize and deserialize input and output data. If not provided, it defaults to defaultTransformer from @trpc/server.
  5. Configure msw-trpc with TRPCMswConfig

    main

    When setting up msw-trpc, you use the TRPCMswConfig interface to define how the MSW handlers are generated. It requires a links array and optionally accepts a transformer to ensure data transformation matches your tRPC server configuration.

    • links: An array of Link objects defining the mapping between tRPC procedures and MSW request handlers.
    • transformer: An optional TRPCCombinedDataTransformer used to handle data serialization/deserialization (e.g., superjson).
    import type { TRPCMswConfig } from 'msw-trpc';
    
    const config: TRPCMswConfig = {
      links: [ /* ... your links ... */ ],
      transformer: superjson, // If using a transformer
    };
  6. Requirements and Limitations for msw-trpc

    main

    To use msw-trpc, ensure your environment meets the following requirements:

    Peer Dependencies:

    • tRPC server v11 (@trpc/server@next)
    • msw (v2 recommended)

    Limitations:

    • Batching: tRPC batching is not yet supported.
  7. Route operations using splitLink

    main

    Use splitLink to conditionally route tRPC operations to different links based on the operation's properties. The condition function receives a subset of the tRPC Operation (specifically type and path) and returns a boolean. If true, the operation is routed to the true link; otherwise, it goes to the false link.

    import { httpLink, splitLink } from 'msw-trpc';
    
    const link = splitLink({
      condition: (op) => op.path.startsWith('/admin'),
      true: httpLink({ url: 'https://admin.api.com' }),
      false: httpLink({ url: 'https://public.api.com' }),
    });
  8. Define tRPC MSW handlers with `trpc.query` and `trpc.mutation`

    main

    Use the trpc object to create MSW handlers that intercept tRPC requests. You can define handlers for both queries and mutations by providing the procedure path and a handler function that simulates the server logic.

    • trpc.query(path, handler, opts): Creates a handler for tRPC queries. It expects the input to be provided via a URL search parameter named input.
    • trpc.mutation(path, handler, opts): Creates a handler for tRPC mutations. It expects the input to be provided in the request body.

    Both methods require an opts object containing links (an array of Link functions) and an optional transformer.

    import { trpc } from 'msw-trpc'
    
    // Example query handler
    const queryHandler = trpc.query('user.getById', async ({ input }) => {
      return { id: input.id, name: 'John Doe' }
    }, {
      links: [myLink]
    })
    
    // Example mutation handler
    const mutationHandler = trpc.mutation('user.update', async ({ input }) => {
      return { success: true }
    }, {
      links: [myLink]
    })
  9. Define procedure handlers with MswTrpc

    main

    The MswTrpc type defines the shape of the object you use to mock your tRPC procedures. It is a deeply nested structure that mirrors your tRPC router's shape. For every query or mutation in your router, you must provide a handler function.

    Each handler receives an object containing the input (inferred from your tRPC procedure) and must return a PromiseOrValue of the procedure's output.

    Example structure:

    // If your router has: router.user.getById.query(...)
    // Your MswTrpc object will look like:
    {
      user: {
        getById: {
          query: ({ input }) => { /* return mocked data */ }
        }
      }
    }
    // Conceptual usage of the MswTrpc type structure
    type MyMswHandlers = MswTrpc<MyRouter>;
    
    const handlers: MyMswHandlers = {
      user: {
        getById: {
          query: async ({ input }) => {
            // input is automatically typed based on the tRPC procedure
            return { id: input.id, name: 'Mock User' };
          }
        }
      }
    };
  10. Use msw-trpc to create MSW handlers for tRPC

    main

    The msw-trpc package provides utilities to intercept tRPC network requests using Mock Service Worker (MSW). The primary entry point is the createMSW function (exported from ./create.js), which allows you to generate MSW handlers based on your tRPC router definition. This enables mocking tRPC APIs in tests or development environments without a running backend.

    import { createMSW } from 'msw-trpc';
    
    // Example usage pattern:
    // const handlers = createMSW(yourRouter);
  11. Use msw-trpc links for tRPC client mocking

    main

    The package exports link utilities (from ./links.js) designed to work with the tRPC client. These links allow you to redirect tRPC calls to MSW handlers, facilitating seamless integration between your tRPC client and the mocked network layer.

    import { mswLink } from 'msw-trpc';
    
    // Example usage pattern:
    // const client = createTRPCProxyClient<AppRouter>({
    //   links: [
    //     mswLink(),
    //     httpLink(),
    //   ],
    // });