-
-
Notifications
You must be signed in to change notification settings - Fork 334
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
fix: allow async overrideResponse to be passed to msw handler (issue #1389) #1390
Conversation
Hi, @severinh |
It's not just the type-checking that does not pass. The whole mock handler does not work correctly when passing an Orval only supports passing a non-async method right now. The following currently works in Orval: // Suppose the user passes the following overrideResponse function:
const overrideResponse = (info) => {
// Cannot get the request body from info, because that would require the method to be async
return {"field": "value"}
}
// Orval then does the following call
JSON.stringify(overrideResponse())
which outputs "{'field': 'value'}" However, suppose the user passes an async function: const overrideResponse = async (info) => {
// Do something async with info, such as reading the request body.
return {"field": "value"}
}
// Orval (before this PR) then does the following call
JSON.stringify(overrideResponse())
// This outputs "{}", which is wrong, because we're stringifying the Promise itself, not the awaited object.
// This needs `await overrideResponse()` to work Hope that helps. |
Thank you for your kindness. I understand that much, but what is the specific background of why I want to use |
Happy to clarify. There are two concrete use cases:
Here's what you can do in MSW: http.post("/greeting", async ({ request }) => {
const { firstName, lastName } = await request.json();
return { greeting: `Hello ${firstName} ${lastName}` }
}); The request body is only available via
Here's what you can do in MSW: http.post("/greeting", async ({ request }) => {
const { firstName, lastName } = await request.json();
expect(firstName).toEqual("Test");
expect(lastName).toEqual("Name");
return getGreetingResponseMock();
}); Neither of these is possible if you want to use an Orval mock handler. That means you have to fall back to hard-coding the paths - and not having to copy-paste paths across the code base is a major reason for using Orval in the first place. :) This is related to issue #1206 that I filed some time ago. Personally, I would have have advised against merging #1375, because it only allows partial flexibility. With the current method signature of Orval's mock handlers (introduced in #1375), you can only override the response body, but you cannot override the entire My preferred solution would have been for Orval mock handlers to look like this: export const getGreetingMockHandler = (override?: GreetingResponse | HttpResponseResolver<{ ... }, GreetingRequest, GreetingResponse>) => {
return http.post('/greeting', async (info) => {
return typeof override === 'function'
? await override(info)
: new HttpResponse(JSON.stringify(override !== undefined ? override : getGreetingResponseMock()), {
status: 200,
headers: {
'Content-Type': 'application/json',
},
});
});
};
// One could then use this Orval mock handler like this:
server.use(getGreetingMockHandler(async (info) => {
// Can produce a response based on the request, make assertions, set custom headers, etc.
return new HttpResponse(...);
}); This would be both simpler and more flexible than what #1375 introduced. But the problem is that since #1375 was already released in 0.29, this would be a backwards-incompatible change. Would that be a possibility? If yes, I'm happy to prepare a PR to make the mock handlers look like the above, solving #1206 too. |
First of all, regarding 1, you want to perform calculations in |
Thanks for the patience. I'm afraid I don't fully understand the question. What do you mean by "on the side that uses mocks"? Could you explain how you would do 1) with an Orval-provided MSW handler like Maybe what could be helpful context: I could of course say: "Fine, for cases like 1) and 2), I just won't use Orval, and instead write the MSW handlers from scratch with But as I mentioned in #1206, the main reason why we use Orval is exactly because it lets us avoid having to hard-code HTTP verbs and paths like |
OK. In short, it's not clear whether you want to use
|
Ah, now I understand the confusion.
To clarify, this PR:
This PR about accessing the HTTP request (!) that the application made to the MSW request handler, which is currently not possible with an Orval-created request handler. Probably my toy example 1) is too simple, so it's not clear why this would be useful. Right now, with Orval request handlers you can only use a static mock response object. No matter what request the application sends, the request handler will return the same response object. In the real server-side implementation of an API, the response will be produced based on the request. Now, it does not make sense to reimplement the real server implementation in a request handler. However, in specific cases, it can help to make the behavior of the request handler just small bit more realistic, by changing the response dynamically (!) based on what request the application made. But that requires access to the request that the application sent, and producing a response object based on that. But Orval currently does not allow that kind of access. Maybe for 2), I can give you a more realistic example, actually from our codebase. We have a functionality where the user can click a thumbs up/thumbs down button in the app, which sends a request to the server of the form server.use(
http.post('*/projects/:projectId/feedback', async ({ request }) => {
const { sentiment } = (await request.json()) as FeedbackRequest;
expect(sentiment).toBe('positive'); // Asserts that the right request is sent.
return HttpResponse.json(getRecordFeedbackMutationResponseMock());
})
);
await userEvent.click(screen.findByRole('button', { name: 'Useful' })); The above is not possible with Orval. I'd like to be able to write the following test using the Orval-generated server.use(
// Orval does not support this async function
getRecordFeedbackMutationResponseMockHandler(async ({ request }) => {
const { sentiment } = (await request.json()) as FeedbackRequest;
expect(sentiment).toBe('positive'); // Asserts that the right request is sent.
return getRecordFeedbackMutationResponseMock();
})
);
await userEvent.click(screen.findByRole('button', { name: 'Useful' })); How about the following: I'm fine with leaving this PR open for now, since it only addresses half of my problem. It only partially resolves #1206. If it's okay for you, I can try to write a new PR to solve #1206. And the solution to that would actually lead to cleaner generated code. I'm about to go on vacation though, so will not respond for a week. :) |
Hmm, I understand the scene you want to use. You want to reproduce the case where the Also, for example, if you want to test whether the well understood. I agree with this so I'll merge it. Thank you for teaching me so carefully. Let's discuss #1206 in an issue. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
thanks!
Status
READY
Description
Fix #1389.
In MSW, a mock handler can access the response resolver info. For example, it can access the request body to change the response based on the request. Access to that request body is only possible through an
async
function call tojson()
.In Orval, PR #1375 made it possible for the override in a MSW mock handler to be a function, and Orval passes the response resolver info to that function. However, Orval requires a synchronous method that returns a response object. It does not allow
async
functions.Before this PR, it was not possible to migrate the above mock handler to Orval. The following code would not type check:
This PR changes the code generation such that both
Promise<ResponseType> | ResponseType
is allowed as a return type for the override. This mirrors what MSW does.Related PRs
#1375