Closed juanca closed 3 years ago
Hey, @juanca.
As the warning rightfully stands, the ?accumulated_time=0
is a redundant part of the request handler's URL. See the reason why.
Query parameters are parameters—arguments sent to a resource on the server. They don't represent a path to the resource:
/api/v1/timer/start
?accumulated_time
When you construct a REST request handler, the first argument you give to it is a resource path:
rest.put('/api/v1/timer/start', resolver)
You can access all query parameters in req.url.searchParams
:
rest('/api/v1/timer/start', (req, res, ctx) => {
const accumulatedTime = req.url.searchParams.get('accumulated_time')
})
rest('/api/v1/timer/start', (req, res, ctx) => {
if (req.url.searchParams.has('accumulated_time')) {
// No "?accumulated_time" query parameter present—bypass this request.
return
}
// Query parameter is present! Mocking the response...
return res(ctx.json({ time: req.uql.searchParams.get('accumulated_time') })
})
I highly suggest reading about Path matching, which illustrates different ways to capture a request and their difference.
If that's the case then I think there's a bug. I have a handler that follows your suggestions and it does not "match". I have to specify the search params in the path in order for MSW to "match" it.
Or am I misunderstanding the order of precedence for handlers? Is it FIFO or LIFO?
The first matching handler that returns a mocked response is used:
If you have the handlers set up literally as in the code example above, then:
rest.put('/api/v1/timer/start')
handler is used if the request satisfies its if (isEqualWith(params, { accumulated_time: 0 })) {
condition.rest.put('/api/v1/timer/start?accumulated_time=0'
, which always returns a mocked response, so it will be used.Query parameters are dropped entirely by MSW when comparing matching URLs. All three of your request handlers will match as they are identical in terms of the request path. The first one that produces a mocked response will be used.
I see little value in having three handlers set up for the same request URL. I suggest merging them into a single handler if you need some complex logic, like conditional responses.
This is the handler that will match PUT /api/v1/timer/start
:
rest.put('/api/v1/timer/start', (req, res, ctx) => {
return res(ctx.json({ matches: true })
})
If something isn't mocked when it should be, always follow these guidelines.
- The
rest.put('/api/v1/timer/start')
handler is used if the request satisfies itsif (isEqualWith(params, { accumulated_time: 0 })) {
condition.- If not, lookup jumps to the next matching handler:
rest.put('/api/v1/timer/start?accumulated_time=0'
, which always returns a mocked response, so it will be used.
D:
This is good to know! I've been stuffing my handlers with a bunch of if(...)
s.
But I digress.
Okay, I think perhaps there is something wrong with my isEqualWith
. I'll look into it.
Okay, the lesson here is:
The values of the search parameters are always strings. This was a lesson I learned after making this issue. Comparing the integer 0
and string 0
was the crux of the issue here.
@kettanaito Thanks for the explanation, it helped pinpoint the problem.
Environment
Request handlers
Then the actual test:
Actual request
Current behavior
I am having trouble figuring out how to properly mock a PUT request.
As you can see in the handlers, I am testing out which of the 3 possible ways to specify the handler URL. The test warns about it not using the ideal pattern. See screenshot of dev tools:
And here is the preview of the response:
In addition, I am not sure why the worker is 404ing -- almost like it is forwarding the request? Probably not related but here is a screenshot of the details:
Expected behavior
I expect the service worker to intercept the PUT request with the proper URL and without any parameters specified. Just like a GET request.