对同一个端点的多个响应的伪造者请求拦截最佳实践 [英] Puppeteer request interception best practice for multiple responses to the same endpoint
问题描述
对于单元测试,我拦截所有请求,然后以特定日期的模拟日期作为响应.我有一个 pageMockedRequests
函数,它将在端点上打开.
For my unit tests I intercept all requests and then responding with mocked date for specific endpoints. I have a pageMockedRequests
function that will switch on the endpoint.
当我想根据被调用的次数更改要发送回的响应时,就会遇到问题.
My issue comes when I want to change the response I am sending back depending on how many times it has been called.
const pageMockedRequests = (request) => {
switch (request.url()) {
case ENDPOINTS.A:
return request.respond(jsonResponseWrapper(returnValidToken(), 200));
case ENDPOINTS.B:
if (count === 0) {
return request.respond(jsonResponseWrapper({RESPONSE FOR 1st CALL}, 200));
} else if (count === 1) {
return request.respond(jsonResponseWrapper({RESPONSE FOR 2nd CALL}, 200));
}
default:
return request.abort();
}
};
上面显示,第二次 ENDPOINT.B
与第一次响应不同.我目前正在 count
上对其进行更改.
The above shows that ENDPOINT.B
for the second time will be different from the first response. I'm currently changing it on count
.
还有其他人这样做吗?
推荐答案
在只有两种可能的情况下,使用 if
或 switch
枚举每种情况都很好.但是,当您选择了3个或4个以上的选项时,环复杂性超出了可维护性.
Enumerating every case with an if
or switch
is fine when there's only a couple of possibilities. But when you wind up with more than 3 or 4 options, the cyclomatic complexity increases beyond maintainability.
可伸缩的方法使用的数据结构基本上是所有请求参数的查找表.一种方法是使用以URL为键的嵌套对象.每个URL指向一个由方法锁定的内部对象,该方法将一个响应数组作为键.对于每个响应数组,您可以保留一个索引计数器,该计数器在发送响应时会向前移动,或者通过弹出或移位来对该数组进行变异.
A scalable approach uses a data structure that is basically a lookup table for all of your request parameters. One approach is to use a nested object keyed by URL. Each URL points to an inner object keyed by method which keys to an array of responses. For each response array, you could keep an index counter that steps forward whenever responses are sent, or mutate the array by popping or shifting.
以下是这种方法的示意图:
Here's a sketch of this approach:
const responsesByEndpoint = {
"https://www.example.com/api/users": {
GET: [/* mocked responses */],
POST: [/* mocked responses */],
PUT: [/* mocked responses */],
DELETE: [/* mocked responses */],
},
"https://www.example.com/api/posts": {
GET: [/* mocked responses */],
POST: [/* mocked responses */],
},
"https://www.example.com/api/login": {
POST: [/* mocked responses */],
},
// ...
};
page.on("request", request => {
try {
const response = responsesByEndpoint
[request.url()][request.method()].shift()
;
if (response === undefined) {
throw Error;
}
request.respond(response);
}
catch (err) {
request.abort(); // or: request.continue();
}
});
通过端点和方法响应的数据结构是常规的,可以序列化为外部文件,尽管您可能需要添加 body:async()=>({"your":"body"})
在反序列化期间使用前每个响应的功能.
The data structure of responses by endpoint and method is regular and can be serialized as an external file, although you may need to add body: async () => ({"your": "body"})
functions per response before use during deserialization.
这种方法还可以很好地处理错误请求,而无需更改任何代码或不添加到 switch
或 if
- else
链中.
This approach also nicely handles bad requests without changing any code or adding to your switch
or if
-else
chain.
如果您偶尔需要重置模拟,请使用测试运行器的 beforeEach
块或编写一个将其重新生成的函数.
If you need to reset your mocks occasionally, use your test runner's beforeEach
block or write a function that returns it fresh.
即使您没有使用这种精确的模拟方法,这种模式也是通用的,应该使您免于 if
/ switch
悲伤.
Even if you're not using this exact mocking approach, this pattern is generic and should save you from if
/switch
sadness.
这篇关于对同一个端点的多个响应的伪造者请求拦截最佳实践的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!