automation_model 1.0.739-stage → 1.0.740-stage

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