I have a Lit component that makes two AJAX calls to an external API:
1.
- Endpoint:
PUT /api/rest/books/
- Payload:
{ view: "VIEW_1", properties: { a: "abcde" } }
- Desired response: a random JSON let’s call it
mockResponse1
-
- Endpoint:
PUT /api/rest/books/
- Payload:
{ view: "VIEW_2", properties: { b: "1234" } }
- Desired response: a random JSON let’s call it
mockResponse2
- Endpoint:
Then, in Storybook, I am using @web/mocks which uses MSW under the hood:
import { registerMockRoutes } from '@web/mocks/browser.js';
import { http } from '@web/mocks/http.js';
...
export const main = () => html`<my-dummy-component></my-dummy-component>`;
main.parameters = {
...
mocks: [
http.put('/api/rest/books/', () => Response.json(mockResponse1)),
http.put('/api/rest/books/', () => Response.json(mockResponse2)) // <--- How to differentiate this call?
]
};
As expected, because the HTTP methods and endpoints are equal, both API calls return the same mockResponse1
, but this is not what I want.
I tried the following solution: create a single request handler that checks for a specific property in the request body (e.g., a unique identifier):
mocks: [
http.put('/api/rest/books', async ({request}) => {
const req = await request.json()
if(req.requestId === 1) return Response.json(mockResponse1)
if(req.requestId === 2) return Response.json(mockResponse2)
})
]
Problem: this works but I will be sending to the real server a property intended only for testing.
Idea 1: implement an HTTP interceptor for my API service that looks for a custom environment variable:
- If
isDev
is true (indicating a development or testing environment), add a callId to the payload. - If
isDev
is false (production build), omit therequestId
.
Idea 2: instead of modifying the payload, observe a property that I know will always be present. For instance, if request 1 consistently includes the property view: “VIEW_1” in its payload, use that as a basis for the mock handler. However, I become tightly coupled to the payload. What if, in the future, request 1 no longer needs to send view: "VIEW_1"
at all?
What do you think of these approaches?