automation_model 1.0.843-dev → 1.0.844-dev
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/route.d.ts +61 -2
- package/lib/route.js +320 -257
- package/lib/route.js.map +1 -1
- package/lib/stable_browser.js +5 -0
- package/lib/stable_browser.js.map +1 -1
- package/package.json +1 -1
package/lib/route.js
CHANGED
|
@@ -91,7 +91,267 @@ function matchRoute(routeItem, req) {
|
|
|
91
91
|
pathFilter(routeItem.filters.path, url.pathname) &&
|
|
92
92
|
queryParamsFilter(queryParams, url.searchParams));
|
|
93
93
|
}
|
|
94
|
+
function handleAbortRequest(action, context) {
|
|
95
|
+
if (context.tracking.timer)
|
|
96
|
+
clearTimeout(context.tracking.timer);
|
|
97
|
+
const errorCode = action.config?.errorCode ?? "failed";
|
|
98
|
+
console.log(`[abort_request] Aborting with error code: ${errorCode}`);
|
|
99
|
+
context.route.abort(errorCode);
|
|
100
|
+
context.abortActionPerformed = true;
|
|
101
|
+
context.tracking.completed = true;
|
|
102
|
+
return {
|
|
103
|
+
type: action.type,
|
|
104
|
+
description: JSON.stringify(action.config),
|
|
105
|
+
status: "success",
|
|
106
|
+
message: `Request aborted with code: ${errorCode}`,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
function handleStatusCodeVerification(action, context) {
|
|
110
|
+
const isSuccess = String(context.status) === String(action.config);
|
|
111
|
+
return {
|
|
112
|
+
type: action.type,
|
|
113
|
+
description: JSON.stringify(action.config),
|
|
114
|
+
status: isSuccess ? "success" : "fail",
|
|
115
|
+
message: `Status code verification ${isSuccess ? "passed" : "failed"}. Expected ${action.config}, got ${context.status}`,
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function handleJsonModify(action, context) {
|
|
119
|
+
if (!context.json) {
|
|
120
|
+
return {
|
|
121
|
+
type: action.type,
|
|
122
|
+
description: JSON.stringify(action.config),
|
|
123
|
+
status: "fail",
|
|
124
|
+
message: "JSON modification failed. Response is not JSON",
|
|
125
|
+
};
|
|
126
|
+
}
|
|
127
|
+
objectPath.set(context.json, action.config.path, action.config.modifyValue);
|
|
128
|
+
context.finalBody = JSON.parse(JSON.stringify(context.json));
|
|
129
|
+
return {
|
|
130
|
+
type: action.type,
|
|
131
|
+
description: JSON.stringify(action.config),
|
|
132
|
+
status: "success",
|
|
133
|
+
message: `JSON modified at path '${action.config.path}'`,
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function handleJsonWholeModify(action, context) {
|
|
137
|
+
if (!context.json) {
|
|
138
|
+
return {
|
|
139
|
+
type: action.type,
|
|
140
|
+
description: JSON.stringify(action.config),
|
|
141
|
+
status: "fail",
|
|
142
|
+
message: "JSON modification failed. Response is not JSON",
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
try {
|
|
146
|
+
const parsedConfig = typeof action.config === "string" ? JSON.parse(action.config) : action.config;
|
|
147
|
+
context.json = parsedConfig;
|
|
148
|
+
context.finalBody = JSON.parse(JSON.stringify(context.json));
|
|
149
|
+
return {
|
|
150
|
+
type: action.type,
|
|
151
|
+
description: JSON.stringify(action.config),
|
|
152
|
+
status: "success",
|
|
153
|
+
message: "Whole JSON body was replaced.",
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
catch (e) {
|
|
157
|
+
const message = `JSON modification failed. Invalid JSON in config: ${e instanceof Error ? e.message : String(e)}`;
|
|
158
|
+
return { type: action.type, description: JSON.stringify(action.config), status: "fail", message };
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
function handleStatusCodeChange(action, context) {
|
|
162
|
+
context.status = Number(action.config);
|
|
163
|
+
return {
|
|
164
|
+
type: action.type,
|
|
165
|
+
description: JSON.stringify(action.config),
|
|
166
|
+
status: "success",
|
|
167
|
+
message: `Status code changed to ${context.status}`,
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
function handleChangeText(action, context) {
|
|
171
|
+
if (context.isBinary) {
|
|
172
|
+
return {
|
|
173
|
+
type: action.type,
|
|
174
|
+
description: JSON.stringify(action.config),
|
|
175
|
+
status: "fail",
|
|
176
|
+
message: "Change text action failed. Body is not text.",
|
|
177
|
+
};
|
|
178
|
+
}
|
|
179
|
+
context.body = action.config;
|
|
180
|
+
context.finalBody = context.body;
|
|
181
|
+
return {
|
|
182
|
+
type: action.type,
|
|
183
|
+
description: JSON.stringify(action.config),
|
|
184
|
+
status: "success",
|
|
185
|
+
message: "Response body text was replaced.",
|
|
186
|
+
};
|
|
187
|
+
}
|
|
188
|
+
function handleAssertJson(action, context) {
|
|
189
|
+
if (!context.json) {
|
|
190
|
+
return {
|
|
191
|
+
type: action.type,
|
|
192
|
+
description: JSON.stringify(action.config),
|
|
193
|
+
status: "fail",
|
|
194
|
+
message: "JSON assertion failed. Response is not JSON.",
|
|
195
|
+
};
|
|
196
|
+
}
|
|
197
|
+
const actual = objectPath.get(context.json, action.config.path);
|
|
198
|
+
const expected = action.config.expectedValue;
|
|
199
|
+
const isSuccess = JSON.stringify(actual) === JSON.stringify(expected);
|
|
200
|
+
return {
|
|
201
|
+
type: action.type,
|
|
202
|
+
description: JSON.stringify(action.config),
|
|
203
|
+
status: isSuccess ? "success" : "fail",
|
|
204
|
+
message: isSuccess
|
|
205
|
+
? `JSON assertion passed for path '${action.config.path}'.`
|
|
206
|
+
: `JSON assertion failed for path '${action.config.path}': expected ${JSON.stringify(expected)}, got ${JSON.stringify(actual)}`,
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
function handleAssertWholeJson(action, context) {
|
|
210
|
+
if (!context.json) {
|
|
211
|
+
return {
|
|
212
|
+
type: action.type,
|
|
213
|
+
description: JSON.stringify(action.config),
|
|
214
|
+
status: "fail",
|
|
215
|
+
message: "Whole JSON assertion failed. Response is not JSON.",
|
|
216
|
+
};
|
|
217
|
+
}
|
|
218
|
+
const originalJSON = JSON.stringify(context.json, null, 2);
|
|
219
|
+
let isSuccess = false;
|
|
220
|
+
let message = "";
|
|
221
|
+
if ("contains" in action.config) {
|
|
222
|
+
isSuccess = originalJSON.includes(action.config.contains);
|
|
223
|
+
message = isSuccess
|
|
224
|
+
? "Whole JSON assertion passed."
|
|
225
|
+
: `Whole JSON assertion failed. Expected to contain: "${action.config.contains}".`;
|
|
226
|
+
}
|
|
227
|
+
else {
|
|
228
|
+
isSuccess = originalJSON === action.config.equals;
|
|
229
|
+
message = isSuccess
|
|
230
|
+
? "Whole JSON assertion passed."
|
|
231
|
+
: `Whole JSON assertion failed. Expected exact match: "${action.config.equals}".`;
|
|
232
|
+
}
|
|
233
|
+
return {
|
|
234
|
+
type: action.type,
|
|
235
|
+
description: JSON.stringify(action.config),
|
|
236
|
+
status: isSuccess ? "success" : "fail",
|
|
237
|
+
message,
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
function handleAssertText(action, context) {
|
|
241
|
+
if (typeof context.body !== "string") {
|
|
242
|
+
return {
|
|
243
|
+
type: action.type,
|
|
244
|
+
description: JSON.stringify(action.config),
|
|
245
|
+
status: "fail",
|
|
246
|
+
message: "Text assertion failed. Body is not text.",
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
let isSuccess = false;
|
|
250
|
+
let message = "";
|
|
251
|
+
if ("contains" in action.config) {
|
|
252
|
+
isSuccess = context.body.includes(action.config.contains);
|
|
253
|
+
message = isSuccess
|
|
254
|
+
? "Text assertion passed."
|
|
255
|
+
: `Text assertion failed. Expected to contain: "${action.config.contains}".`;
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
isSuccess = context.body === action.config.equals;
|
|
259
|
+
message = isSuccess
|
|
260
|
+
? "Text assertion passed."
|
|
261
|
+
: `Text assertion failed. Expected exact match: "${action.config.equals}".`;
|
|
262
|
+
}
|
|
263
|
+
return {
|
|
264
|
+
type: action.type,
|
|
265
|
+
description: JSON.stringify(action.config),
|
|
266
|
+
status: isSuccess ? "success" : "fail",
|
|
267
|
+
message,
|
|
268
|
+
};
|
|
269
|
+
}
|
|
270
|
+
function handleStubAction(stubAction, route, tracking) {
|
|
271
|
+
let actionStatus = "success";
|
|
272
|
+
const description = JSON.stringify(stubAction.config);
|
|
273
|
+
const request = route.request();
|
|
274
|
+
let stubActionPerformed = false;
|
|
275
|
+
debug(`Stub action found for ${request.url()}. Skipping fetch.`);
|
|
276
|
+
if (tracking.timer)
|
|
277
|
+
clearTimeout(tracking.timer);
|
|
278
|
+
const fullFillConfig = {};
|
|
279
|
+
if (!tracking.actionResults)
|
|
280
|
+
tracking.actionResults = [];
|
|
281
|
+
if (stubAction.config.path) {
|
|
282
|
+
const filePath = path.join(process.cwd(), "data", "fixtures", stubAction.config.path);
|
|
283
|
+
debug(`Stub action file path: ${filePath}`);
|
|
284
|
+
if (existsSync(filePath)) {
|
|
285
|
+
fullFillConfig.path = filePath;
|
|
286
|
+
debug(`Stub action fulfilled with file: ${filePath}`);
|
|
287
|
+
}
|
|
288
|
+
else {
|
|
289
|
+
actionStatus = "fail";
|
|
290
|
+
tracking.actionResults.push({
|
|
291
|
+
type: "stub_request",
|
|
292
|
+
description,
|
|
293
|
+
status: actionStatus,
|
|
294
|
+
message: `Stub action failed for ${tracking.url}: File not found at ${filePath}`,
|
|
295
|
+
});
|
|
296
|
+
stubActionPerformed = true;
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
if (!fullFillConfig.path) {
|
|
300
|
+
if (stubAction.config.statusCode) {
|
|
301
|
+
fullFillConfig.status = Number(stubAction.config.statusCode);
|
|
302
|
+
}
|
|
303
|
+
if (stubAction.config.contentType) {
|
|
304
|
+
if (stubAction.config.contentType === "application/json") {
|
|
305
|
+
fullFillConfig.contentType = "application/json";
|
|
306
|
+
if (stubAction.config.body) {
|
|
307
|
+
try {
|
|
308
|
+
fullFillConfig.json = JSON.parse(stubAction.config.body);
|
|
309
|
+
}
|
|
310
|
+
catch (e) {
|
|
311
|
+
debug(`Invalid JSON in stub action body: ${stubAction.config.body}, `, e instanceof Error ? e.message : String(e));
|
|
312
|
+
debug("Invalid JSON, defaulting to empty object");
|
|
313
|
+
fullFillConfig.json = {};
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
else {
|
|
318
|
+
fullFillConfig.contentType = stubAction.config.contentType;
|
|
319
|
+
fullFillConfig.body = stubAction.config.body || "";
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
if (!fullFillConfig.json && !fullFillConfig.body) {
|
|
323
|
+
if (stubAction.config.body) {
|
|
324
|
+
fullFillConfig.body = stubAction.config.body;
|
|
325
|
+
}
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
if (actionStatus === "success") {
|
|
329
|
+
try {
|
|
330
|
+
route.fulfill(fullFillConfig);
|
|
331
|
+
stubActionPerformed = true;
|
|
332
|
+
tracking.completed = true;
|
|
333
|
+
tracking.actionResults.push({
|
|
334
|
+
type: "stub_request",
|
|
335
|
+
description,
|
|
336
|
+
status: actionStatus,
|
|
337
|
+
message: `Stub action executed for ${request.url()}`,
|
|
338
|
+
});
|
|
339
|
+
}
|
|
340
|
+
catch (e) {
|
|
341
|
+
actionStatus = "fail";
|
|
342
|
+
debug(`Failed to fulfill stub request for ${request.url()}`, e);
|
|
343
|
+
tracking.actionResults.push({
|
|
344
|
+
type: "stub_request",
|
|
345
|
+
description,
|
|
346
|
+
status: actionStatus,
|
|
347
|
+
message: `Stub action failed for ${request.url()}: ${e instanceof Error ? e.message : String(e)}`,
|
|
348
|
+
});
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
return stubActionPerformed;
|
|
352
|
+
}
|
|
94
353
|
export async function registerBeforeStepRoutes(context, stepName, world) {
|
|
354
|
+
const debug = createDebug("automation_model:route:registerBeforeStepRoutes");
|
|
95
355
|
const page = context.web.page;
|
|
96
356
|
if (!page)
|
|
97
357
|
throw new Error("context.web.page is missing");
|
|
@@ -103,22 +363,35 @@ export async function registerBeforeStepRoutes(context, stepName, world) {
|
|
|
103
363
|
}
|
|
104
364
|
for (let i = 0; i < allRouteItems.length; i++) {
|
|
105
365
|
const item = allRouteItems[i];
|
|
366
|
+
debug(`Setting up mandatory route with timeout ${item.timeout}ms: ${JSON.stringify(item.filters)}`);
|
|
367
|
+
let content = JSON.stringify(item);
|
|
368
|
+
try {
|
|
369
|
+
content = await replaceWithLocalTestData(content, context.web.world, true, false, content, context.web, false);
|
|
370
|
+
allRouteItems[i] = JSON.parse(content); // Modify the original array
|
|
371
|
+
debug(`After replacing test data: ${JSON.stringify(allRouteItems[i])}`);
|
|
372
|
+
}
|
|
373
|
+
catch (error) {
|
|
374
|
+
debug("Error replacing test data:", error);
|
|
375
|
+
}
|
|
106
376
|
if (item.mandatory) {
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
377
|
+
const path = item.filters.path;
|
|
378
|
+
const queryParams = Object.entries(item.filters.queryParams || {})
|
|
379
|
+
.map(([key, value]) => `${key}=${value}`)
|
|
380
|
+
.join("&");
|
|
381
|
+
const tracking = {
|
|
382
|
+
routeItem: item,
|
|
383
|
+
url: `${path}${queryParams ? `?${queryParams}` : ""}`,
|
|
384
|
+
completed: false,
|
|
385
|
+
startedAt: Date.now(),
|
|
386
|
+
actionResults: [],
|
|
387
|
+
};
|
|
388
|
+
context.__routeState.matched.push(tracking);
|
|
117
389
|
}
|
|
118
390
|
}
|
|
119
391
|
debug("New allrouteItems", JSON.stringify(allRouteItems));
|
|
120
392
|
let message = null;
|
|
121
393
|
page.route("**/*", async (route) => {
|
|
394
|
+
const debug = createDebug("automation_model:route:intercept");
|
|
122
395
|
const request = route.request();
|
|
123
396
|
debug(`Intercepting request: ${request.method()} ${request.url()}`);
|
|
124
397
|
const matchedItem = allRouteItems.find((item) => matchRoute(item, route));
|
|
@@ -126,7 +399,7 @@ export async function registerBeforeStepRoutes(context, stepName, world) {
|
|
|
126
399
|
return route.continue();
|
|
127
400
|
debug(`Matched route item: ${JSON.stringify(matchedItem)}`);
|
|
128
401
|
debug("Initial context route state", context.__routeState);
|
|
129
|
-
let tracking = context.__routeState.matched.find((t) => t.routeItem === matchedItem && !t.completed);
|
|
402
|
+
let tracking = context.__routeState.matched.find((t) => JSON.stringify(t.routeItem) === JSON.stringify(matchedItem) && !t.completed);
|
|
130
403
|
debug("Tracking", tracking);
|
|
131
404
|
let stubActionPerformed = false;
|
|
132
405
|
if (!tracking) {
|
|
@@ -148,88 +421,12 @@ export async function registerBeforeStepRoutes(context, stepName, world) {
|
|
|
148
421
|
}
|
|
149
422
|
const stubAction = matchedItem.actions.find((a) => a.type === "stub_request");
|
|
150
423
|
if (stubAction) {
|
|
151
|
-
|
|
152
|
-
const description = JSON.stringify(stubAction.config);
|
|
153
|
-
debug(`Stub action found for ${request.url()}. Skipping fetch.`);
|
|
154
|
-
if (tracking.timer)
|
|
155
|
-
clearTimeout(tracking.timer);
|
|
156
|
-
const fullFillConfig = {};
|
|
157
|
-
if (stubAction.config.path) {
|
|
158
|
-
const filePath = path.join(process.cwd(), "data", "fixtures", stubAction.config.path);
|
|
159
|
-
debug(`Stub action file path: ${filePath}`);
|
|
160
|
-
if (existsSync(filePath)) {
|
|
161
|
-
fullFillConfig.path = filePath;
|
|
162
|
-
debug(`Stub action fulfilled with file: ${filePath}`);
|
|
163
|
-
}
|
|
164
|
-
else {
|
|
165
|
-
actionStatus = "fail";
|
|
166
|
-
tracking.actionResults.push({
|
|
167
|
-
type: "stub_request",
|
|
168
|
-
description,
|
|
169
|
-
status: actionStatus,
|
|
170
|
-
message: `Stub action failed for ${tracking.url}: File not found at ${filePath}`,
|
|
171
|
-
});
|
|
172
|
-
stubActionPerformed = true;
|
|
173
|
-
}
|
|
174
|
-
}
|
|
175
|
-
if (!fullFillConfig.path) {
|
|
176
|
-
if (stubAction.config.statusCode) {
|
|
177
|
-
fullFillConfig.status = Number(stubAction.config.statusCode);
|
|
178
|
-
}
|
|
179
|
-
if (stubAction.config.contentType) {
|
|
180
|
-
if (stubAction.config.contentType === "application/json") {
|
|
181
|
-
fullFillConfig.contentType = "application/json";
|
|
182
|
-
if (stubAction.config.body) {
|
|
183
|
-
try {
|
|
184
|
-
fullFillConfig.json = JSON.parse(stubAction.config.body);
|
|
185
|
-
}
|
|
186
|
-
catch (e) {
|
|
187
|
-
debug(`Invalid JSON in stub action body: ${stubAction.config.body}, `, e instanceof Error ? e.message : String(e));
|
|
188
|
-
debug("Invalid JSON, defaulting to empty object");
|
|
189
|
-
fullFillConfig.json = {};
|
|
190
|
-
}
|
|
191
|
-
}
|
|
192
|
-
}
|
|
193
|
-
else {
|
|
194
|
-
fullFillConfig.contentType = stubAction.config.contentType;
|
|
195
|
-
fullFillConfig.body = stubAction.config.body || "";
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
if (!fullFillConfig.json && !fullFillConfig.body) {
|
|
199
|
-
if (stubAction.config.body) {
|
|
200
|
-
fullFillConfig.body = stubAction.config.body;
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
if (actionStatus === "success") {
|
|
205
|
-
try {
|
|
206
|
-
route.fulfill(fullFillConfig);
|
|
207
|
-
stubActionPerformed = true;
|
|
208
|
-
tracking.completed = true;
|
|
209
|
-
tracking.actionResults.push({
|
|
210
|
-
type: "stub_request",
|
|
211
|
-
description,
|
|
212
|
-
status: actionStatus,
|
|
213
|
-
message: `Stub action executed for ${request.url()}`,
|
|
214
|
-
});
|
|
215
|
-
}
|
|
216
|
-
catch (e) {
|
|
217
|
-
actionStatus = "fail";
|
|
218
|
-
debug(`Failed to fulfill stub request for ${request.url()}`, e);
|
|
219
|
-
tracking.actionResults.push({
|
|
220
|
-
type: "stub_request",
|
|
221
|
-
description,
|
|
222
|
-
status: actionStatus,
|
|
223
|
-
message: `Stub action failed for ${request.url()}: ${e instanceof Error ? e.message : String(e)}`,
|
|
224
|
-
});
|
|
225
|
-
}
|
|
226
|
-
}
|
|
424
|
+
stubActionPerformed = handleStubAction(stubAction, route, tracking);
|
|
227
425
|
}
|
|
228
426
|
if (!stubActionPerformed) {
|
|
229
427
|
let response;
|
|
230
428
|
try {
|
|
231
429
|
response = await route.fetch();
|
|
232
|
-
// debug("Matched item response", response);
|
|
233
430
|
}
|
|
234
431
|
catch (e) {
|
|
235
432
|
console.error("Fetch failed for", request.url(), e);
|
|
@@ -237,213 +434,79 @@ export async function registerBeforeStepRoutes(context, stepName, world) {
|
|
|
237
434
|
clearTimeout(tracking.timer);
|
|
238
435
|
return route.abort();
|
|
239
436
|
}
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
const
|
|
243
|
-
!headers["content-type"]?.includes("text") &&
|
|
244
|
-
!headers["content-type"]?.includes("application/csv");
|
|
245
|
-
// debug("Matched item isBinary", isBinary);
|
|
246
|
-
const isJSON = headers["content-type"]?.includes("application/json") || headers["content-type"]?.includes("json")
|
|
247
|
-
? true
|
|
248
|
-
: false;
|
|
249
|
-
// debug("Matched item isJSON", isJSON);
|
|
250
|
-
let body;
|
|
251
|
-
if (isBinary) {
|
|
252
|
-
body = await response.body(); // returns a Buffer
|
|
253
|
-
}
|
|
254
|
-
else {
|
|
255
|
-
body = await response.text();
|
|
256
|
-
}
|
|
437
|
+
const headers = response.headers();
|
|
438
|
+
const isBinary = !headers["content-type"]?.includes("application/json") && !headers["content-type"]?.includes("text");
|
|
439
|
+
const body = isBinary ? await response.body() : await response.text();
|
|
257
440
|
let json;
|
|
258
441
|
try {
|
|
259
|
-
|
|
260
|
-
if (typeof body === "string") {
|
|
442
|
+
if (typeof body === "string")
|
|
261
443
|
json = JSON.parse(body);
|
|
262
|
-
}
|
|
263
444
|
}
|
|
264
445
|
catch (_) { }
|
|
446
|
+
const actionHandlerContext = {
|
|
447
|
+
route,
|
|
448
|
+
tracking,
|
|
449
|
+
status: response.status(),
|
|
450
|
+
body,
|
|
451
|
+
json,
|
|
452
|
+
isBinary,
|
|
453
|
+
finalBody: json ?? body,
|
|
454
|
+
abortActionPerformed: false,
|
|
455
|
+
};
|
|
265
456
|
const actionResults = [];
|
|
266
|
-
let abortActionPerformed = false;
|
|
267
|
-
let finalBody = isJSON && json ? json : body;
|
|
268
|
-
// debug("Matched item actions", matchedItem.actions);
|
|
269
457
|
for (const action of matchedItem.actions) {
|
|
270
|
-
let
|
|
271
|
-
const description = JSON.stringify(action.config);
|
|
458
|
+
let result;
|
|
272
459
|
switch (action.type) {
|
|
273
460
|
case "abort_request":
|
|
274
|
-
|
|
275
|
-
clearTimeout(tracking.timer);
|
|
276
|
-
const errorCode = action.config?.errorCode ?? "failed";
|
|
277
|
-
console.log(`[abort_request] Aborting with error code: ${errorCode}`);
|
|
278
|
-
await route.abort(errorCode);
|
|
279
|
-
abortActionPerformed = true;
|
|
280
|
-
tracking.completed = true;
|
|
461
|
+
result = handleAbortRequest(action, actionHandlerContext);
|
|
281
462
|
break;
|
|
282
463
|
case "status_code_verification":
|
|
283
|
-
|
|
284
|
-
actionStatus = "fail";
|
|
285
|
-
message = `Status code verification failed. Expected ${action.config}, got ${status}`;
|
|
286
|
-
debug(`[status_code_verification] Failed: ${message}`);
|
|
287
|
-
}
|
|
288
|
-
else {
|
|
289
|
-
console.log(`[status_code_verification] Passed`);
|
|
290
|
-
message = `Status code verification passed. Expected ${action.config}, got ${status}`;
|
|
291
|
-
}
|
|
464
|
+
result = handleStatusCodeVerification(action, actionHandlerContext);
|
|
292
465
|
break;
|
|
293
466
|
case "json_modify":
|
|
294
|
-
|
|
295
|
-
actionStatus = "fail";
|
|
296
|
-
message = "JSON modification failed. Response is not JSON";
|
|
297
|
-
debug(`[json_modify] Failed: ${message}`);
|
|
298
|
-
}
|
|
299
|
-
else {
|
|
300
|
-
if (action.config && action.config.path && action.config.modifyValue) {
|
|
301
|
-
objectPath.set(json, action.config.path, action.config.modifyValue);
|
|
302
|
-
console.log(`[json_modify] Modified path ${action.config.path} to ${action.config.modifyValue}`);
|
|
303
|
-
console.log(`[json_modify] Modified JSON`);
|
|
304
|
-
message = `JSON modified successfully`;
|
|
305
|
-
finalBody = JSON.parse(JSON.stringify(json));
|
|
306
|
-
}
|
|
307
|
-
}
|
|
467
|
+
result = handleJsonModify(action, actionHandlerContext);
|
|
308
468
|
break;
|
|
309
469
|
case "json_whole_modify":
|
|
310
|
-
|
|
311
|
-
actionStatus = "fail";
|
|
312
|
-
message = "JSON modification failed. Response is not JSON";
|
|
313
|
-
debug(`[json_whole_modify] Failed: ${message}`);
|
|
314
|
-
}
|
|
315
|
-
else {
|
|
316
|
-
try {
|
|
317
|
-
const parsedConfig = JSON.parse(action.config);
|
|
318
|
-
json = parsedConfig;
|
|
319
|
-
finalBody = JSON.parse(JSON.stringify(json));
|
|
320
|
-
}
|
|
321
|
-
catch (e) {
|
|
322
|
-
actionStatus = "fail";
|
|
323
|
-
message = `JSON modification failed. Invalid JSON: ${e instanceof Error ? e.message : String(e)}`;
|
|
324
|
-
debug(`[json_whole_modify] Failed: ${message}`);
|
|
325
|
-
break;
|
|
326
|
-
}
|
|
327
|
-
console.log(`[json_whole_modify] Whole JSON replaced`);
|
|
328
|
-
message = `JSON replaced successfully`;
|
|
329
|
-
}
|
|
470
|
+
result = handleJsonWholeModify(action, actionHandlerContext);
|
|
330
471
|
break;
|
|
331
472
|
case "status_code_change":
|
|
332
|
-
|
|
333
|
-
console.log(`[status_code_change] Status changed to ${status}`);
|
|
334
|
-
message = `Status code changed to ${status}`;
|
|
473
|
+
result = handleStatusCodeChange(action, actionHandlerContext);
|
|
335
474
|
break;
|
|
336
475
|
case "change_text":
|
|
337
|
-
|
|
338
|
-
actionStatus = "fail";
|
|
339
|
-
message = "Change text action failed. Body is not a text";
|
|
340
|
-
debug(`[change_text] Failed: ${message}`);
|
|
341
|
-
}
|
|
342
|
-
else {
|
|
343
|
-
body = action.config;
|
|
344
|
-
console.log(`[change_text] HTML body replaced`);
|
|
345
|
-
message = `HTML body replaced successfully`;
|
|
346
|
-
finalBody = body;
|
|
347
|
-
}
|
|
476
|
+
result = handleChangeText(action, actionHandlerContext);
|
|
348
477
|
break;
|
|
349
478
|
case "assert_json":
|
|
350
|
-
|
|
351
|
-
actionStatus = "fail";
|
|
352
|
-
message = "JSON assertion failed. Response is not JSON";
|
|
353
|
-
debug(`[assert_json] Failed: ${message}`);
|
|
354
|
-
}
|
|
355
|
-
else {
|
|
356
|
-
const actual = objectPath.get(json, action.config.path);
|
|
357
|
-
if (typeof actual !== "object") {
|
|
358
|
-
if (JSON.stringify(actual) !== JSON.stringify(action.config.expectedValue)) {
|
|
359
|
-
actionStatus = "fail";
|
|
360
|
-
message = `JSON assertion failed for path ${action.config.path}: expected ${JSON.stringify(action.config.expectedValue)}, got ${JSON.stringify(actual)}`;
|
|
361
|
-
debug(`[assert_json] Failed: ${message}`);
|
|
362
|
-
}
|
|
363
|
-
}
|
|
364
|
-
else if (JSON.stringify(actual) !== action.config.expectedValue) {
|
|
365
|
-
actionStatus = "fail";
|
|
366
|
-
message = `JSON assertion failed for path ${action.config.path}: expected ${action.config.expectedValue}, got ${JSON.stringify(actual)}`;
|
|
367
|
-
debug(`[assert_json] Failed: ${message}`);
|
|
368
|
-
}
|
|
369
|
-
else {
|
|
370
|
-
console.log(`[assert_json] Assertion passed for path ${action.config.path}`);
|
|
371
|
-
message = `JSON assertion passed for path ${action.config.path}`;
|
|
372
|
-
}
|
|
373
|
-
}
|
|
479
|
+
result = handleAssertJson(action, actionHandlerContext);
|
|
374
480
|
break;
|
|
375
481
|
case "assert_whole_json":
|
|
376
|
-
|
|
377
|
-
actionStatus = "fail";
|
|
378
|
-
message = "Whole JSON assertion failed. Response is not JSON";
|
|
379
|
-
debug(`[assert_whole_json] Failed: ${message}`);
|
|
380
|
-
}
|
|
381
|
-
else {
|
|
382
|
-
if (action.config.contains) {
|
|
383
|
-
const originalJSON = JSON.stringify(json, null, 2);
|
|
384
|
-
if (!originalJSON.includes(action.config.contains)) {
|
|
385
|
-
actionStatus = "fail";
|
|
386
|
-
message = `Whole JSON assertion failed. Expected to contain: "${action.config.contains}", actual: "${body}"`;
|
|
387
|
-
debug(`[assert_whole_json] Failed: ${message}`);
|
|
388
|
-
}
|
|
389
|
-
}
|
|
390
|
-
else if (action.config.equals) {
|
|
391
|
-
const originalJSON = JSON.stringify(json, null, 2);
|
|
392
|
-
if (originalJSON !== action.config.equals) {
|
|
393
|
-
actionStatus = "fail";
|
|
394
|
-
message = `Whole JSON assertion failed. Expected exact match: "${action.config.equals}", actual: "${body}"`;
|
|
395
|
-
debug(`[assert_whole_json] Failed: ${message}`);
|
|
396
|
-
}
|
|
397
|
-
}
|
|
398
|
-
else {
|
|
399
|
-
console.log(`[assert_whole_json] Assertion passed`);
|
|
400
|
-
message = `Whole JSON assertion passed.`;
|
|
401
|
-
}
|
|
402
|
-
}
|
|
482
|
+
result = handleAssertWholeJson(action, actionHandlerContext);
|
|
403
483
|
break;
|
|
404
484
|
case "assert_text":
|
|
405
|
-
|
|
406
|
-
console.error(`[assert_text] Body is not text`);
|
|
407
|
-
actionStatus = "fail";
|
|
408
|
-
message = "Text assertion failed. Body is not text";
|
|
409
|
-
debug(`[assert_text] Failed: ${message}`);
|
|
410
|
-
}
|
|
411
|
-
else {
|
|
412
|
-
if (action.config.contains && !body.includes(action.config.contains)) {
|
|
413
|
-
actionStatus = "fail";
|
|
414
|
-
message = `Text assertion failed. Expected to contain: "${action.config.contains}", actual: "${body}"`;
|
|
415
|
-
debug(`[assert_text] Failed: ${message}`);
|
|
416
|
-
}
|
|
417
|
-
else if (action.config.equals && body !== action.config.equals) {
|
|
418
|
-
actionStatus = "fail";
|
|
419
|
-
message = `Text assertion failed. Expected exact match: "${action.config.equals}", actual: "${body}"`;
|
|
420
|
-
debug(`[assert_text] Failed: ${message}`);
|
|
421
|
-
}
|
|
422
|
-
else {
|
|
423
|
-
console.log(`[assert_text] Assertion passed`);
|
|
424
|
-
message = `Text assertion passed.`;
|
|
425
|
-
}
|
|
426
|
-
}
|
|
485
|
+
result = handleAssertText(action, actionHandlerContext);
|
|
427
486
|
break;
|
|
428
487
|
default:
|
|
429
|
-
console.warn(`Unknown action type
|
|
488
|
+
console.warn(`Unknown action type`);
|
|
430
489
|
}
|
|
431
|
-
|
|
432
|
-
|
|
490
|
+
if (result)
|
|
491
|
+
actionResults.push(result);
|
|
433
492
|
}
|
|
434
493
|
tracking.completed = true;
|
|
435
494
|
tracking.actionResults = actionResults;
|
|
436
495
|
if (tracking.timer)
|
|
437
496
|
clearTimeout(tracking.timer);
|
|
438
|
-
if (!abortActionPerformed) {
|
|
497
|
+
if (!actionHandlerContext.abortActionPerformed) {
|
|
439
498
|
try {
|
|
499
|
+
const isJSON = headers["content-type"]?.includes("application/json");
|
|
440
500
|
if (isJSON) {
|
|
441
|
-
await route.fulfill({ status, json: finalBody, headers });
|
|
501
|
+
await route.fulfill({ status: actionHandlerContext.status, json: actionHandlerContext.finalBody, headers });
|
|
442
502
|
}
|
|
443
503
|
else {
|
|
444
|
-
await route.fulfill({
|
|
504
|
+
await route.fulfill({
|
|
505
|
+
status: actionHandlerContext.status,
|
|
506
|
+
body: actionHandlerContext.finalBody,
|
|
507
|
+
headers,
|
|
508
|
+
});
|
|
445
509
|
}
|
|
446
|
-
// await route.fulfill({ status, body: finalBody, headers });
|
|
447
510
|
}
|
|
448
511
|
catch (e) {
|
|
449
512
|
console.error("Failed to fulfill route:", e);
|