trpc
trpc copied to clipboard
Ability to add mocking of a tRPC server
Summary
- Add the ability to easily mock a tRPC backend for usage in things like storybook, jest, etc
Background
There are many use cases for mocking beyond "writing to a database.
Two that immediately come to mind for our use case:
- Using a mock API for stories (Storybook, Ladle). For this use case, even if we could use a real endpoint, it wouldn't be a good idea, as one generally wants to control the data and not have some gibberish mock data created by test users.
- Endpoints that go beyond database calls. We have a use case that requires a tight integration with many AWS services, including ones that would bill you a lot, if you were just creating these resources for testing. In this case also running a live API isn't even feasible locally. And deploying an actual API can take many minutes. So you can't even tear it down for each test.
I agree on integration > mocking premise in general. But there are some cases that are just not feasible without having mocks.
Originally posted by @moltar in https://github.com/trpc/trpc/discussions/1879#discussioncomment-3395657
Todos
- [ ] Create spec/RFC on how mocking should look like
- [ ] Implement said mocking
Funding
- You can sponsor this specific effort via a Polar.sh pledge below
- We receive the pledge once the issue is completed & verified
Create spec/RFC on how mocking should look like
Could this work?
Add an optional option.mock parameter to each function (api) returning from createTRPCProxyClient, the option.mock type should be the same as the return type form the function (api).
Example: import { setMock, createTRPCProxyClient } from "trpc/client";
const client = createTRPCProxyClient<AppRouter>({url, allowMocks: process.env.node_env != "production" );
// setting the mock for /posts setMock(client.posts, [{ id: 1, content: "post 1"}]);
Something like that?
@Yanipo5 @KATT I think mocking would be easy now that HTTP is decoupled from the client. One can create a mockLink that simply intercepts all requests. For example, maybe can use PollyJS for that.
I don't exactly understand that firm statement about testing. Intercepting and stubbing calls is super useful when working on the front end. You can quickly set up various cases and store all the code in the git repo.
I personally don't see the value in putting this into tRPC proper. I think it serves the library to keep it lean and recommend / provide examples for something like https://mswjs.io/
@KATT I agree it should be implemented.
For sure it's possible to hack in tests with Jest by trying to spyOn... but in some cases with want mocks at runtime. In my case I ended using msw to mock what the trpc could answer, but that's a real pain to think about network response format to be sure the tRPC client will be fine.
I think a trpc client middlewares logic could do the trick. When I would want the mock, I add a middleware at the first position, I do my "switch case" or whatever to have the consistent behavior and just return the needed result. In this case the middleware would not call the next() middleware, but still, it would allow people to do any trick they want.
The perfect solution and the more agnostic would be to wrap the trpc logic in a custom data repository that is easy to mock at initialisation... but since it's easier to use trpc with react-query sometimes, it makes things to complicated too go this way (since the React logic would be coupled with the repository in case of @trpc/react...).
@sneko could you share how you managed to mock it using msw? I tried with a rest handler but the trpc query is not intercepted
@meienberger it's currently spread across my project :s , but for reference I can advise you:
It was inspired by: https://gist.github.com/martin-fv/9bad75363245a16c918e112eb6a19f0d
The issues to follow for future improvements: https://github.com/trpc/trpc/discussions/1879 https://github.com/trpc/trpc/issues/2468 (this one :D )
@sneko thank you for sharing!
https://github.com/maloguertin/msw-trpc
Is https://github.com/maloguertin/msw-trpc the way to go for integrating storybook with trpc?