How do you mock different responses in real life? #1117
-
👋 Hello hello! I'm kinda new to this mocking thing, and I'm struggling implementing a proper developer experience to test different cases. Let's take the following scenario for example: a user wants to browse our home page, which fires a requests to our API. flowchart LR
User -- browse --> /home
/home -- calls --> /api/articles/latest
Note that the endpoint is static, meaning that we do not pass any path param, query param, custom headers, etc. Every request to the home page will fire the exact same API request. Nothing changes on that side. However, I'd still like to mock different responses:
So, here are what my handlers could look like: export const handlers = [
rest.get('/api/articles/latest', (request, response, context) => {
// Sad path
if (...) {
return response(
context.status(500),
context.json({ error: 'oops!' }),
)
}
// Happy path
return response(
context.status(200),
context.json({ data: 'some-random-fake-data' }),
)
}),
] And, we're approaching what I'm struggling with: What to define as Since the API call is entirely static, I can't use anything to differentiate both of them. One way, would obviously be to add such dynamic parameter, but it would introduce something that will only be used to test the application, and never in production. Which does not look great in my opinion. So, here I am, asking the community for advice. How do you handle such cases on your side? Is there another solution that I didn't think of? 🙏 |
Beta Was this translation helpful? Give feedback.
Replies: 7 comments 25 replies
-
Hey, @antoinerey. Thanks for raising this, it's a great question. One great thing is that the handlers you write are still regular JavaScript code executed on the client. This means they have the entire client context, not only the intercepted request. I've seen a great pattern where developers controlled what API responses MSW returns by using the URL query parameters: export const handlers = [
rest.get('/api/articles/latest', (request, response, context) => {
const pageParams = new URLSearchParams(window.location.search)
const scenario = pageParams.get('scenario')
// Sad path
if (scenario === 'error') {
return response(
context.status(500),
context.json({ error: 'oops!' }),
)
}
// Happy path
return response(
context.status(200),
context.json({ data: 'some-random-fake-data' }),
)
}), Note that Since there's no request information to base the conditional mocked responses on, then the next upper context—like the Node.jsIf you want to make this endpoint respond with different mocked responses in a Node.js test, for example, use the server.use() function: it('success path', () => {
// no changes to the handler
})
it('error path', () => {
server.use(
rest.get('/api/articles/latest', (req, res, ctx) => res(ctx.status(500))
)
// the rest of the test
})
|
Beta Was this translation helpful? Give feedback.
-
@antoinerey I had exactly the same issue, but solved it differently. Instead of hardcoding the different scenarios in the mock handler, you could define different handlers and switch between them on runtime. I created a package that solves this problem for you: It cannot leverange MSW as being a service worker inside your app, but it reuses the response composition features of MSW. |
Beta Was this translation helpful? Give feedback.
-
How do you test GQL that calls the same query or mutation multiple times in the same test (with the same or no args)? |
Beta Was this translation helpful? Give feedback.
-
Thanks, that is what I ended up doing.
…On Mon., Jul. 11, 2022, 5:43 p.m. Artem Zakharchenko, < ***@***.***> wrote:
Hey, @coler-j <https://github.com/coler-j>.
Since all those requests will hit the same request handler, and you don't
have any payload to distinguish them (different headers/parameters/body),
then you'd have to track their call order.
You can do that by declaring your response resolver as a generator
function:
import { graphql } from 'msw'
export const handlers = [
graphql.query('GetPosts', function* (req, res, ctx) {
let requestNumber = 1
const data = getDataByRequestNumber(requestNumber)
requestNumber++
yield res(ctx.data(data))
})]
You can take a look at our integration test
<https://github.com/mswjs/msw/blob/6990c3a57a1f515fe977c2eaa7741005b885b8af/test/rest-api/generator.mocks.ts#L4>
for inspiration. I'm not proficient with generators, so perhaps you'd have
to issue a regular return at some point.
—
Reply to this email directly, view it on GitHub
<#1117 (reply in thread)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AB3Z672TAAZV72MFW7ECTJDVTSIRVANCNFSM5PEZFFMQ>
.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
Beta Was this translation helpful? Give feedback.
-
Beta Was this translation helpful? Give feedback.
-
I am working on a project that will allow for making MSW mocks dynamic and allows you to create scenarios out of multiple dynamic mocks. It also includes a dashboard that is framework independent and does not resort to the MSW HTTP middleware. It has not been tested properly so I would not recommend using it just yet outside of proof of concepts. It is a work in progress. The source code is still a bit messy/complex and barely has any documentation. The UI is not styled properly either and missing some functionality. As I see it now, the API should be pretty stable, apart from the I am just dropping this here in case anyone wants to keep track of it and perhaps share some early feedback or even contribute. https://github.com/dynamicmsw/dynamic-msw |
Beta Was this translation helpful? Give feedback.
-
parse the data from url or body. We can set up a set of test logic. |
Beta Was this translation helpful? Give feedback.
Hey, @antoinerey. Thanks for raising this, it's a great question.
One great thing is that the handlers you write are still regular JavaScript code executed on the client. This means they have the entire client context, not only the intercepted request. I've seen a great pattern where developers controlled what API responses MSW returns by using the URL query parameters: