@riddledc/riddle-proof 0.7.117 → 0.7.119
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/README.md +35 -4
- package/dist/{chunk-SBOGXOV5.js → chunk-DVMBXDIF.js} +62 -6
- package/dist/cli.cjs +61 -6
- package/dist/cli.js +1 -1
- package/dist/index.cjs +63 -6
- package/dist/index.d.cts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js +3 -1
- package/dist/profile.cjs +63 -6
- package/dist/profile.d.cts +5 -1
- package/dist/profile.d.ts +5 -1
- package/dist/profile.js +3 -1
- package/examples/profiles/handled-recovery-action-malformed-success.json +126 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -203,6 +203,7 @@ The package includes generic starter profiles:
|
|
|
203
203
|
- `examples/profiles/page-content-basic.json` for route/content/layout smoke profiles.
|
|
204
204
|
- `examples/profiles/route-inventory-basic.json` for source-link and direct-route audits.
|
|
205
205
|
- `examples/profiles/handled-recovery-list-load.json` for malformed list-load recovery profiles.
|
|
206
|
+
- `examples/profiles/handled-recovery-action-malformed-success.json` for action recovery profiles where the request succeeds at HTTP level but returns an unusable body.
|
|
206
207
|
|
|
207
208
|
Copy one of those shapes into a repository profile directory and replace the
|
|
208
209
|
routes, selectors, mock URLs, and text checks with app-specific invariants.
|
|
@@ -220,6 +221,15 @@ when the list failed to load; and keep `no_fatal_console_errors` plus
|
|
|
220
221
|
recovery-quality bugs and hidden browser-health debt without requiring a
|
|
221
222
|
separate CI or wrapper-specific path.
|
|
222
223
|
|
|
224
|
+
For handled action recovery profiles, assert the action itself as well as the
|
|
225
|
+
recovery UI. Capture the request body when the action payload matters, preserve
|
|
226
|
+
the surrounding page state, and reject the success modal, toast, or row that
|
|
227
|
+
would imply the action completed. A useful malformed-success profile returns a
|
|
228
|
+
successful HTTP status with an invalid JSON body, waits for one generic failure
|
|
229
|
+
message, captures a recovery screenshot, and keeps parser text plus browser
|
|
230
|
+
console/page errors out of the final proof. This catches action paths that look
|
|
231
|
+
recovered to a user but still poison the browser evidence stream.
|
|
232
|
+
|
|
223
233
|
Checks normally apply to every captured viewport. Add `viewports` (or
|
|
224
234
|
`viewport_names`) to a check when responsive UI intentionally exposes an
|
|
225
235
|
invariant only on named viewports, such as desktop-only helper copy while phone
|
|
@@ -229,10 +239,11 @@ layouts keep the same route, link, and overflow contracts.
|
|
|
229
239
|
before navigation, records each hit, and adds an implicit
|
|
230
240
|
`network_mocks_succeeded` check when mocks are present. A mock supports
|
|
231
241
|
`url`/`glob`/`pattern`, optional `method`, `status`, `content_type`, `headers`,
|
|
232
|
-
string `body`, JSON `json` / `body_json`,
|
|
233
|
-
best-effort mocks. Use `responses` for
|
|
234
|
-
same endpoint should return a sequence,
|
|
235
|
-
Each response accepts the same payload
|
|
242
|
+
string `body`, JSON `json` / `body_json`, `abort: true` for fetch-level network
|
|
243
|
+
failures, and `required: false` for best-effort mocks. Use `responses` for
|
|
244
|
+
retry or recovery profiles where the same endpoint should return a sequence,
|
|
245
|
+
such as first `503` and then `200`. Each response accepts the same payload
|
|
246
|
+
fields plus an optional label:
|
|
236
247
|
|
|
237
248
|
```json
|
|
238
249
|
{
|
|
@@ -254,6 +265,26 @@ Each response accepts the same payload fields plus an optional label:
|
|
|
254
265
|
}
|
|
255
266
|
```
|
|
256
267
|
|
|
268
|
+
Use `abort: true` when the product must recover from a transport failure rather
|
|
269
|
+
than an HTTP error response. The default Playwright abort code is `failed`; set
|
|
270
|
+
`abort_error_code` (or use `abort: "connectionreset"`) for a specific browser
|
|
271
|
+
network error:
|
|
272
|
+
|
|
273
|
+
```json
|
|
274
|
+
{
|
|
275
|
+
"label": "api-key-revoke-network-failure",
|
|
276
|
+
"url": "**/billing/api-keys/key_123",
|
|
277
|
+
"method": "DELETE",
|
|
278
|
+
"abort": true,
|
|
279
|
+
"abort_error_code": "failed"
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
Aborted mocks count as intentional mock hits. Matching browser
|
|
284
|
+
`Failed to load resource` console entries for the mocked URL are allowed by
|
|
285
|
+
`no_fatal_console_errors`; app-level `console.error(...)` calls still fail unless
|
|
286
|
+
explicitly allowlisted.
|
|
287
|
+
|
|
257
288
|
When `responses` is present, `network_mocks_succeeded` requires each configured
|
|
258
289
|
response to be hit at least once by default and records `hit_index`,
|
|
259
290
|
`response_index`, and `response_label` for each request. Set
|
|
@@ -63,6 +63,22 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
|
|
|
63
63
|
"wait_for_text",
|
|
64
64
|
"window_call"
|
|
65
65
|
];
|
|
66
|
+
var RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES = [
|
|
67
|
+
"aborted",
|
|
68
|
+
"accessdenied",
|
|
69
|
+
"addressunreachable",
|
|
70
|
+
"blockedbyclient",
|
|
71
|
+
"blockedbyresponse",
|
|
72
|
+
"connectionaborted",
|
|
73
|
+
"connectionclosed",
|
|
74
|
+
"connectionfailed",
|
|
75
|
+
"connectionrefused",
|
|
76
|
+
"connectionreset",
|
|
77
|
+
"internetdisconnected",
|
|
78
|
+
"namenotresolved",
|
|
79
|
+
"timedout",
|
|
80
|
+
"failed"
|
|
81
|
+
];
|
|
66
82
|
var DEFAULT_VIEWPORTS = [
|
|
67
83
|
{ name: "desktop", width: 1280, height: 800 }
|
|
68
84
|
];
|
|
@@ -603,6 +619,7 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
|
603
619
|
const body = stringValue(input.body) ?? stringValue(input.body_text) ?? stringValue(input.bodyText) ?? defaults.body;
|
|
604
620
|
const hasJsonBody = Object.prototype.hasOwnProperty.call(input, "body_json") || Object.prototype.hasOwnProperty.call(input, "bodyJson") || Object.prototype.hasOwnProperty.call(input, "json");
|
|
605
621
|
const requestBody = normalizeNetworkMockRequestBodyConstraints(input, label);
|
|
622
|
+
const abort = normalizeNetworkMockAbort(input, label, defaults.abort, defaults.abort_error_code);
|
|
606
623
|
return {
|
|
607
624
|
label: stringValue(input.label) || stringValue(input.name) || defaults.label,
|
|
608
625
|
status,
|
|
@@ -611,6 +628,8 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
|
611
628
|
body,
|
|
612
629
|
body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json,
|
|
613
630
|
delay_ms: normalizeNetworkMockDelay(input, label, defaults.delay_ms),
|
|
631
|
+
abort: abort.abort,
|
|
632
|
+
abort_error_code: abort.abort_error_code,
|
|
614
633
|
capture_request_body: requestBody.capture_request_body,
|
|
615
634
|
request_body_contains: requestBody.request_body_contains,
|
|
616
635
|
request_body_patterns: requestBody.request_body_patterns,
|
|
@@ -618,6 +637,20 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
|
618
637
|
request_body_not_patterns: requestBody.request_body_not_patterns
|
|
619
638
|
};
|
|
620
639
|
}
|
|
640
|
+
function normalizeNetworkMockAbort(input, label, defaultAbort, defaultErrorCode) {
|
|
641
|
+
const abortInput = input.abort ?? input.route_abort ?? input.routeAbort;
|
|
642
|
+
const explicitAbort = typeof abortInput === "string" ? abortInput.trim().length > 0 : abortInput === true;
|
|
643
|
+
const abort = explicitAbort || defaultAbort === true;
|
|
644
|
+
if (!abort) return {};
|
|
645
|
+
const codeInput = stringValue(
|
|
646
|
+
typeof abortInput === "string" ? abortInput : input.abort_error_code ?? input.abortErrorCode ?? input.abort_error ?? input.abortError ?? input.network_error ?? input.networkError
|
|
647
|
+
) || defaultErrorCode || "failed";
|
|
648
|
+
const abort_error_code = codeInput.toLowerCase();
|
|
649
|
+
if (!RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES.includes(abort_error_code)) {
|
|
650
|
+
throw new Error(`${label}.abort_error_code must be one of ${RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES.join(", ")}.`);
|
|
651
|
+
}
|
|
652
|
+
return { abort: true, abort_error_code };
|
|
653
|
+
}
|
|
621
654
|
function normalizeNetworkMockDelay(input, label, defaultValue) {
|
|
622
655
|
const value = numberValue(
|
|
623
656
|
input.delay_ms ?? input.delayMs ?? input.wait_ms ?? input.waitMs ?? input.latency_ms ?? input.latencyMs
|
|
@@ -639,7 +672,9 @@ function normalizeNetworkMockResponses(value, mockIndex, defaults) {
|
|
|
639
672
|
headers: defaults.headers,
|
|
640
673
|
body: defaults.body,
|
|
641
674
|
body_json: defaults.body_json,
|
|
642
|
-
delay_ms: defaults.delay_ms
|
|
675
|
+
delay_ms: defaults.delay_ms,
|
|
676
|
+
abort: defaults.abort,
|
|
677
|
+
abort_error_code: defaults.abort_error_code
|
|
643
678
|
};
|
|
644
679
|
return value.map((response, responseIndex) => {
|
|
645
680
|
if (!isRecord(response)) {
|
|
@@ -1402,7 +1437,9 @@ function expectedFailedNetworkMockEvents(evidence) {
|
|
|
1402
1437
|
return (evidence.network_mocks || []).filter((event) => {
|
|
1403
1438
|
if (!isRecord(event) || event.ok === false) return false;
|
|
1404
1439
|
const status = numberValue(event.status);
|
|
1405
|
-
|
|
1440
|
+
const isHttpFailure = status !== void 0 && status >= 400;
|
|
1441
|
+
const isAbortedMock = event.abort === true && Boolean(stringValue(event.abort_error_code));
|
|
1442
|
+
return (isHttpFailure || isAbortedMock) && Boolean(stringValue(event.url));
|
|
1406
1443
|
});
|
|
1407
1444
|
}
|
|
1408
1445
|
function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
@@ -1412,7 +1449,8 @@ function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
|
1412
1449
|
if (!eventUrl) return void 0;
|
|
1413
1450
|
return expectedFailedNetworkMockEvents(evidence).find((mockEvent) => {
|
|
1414
1451
|
const status = numberValue(mockEvent.status);
|
|
1415
|
-
|
|
1452
|
+
const abortErrorCode = stringValue(mockEvent.abort_error_code);
|
|
1453
|
+
return stringValue(mockEvent.url) === eventUrl && (status !== void 0 && sample.includes(String(status)) || Boolean(abortErrorCode) && /Failed to load resource/i.test(sample));
|
|
1416
1454
|
});
|
|
1417
1455
|
}
|
|
1418
1456
|
function isExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
@@ -1424,6 +1462,7 @@ function expectedFailedNetworkMockConsoleEventSummary(event, evidence) {
|
|
|
1424
1462
|
return {
|
|
1425
1463
|
url: consoleEventLocationUrl(event) ?? null,
|
|
1426
1464
|
status: match ? numberValue(match.status) ?? null : null,
|
|
1465
|
+
abort_error_code: match ? stringValue(match.abort_error_code) ?? null : null,
|
|
1427
1466
|
label: match ? stringValue(match.label) ?? null : null,
|
|
1428
1467
|
response_label: match ? stringValue(match.response_label) ?? null : null,
|
|
1429
1468
|
text: isRecord(event) && typeof event.text === "string" ? event.text.slice(0, 300) : sample.slice(0, 300)
|
|
@@ -2440,7 +2479,8 @@ function expectedFailedNetworkMockEvents(evidence) {
|
|
|
2440
2479
|
if (!event || typeof event !== "object" || Array.isArray(event) || event.ok === false) return false;
|
|
2441
2480
|
const status = typeof event.status === "number" && Number.isFinite(event.status) ? event.status : undefined;
|
|
2442
2481
|
const url = typeof event.url === "string" && event.url.trim() ? event.url.trim() : undefined;
|
|
2443
|
-
|
|
2482
|
+
const abortErrorCode = typeof event.abort_error_code === "string" && event.abort_error_code.trim() ? event.abort_error_code.trim() : undefined;
|
|
2483
|
+
return ((status !== undefined && status >= 400) || (event.abort === true && Boolean(abortErrorCode))) && Boolean(url);
|
|
2444
2484
|
});
|
|
2445
2485
|
}
|
|
2446
2486
|
function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
@@ -2451,7 +2491,8 @@ function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
|
2451
2491
|
return expectedFailedNetworkMockEvents(evidence).find((mockEvent) => {
|
|
2452
2492
|
const status = typeof mockEvent.status === "number" && Number.isFinite(mockEvent.status) ? mockEvent.status : undefined;
|
|
2453
2493
|
const mockUrl = typeof mockEvent.url === "string" && mockEvent.url.trim() ? mockEvent.url.trim() : undefined;
|
|
2454
|
-
|
|
2494
|
+
const abortErrorCode = typeof mockEvent.abort_error_code === "string" && mockEvent.abort_error_code.trim() ? mockEvent.abort_error_code.trim() : undefined;
|
|
2495
|
+
return mockUrl === eventUrl && ((status !== undefined && sample.includes(String(status))) || (Boolean(abortErrorCode) && /Failed to load resource/i.test(sample)));
|
|
2455
2496
|
});
|
|
2456
2497
|
}
|
|
2457
2498
|
function isExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
@@ -2463,6 +2504,7 @@ function expectedFailedNetworkMockConsoleEventSummary(event, evidence) {
|
|
|
2463
2504
|
return {
|
|
2464
2505
|
url: consoleEventLocationUrl(event) || null,
|
|
2465
2506
|
status: match && typeof match.status === "number" && Number.isFinite(match.status) ? match.status : null,
|
|
2507
|
+
abort_error_code: match && typeof match.abort_error_code === "string" && match.abort_error_code.trim() ? match.abort_error_code.trim() : null,
|
|
2466
2508
|
label: match && typeof match.label === "string" && match.label.trim() ? match.label.trim() : null,
|
|
2467
2509
|
response_label: match && typeof match.response_label === "string" && match.response_label.trim() ? match.response_label.trim() : null,
|
|
2468
2510
|
text: event && typeof event === "object" && !Array.isArray(event) && typeof event.text === "string" ? event.text.slice(0, 300) : sample.slice(0, 300),
|
|
@@ -4096,6 +4138,10 @@ async function registerNetworkMocks(mocks) {
|
|
|
4096
4138
|
const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock, responseBodyContract) : [];
|
|
4097
4139
|
const status = response.status || mock.status || 200;
|
|
4098
4140
|
const delayMs = numberValue(response.delay_ms) || 0;
|
|
4141
|
+
const shouldAbort = response.abort === true;
|
|
4142
|
+
const abortErrorCode = typeof response.abort_error_code === "string" && response.abort_error_code.trim()
|
|
4143
|
+
? response.abort_error_code.trim()
|
|
4144
|
+
: "failed";
|
|
4099
4145
|
const event = {
|
|
4100
4146
|
ok: true,
|
|
4101
4147
|
label: mock.label,
|
|
@@ -4108,8 +4154,13 @@ async function registerNetworkMocks(mocks) {
|
|
|
4108
4154
|
sequence_cycle: responseSelection === "sequence" && responseIndex !== null && mock.repeat_responses === true && hitIndex >= responses.length,
|
|
4109
4155
|
url: request.url(),
|
|
4110
4156
|
method,
|
|
4111
|
-
status,
|
|
4112
4157
|
};
|
|
4158
|
+
if (shouldAbort) {
|
|
4159
|
+
event.abort = true;
|
|
4160
|
+
event.abort_error_code = abortErrorCode;
|
|
4161
|
+
} else {
|
|
4162
|
+
event.status = status;
|
|
4163
|
+
}
|
|
4113
4164
|
if (delayMs) event.delay_ms = delayMs;
|
|
4114
4165
|
if (shouldCaptureRequestBody) {
|
|
4115
4166
|
event.request_body_matches = requestBodyFailures.length === 0;
|
|
@@ -4119,6 +4170,10 @@ async function registerNetworkMocks(mocks) {
|
|
|
4119
4170
|
}
|
|
4120
4171
|
networkMockEvents.push(event);
|
|
4121
4172
|
if (delayMs) await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
4173
|
+
if (shouldAbort) {
|
|
4174
|
+
await route.abort(abortErrorCode);
|
|
4175
|
+
return;
|
|
4176
|
+
}
|
|
4122
4177
|
await route.fulfill({
|
|
4123
4178
|
status,
|
|
4124
4179
|
headers,
|
|
@@ -5828,6 +5883,7 @@ export {
|
|
|
5828
5883
|
RIDDLE_PROOF_PROFILE_STATUSES,
|
|
5829
5884
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
5830
5885
|
RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
|
|
5886
|
+
RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES,
|
|
5831
5887
|
slugifyRiddleProofProfileName,
|
|
5832
5888
|
collectRiddleProofProfileWarnings,
|
|
5833
5889
|
normalizeRiddleProofProfile,
|
package/dist/cli.cjs
CHANGED
|
@@ -7000,6 +7000,22 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
|
|
|
7000
7000
|
"wait_for_text",
|
|
7001
7001
|
"window_call"
|
|
7002
7002
|
];
|
|
7003
|
+
var RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES = [
|
|
7004
|
+
"aborted",
|
|
7005
|
+
"accessdenied",
|
|
7006
|
+
"addressunreachable",
|
|
7007
|
+
"blockedbyclient",
|
|
7008
|
+
"blockedbyresponse",
|
|
7009
|
+
"connectionaborted",
|
|
7010
|
+
"connectionclosed",
|
|
7011
|
+
"connectionfailed",
|
|
7012
|
+
"connectionrefused",
|
|
7013
|
+
"connectionreset",
|
|
7014
|
+
"internetdisconnected",
|
|
7015
|
+
"namenotresolved",
|
|
7016
|
+
"timedout",
|
|
7017
|
+
"failed"
|
|
7018
|
+
];
|
|
7003
7019
|
var DEFAULT_VIEWPORTS = [
|
|
7004
7020
|
{ name: "desktop", width: 1280, height: 800 }
|
|
7005
7021
|
];
|
|
@@ -7540,6 +7556,7 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
|
7540
7556
|
const body = stringValue2(input.body) ?? stringValue2(input.body_text) ?? stringValue2(input.bodyText) ?? defaults.body;
|
|
7541
7557
|
const hasJsonBody = Object.prototype.hasOwnProperty.call(input, "body_json") || Object.prototype.hasOwnProperty.call(input, "bodyJson") || Object.prototype.hasOwnProperty.call(input, "json");
|
|
7542
7558
|
const requestBody = normalizeNetworkMockRequestBodyConstraints(input, label);
|
|
7559
|
+
const abort = normalizeNetworkMockAbort(input, label, defaults.abort, defaults.abort_error_code);
|
|
7543
7560
|
return {
|
|
7544
7561
|
label: stringValue2(input.label) || stringValue2(input.name) || defaults.label,
|
|
7545
7562
|
status,
|
|
@@ -7548,6 +7565,8 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
|
7548
7565
|
body,
|
|
7549
7566
|
body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json,
|
|
7550
7567
|
delay_ms: normalizeNetworkMockDelay(input, label, defaults.delay_ms),
|
|
7568
|
+
abort: abort.abort,
|
|
7569
|
+
abort_error_code: abort.abort_error_code,
|
|
7551
7570
|
capture_request_body: requestBody.capture_request_body,
|
|
7552
7571
|
request_body_contains: requestBody.request_body_contains,
|
|
7553
7572
|
request_body_patterns: requestBody.request_body_patterns,
|
|
@@ -7555,6 +7574,20 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
|
7555
7574
|
request_body_not_patterns: requestBody.request_body_not_patterns
|
|
7556
7575
|
};
|
|
7557
7576
|
}
|
|
7577
|
+
function normalizeNetworkMockAbort(input, label, defaultAbort, defaultErrorCode) {
|
|
7578
|
+
const abortInput = input.abort ?? input.route_abort ?? input.routeAbort;
|
|
7579
|
+
const explicitAbort = typeof abortInput === "string" ? abortInput.trim().length > 0 : abortInput === true;
|
|
7580
|
+
const abort = explicitAbort || defaultAbort === true;
|
|
7581
|
+
if (!abort) return {};
|
|
7582
|
+
const codeInput = stringValue2(
|
|
7583
|
+
typeof abortInput === "string" ? abortInput : input.abort_error_code ?? input.abortErrorCode ?? input.abort_error ?? input.abortError ?? input.network_error ?? input.networkError
|
|
7584
|
+
) || defaultErrorCode || "failed";
|
|
7585
|
+
const abort_error_code = codeInput.toLowerCase();
|
|
7586
|
+
if (!RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES.includes(abort_error_code)) {
|
|
7587
|
+
throw new Error(`${label}.abort_error_code must be one of ${RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES.join(", ")}.`);
|
|
7588
|
+
}
|
|
7589
|
+
return { abort: true, abort_error_code };
|
|
7590
|
+
}
|
|
7558
7591
|
function normalizeNetworkMockDelay(input, label, defaultValue) {
|
|
7559
7592
|
const value = numberValue(
|
|
7560
7593
|
input.delay_ms ?? input.delayMs ?? input.wait_ms ?? input.waitMs ?? input.latency_ms ?? input.latencyMs
|
|
@@ -7576,7 +7609,9 @@ function normalizeNetworkMockResponses(value, mockIndex, defaults) {
|
|
|
7576
7609
|
headers: defaults.headers,
|
|
7577
7610
|
body: defaults.body,
|
|
7578
7611
|
body_json: defaults.body_json,
|
|
7579
|
-
delay_ms: defaults.delay_ms
|
|
7612
|
+
delay_ms: defaults.delay_ms,
|
|
7613
|
+
abort: defaults.abort,
|
|
7614
|
+
abort_error_code: defaults.abort_error_code
|
|
7580
7615
|
};
|
|
7581
7616
|
return value.map((response, responseIndex) => {
|
|
7582
7617
|
if (!isRecord(response)) {
|
|
@@ -8339,7 +8374,9 @@ function expectedFailedNetworkMockEvents(evidence) {
|
|
|
8339
8374
|
return (evidence.network_mocks || []).filter((event) => {
|
|
8340
8375
|
if (!isRecord(event) || event.ok === false) return false;
|
|
8341
8376
|
const status = numberValue(event.status);
|
|
8342
|
-
|
|
8377
|
+
const isHttpFailure = status !== void 0 && status >= 400;
|
|
8378
|
+
const isAbortedMock = event.abort === true && Boolean(stringValue2(event.abort_error_code));
|
|
8379
|
+
return (isHttpFailure || isAbortedMock) && Boolean(stringValue2(event.url));
|
|
8343
8380
|
});
|
|
8344
8381
|
}
|
|
8345
8382
|
function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
@@ -8349,7 +8386,8 @@ function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
|
8349
8386
|
if (!eventUrl) return void 0;
|
|
8350
8387
|
return expectedFailedNetworkMockEvents(evidence).find((mockEvent) => {
|
|
8351
8388
|
const status = numberValue(mockEvent.status);
|
|
8352
|
-
|
|
8389
|
+
const abortErrorCode = stringValue2(mockEvent.abort_error_code);
|
|
8390
|
+
return stringValue2(mockEvent.url) === eventUrl && (status !== void 0 && sample.includes(String(status)) || Boolean(abortErrorCode) && /Failed to load resource/i.test(sample));
|
|
8353
8391
|
});
|
|
8354
8392
|
}
|
|
8355
8393
|
function isExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
@@ -8361,6 +8399,7 @@ function expectedFailedNetworkMockConsoleEventSummary(event, evidence) {
|
|
|
8361
8399
|
return {
|
|
8362
8400
|
url: consoleEventLocationUrl(event) ?? null,
|
|
8363
8401
|
status: match ? numberValue(match.status) ?? null : null,
|
|
8402
|
+
abort_error_code: match ? stringValue2(match.abort_error_code) ?? null : null,
|
|
8364
8403
|
label: match ? stringValue2(match.label) ?? null : null,
|
|
8365
8404
|
response_label: match ? stringValue2(match.response_label) ?? null : null,
|
|
8366
8405
|
text: isRecord(event) && typeof event.text === "string" ? event.text.slice(0, 300) : sample.slice(0, 300)
|
|
@@ -9361,7 +9400,8 @@ function expectedFailedNetworkMockEvents(evidence) {
|
|
|
9361
9400
|
if (!event || typeof event !== "object" || Array.isArray(event) || event.ok === false) return false;
|
|
9362
9401
|
const status = typeof event.status === "number" && Number.isFinite(event.status) ? event.status : undefined;
|
|
9363
9402
|
const url = typeof event.url === "string" && event.url.trim() ? event.url.trim() : undefined;
|
|
9364
|
-
|
|
9403
|
+
const abortErrorCode = typeof event.abort_error_code === "string" && event.abort_error_code.trim() ? event.abort_error_code.trim() : undefined;
|
|
9404
|
+
return ((status !== undefined && status >= 400) || (event.abort === true && Boolean(abortErrorCode))) && Boolean(url);
|
|
9365
9405
|
});
|
|
9366
9406
|
}
|
|
9367
9407
|
function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
@@ -9372,7 +9412,8 @@ function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
|
9372
9412
|
return expectedFailedNetworkMockEvents(evidence).find((mockEvent) => {
|
|
9373
9413
|
const status = typeof mockEvent.status === "number" && Number.isFinite(mockEvent.status) ? mockEvent.status : undefined;
|
|
9374
9414
|
const mockUrl = typeof mockEvent.url === "string" && mockEvent.url.trim() ? mockEvent.url.trim() : undefined;
|
|
9375
|
-
|
|
9415
|
+
const abortErrorCode = typeof mockEvent.abort_error_code === "string" && mockEvent.abort_error_code.trim() ? mockEvent.abort_error_code.trim() : undefined;
|
|
9416
|
+
return mockUrl === eventUrl && ((status !== undefined && sample.includes(String(status))) || (Boolean(abortErrorCode) && /Failed to load resource/i.test(sample)));
|
|
9376
9417
|
});
|
|
9377
9418
|
}
|
|
9378
9419
|
function isExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
@@ -9384,6 +9425,7 @@ function expectedFailedNetworkMockConsoleEventSummary(event, evidence) {
|
|
|
9384
9425
|
return {
|
|
9385
9426
|
url: consoleEventLocationUrl(event) || null,
|
|
9386
9427
|
status: match && typeof match.status === "number" && Number.isFinite(match.status) ? match.status : null,
|
|
9428
|
+
abort_error_code: match && typeof match.abort_error_code === "string" && match.abort_error_code.trim() ? match.abort_error_code.trim() : null,
|
|
9387
9429
|
label: match && typeof match.label === "string" && match.label.trim() ? match.label.trim() : null,
|
|
9388
9430
|
response_label: match && typeof match.response_label === "string" && match.response_label.trim() ? match.response_label.trim() : null,
|
|
9389
9431
|
text: event && typeof event === "object" && !Array.isArray(event) && typeof event.text === "string" ? event.text.slice(0, 300) : sample.slice(0, 300),
|
|
@@ -11017,6 +11059,10 @@ async function registerNetworkMocks(mocks) {
|
|
|
11017
11059
|
const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock, responseBodyContract) : [];
|
|
11018
11060
|
const status = response.status || mock.status || 200;
|
|
11019
11061
|
const delayMs = numberValue(response.delay_ms) || 0;
|
|
11062
|
+
const shouldAbort = response.abort === true;
|
|
11063
|
+
const abortErrorCode = typeof response.abort_error_code === "string" && response.abort_error_code.trim()
|
|
11064
|
+
? response.abort_error_code.trim()
|
|
11065
|
+
: "failed";
|
|
11020
11066
|
const event = {
|
|
11021
11067
|
ok: true,
|
|
11022
11068
|
label: mock.label,
|
|
@@ -11029,8 +11075,13 @@ async function registerNetworkMocks(mocks) {
|
|
|
11029
11075
|
sequence_cycle: responseSelection === "sequence" && responseIndex !== null && mock.repeat_responses === true && hitIndex >= responses.length,
|
|
11030
11076
|
url: request.url(),
|
|
11031
11077
|
method,
|
|
11032
|
-
status,
|
|
11033
11078
|
};
|
|
11079
|
+
if (shouldAbort) {
|
|
11080
|
+
event.abort = true;
|
|
11081
|
+
event.abort_error_code = abortErrorCode;
|
|
11082
|
+
} else {
|
|
11083
|
+
event.status = status;
|
|
11084
|
+
}
|
|
11034
11085
|
if (delayMs) event.delay_ms = delayMs;
|
|
11035
11086
|
if (shouldCaptureRequestBody) {
|
|
11036
11087
|
event.request_body_matches = requestBodyFailures.length === 0;
|
|
@@ -11040,6 +11091,10 @@ async function registerNetworkMocks(mocks) {
|
|
|
11040
11091
|
}
|
|
11041
11092
|
networkMockEvents.push(event);
|
|
11042
11093
|
if (delayMs) await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
11094
|
+
if (shouldAbort) {
|
|
11095
|
+
await route.abort(abortErrorCode);
|
|
11096
|
+
return;
|
|
11097
|
+
}
|
|
11043
11098
|
await route.fulfill({
|
|
11044
11099
|
status,
|
|
11045
11100
|
headers,
|
package/dist/cli.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -2916,6 +2916,7 @@ __export(index_exports, {
|
|
|
2916
2916
|
RIDDLE_PROOF_PLAYABILITY_VERSION: () => RIDDLE_PROOF_PLAYABILITY_VERSION,
|
|
2917
2917
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES: () => RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
2918
2918
|
RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: () => RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
|
|
2919
|
+
RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES: () => RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES,
|
|
2919
2920
|
RIDDLE_PROOF_PROFILE_RESULT_VERSION: () => RIDDLE_PROOF_PROFILE_RESULT_VERSION,
|
|
2920
2921
|
RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: () => RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
|
|
2921
2922
|
RIDDLE_PROOF_PROFILE_STATUSES: () => RIDDLE_PROOF_PROFILE_STATUSES,
|
|
@@ -8793,6 +8794,22 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
|
|
|
8793
8794
|
"wait_for_text",
|
|
8794
8795
|
"window_call"
|
|
8795
8796
|
];
|
|
8797
|
+
var RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES = [
|
|
8798
|
+
"aborted",
|
|
8799
|
+
"accessdenied",
|
|
8800
|
+
"addressunreachable",
|
|
8801
|
+
"blockedbyclient",
|
|
8802
|
+
"blockedbyresponse",
|
|
8803
|
+
"connectionaborted",
|
|
8804
|
+
"connectionclosed",
|
|
8805
|
+
"connectionfailed",
|
|
8806
|
+
"connectionrefused",
|
|
8807
|
+
"connectionreset",
|
|
8808
|
+
"internetdisconnected",
|
|
8809
|
+
"namenotresolved",
|
|
8810
|
+
"timedout",
|
|
8811
|
+
"failed"
|
|
8812
|
+
];
|
|
8796
8813
|
var DEFAULT_VIEWPORTS = [
|
|
8797
8814
|
{ name: "desktop", width: 1280, height: 800 }
|
|
8798
8815
|
];
|
|
@@ -9333,6 +9350,7 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
|
9333
9350
|
const body = stringValue5(input.body) ?? stringValue5(input.body_text) ?? stringValue5(input.bodyText) ?? defaults.body;
|
|
9334
9351
|
const hasJsonBody = Object.prototype.hasOwnProperty.call(input, "body_json") || Object.prototype.hasOwnProperty.call(input, "bodyJson") || Object.prototype.hasOwnProperty.call(input, "json");
|
|
9335
9352
|
const requestBody = normalizeNetworkMockRequestBodyConstraints(input, label);
|
|
9353
|
+
const abort = normalizeNetworkMockAbort(input, label, defaults.abort, defaults.abort_error_code);
|
|
9336
9354
|
return {
|
|
9337
9355
|
label: stringValue5(input.label) || stringValue5(input.name) || defaults.label,
|
|
9338
9356
|
status,
|
|
@@ -9341,6 +9359,8 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
|
9341
9359
|
body,
|
|
9342
9360
|
body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json,
|
|
9343
9361
|
delay_ms: normalizeNetworkMockDelay(input, label, defaults.delay_ms),
|
|
9362
|
+
abort: abort.abort,
|
|
9363
|
+
abort_error_code: abort.abort_error_code,
|
|
9344
9364
|
capture_request_body: requestBody.capture_request_body,
|
|
9345
9365
|
request_body_contains: requestBody.request_body_contains,
|
|
9346
9366
|
request_body_patterns: requestBody.request_body_patterns,
|
|
@@ -9348,6 +9368,20 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
|
9348
9368
|
request_body_not_patterns: requestBody.request_body_not_patterns
|
|
9349
9369
|
};
|
|
9350
9370
|
}
|
|
9371
|
+
function normalizeNetworkMockAbort(input, label, defaultAbort, defaultErrorCode) {
|
|
9372
|
+
const abortInput = input.abort ?? input.route_abort ?? input.routeAbort;
|
|
9373
|
+
const explicitAbort = typeof abortInput === "string" ? abortInput.trim().length > 0 : abortInput === true;
|
|
9374
|
+
const abort = explicitAbort || defaultAbort === true;
|
|
9375
|
+
if (!abort) return {};
|
|
9376
|
+
const codeInput = stringValue5(
|
|
9377
|
+
typeof abortInput === "string" ? abortInput : input.abort_error_code ?? input.abortErrorCode ?? input.abort_error ?? input.abortError ?? input.network_error ?? input.networkError
|
|
9378
|
+
) || defaultErrorCode || "failed";
|
|
9379
|
+
const abort_error_code = codeInput.toLowerCase();
|
|
9380
|
+
if (!RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES.includes(abort_error_code)) {
|
|
9381
|
+
throw new Error(`${label}.abort_error_code must be one of ${RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES.join(", ")}.`);
|
|
9382
|
+
}
|
|
9383
|
+
return { abort: true, abort_error_code };
|
|
9384
|
+
}
|
|
9351
9385
|
function normalizeNetworkMockDelay(input, label, defaultValue) {
|
|
9352
9386
|
const value = numberValue3(
|
|
9353
9387
|
input.delay_ms ?? input.delayMs ?? input.wait_ms ?? input.waitMs ?? input.latency_ms ?? input.latencyMs
|
|
@@ -9369,7 +9403,9 @@ function normalizeNetworkMockResponses(value, mockIndex, defaults) {
|
|
|
9369
9403
|
headers: defaults.headers,
|
|
9370
9404
|
body: defaults.body,
|
|
9371
9405
|
body_json: defaults.body_json,
|
|
9372
|
-
delay_ms: defaults.delay_ms
|
|
9406
|
+
delay_ms: defaults.delay_ms,
|
|
9407
|
+
abort: defaults.abort,
|
|
9408
|
+
abort_error_code: defaults.abort_error_code
|
|
9373
9409
|
};
|
|
9374
9410
|
return value.map((response, responseIndex) => {
|
|
9375
9411
|
if (!isRecord2(response)) {
|
|
@@ -10132,7 +10168,9 @@ function expectedFailedNetworkMockEvents(evidence) {
|
|
|
10132
10168
|
return (evidence.network_mocks || []).filter((event) => {
|
|
10133
10169
|
if (!isRecord2(event) || event.ok === false) return false;
|
|
10134
10170
|
const status = numberValue3(event.status);
|
|
10135
|
-
|
|
10171
|
+
const isHttpFailure = status !== void 0 && status >= 400;
|
|
10172
|
+
const isAbortedMock = event.abort === true && Boolean(stringValue5(event.abort_error_code));
|
|
10173
|
+
return (isHttpFailure || isAbortedMock) && Boolean(stringValue5(event.url));
|
|
10136
10174
|
});
|
|
10137
10175
|
}
|
|
10138
10176
|
function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
@@ -10142,7 +10180,8 @@ function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
|
10142
10180
|
if (!eventUrl) return void 0;
|
|
10143
10181
|
return expectedFailedNetworkMockEvents(evidence).find((mockEvent) => {
|
|
10144
10182
|
const status = numberValue3(mockEvent.status);
|
|
10145
|
-
|
|
10183
|
+
const abortErrorCode = stringValue5(mockEvent.abort_error_code);
|
|
10184
|
+
return stringValue5(mockEvent.url) === eventUrl && (status !== void 0 && sample.includes(String(status)) || Boolean(abortErrorCode) && /Failed to load resource/i.test(sample));
|
|
10146
10185
|
});
|
|
10147
10186
|
}
|
|
10148
10187
|
function isExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
@@ -10154,6 +10193,7 @@ function expectedFailedNetworkMockConsoleEventSummary(event, evidence) {
|
|
|
10154
10193
|
return {
|
|
10155
10194
|
url: consoleEventLocationUrl(event) ?? null,
|
|
10156
10195
|
status: match ? numberValue3(match.status) ?? null : null,
|
|
10196
|
+
abort_error_code: match ? stringValue5(match.abort_error_code) ?? null : null,
|
|
10157
10197
|
label: match ? stringValue5(match.label) ?? null : null,
|
|
10158
10198
|
response_label: match ? stringValue5(match.response_label) ?? null : null,
|
|
10159
10199
|
text: isRecord2(event) && typeof event.text === "string" ? event.text.slice(0, 300) : sample.slice(0, 300)
|
|
@@ -11170,7 +11210,8 @@ function expectedFailedNetworkMockEvents(evidence) {
|
|
|
11170
11210
|
if (!event || typeof event !== "object" || Array.isArray(event) || event.ok === false) return false;
|
|
11171
11211
|
const status = typeof event.status === "number" && Number.isFinite(event.status) ? event.status : undefined;
|
|
11172
11212
|
const url = typeof event.url === "string" && event.url.trim() ? event.url.trim() : undefined;
|
|
11173
|
-
|
|
11213
|
+
const abortErrorCode = typeof event.abort_error_code === "string" && event.abort_error_code.trim() ? event.abort_error_code.trim() : undefined;
|
|
11214
|
+
return ((status !== undefined && status >= 400) || (event.abort === true && Boolean(abortErrorCode))) && Boolean(url);
|
|
11174
11215
|
});
|
|
11175
11216
|
}
|
|
11176
11217
|
function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
@@ -11181,7 +11222,8 @@ function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
|
11181
11222
|
return expectedFailedNetworkMockEvents(evidence).find((mockEvent) => {
|
|
11182
11223
|
const status = typeof mockEvent.status === "number" && Number.isFinite(mockEvent.status) ? mockEvent.status : undefined;
|
|
11183
11224
|
const mockUrl = typeof mockEvent.url === "string" && mockEvent.url.trim() ? mockEvent.url.trim() : undefined;
|
|
11184
|
-
|
|
11225
|
+
const abortErrorCode = typeof mockEvent.abort_error_code === "string" && mockEvent.abort_error_code.trim() ? mockEvent.abort_error_code.trim() : undefined;
|
|
11226
|
+
return mockUrl === eventUrl && ((status !== undefined && sample.includes(String(status))) || (Boolean(abortErrorCode) && /Failed to load resource/i.test(sample)));
|
|
11185
11227
|
});
|
|
11186
11228
|
}
|
|
11187
11229
|
function isExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
@@ -11193,6 +11235,7 @@ function expectedFailedNetworkMockConsoleEventSummary(event, evidence) {
|
|
|
11193
11235
|
return {
|
|
11194
11236
|
url: consoleEventLocationUrl(event) || null,
|
|
11195
11237
|
status: match && typeof match.status === "number" && Number.isFinite(match.status) ? match.status : null,
|
|
11238
|
+
abort_error_code: match && typeof match.abort_error_code === "string" && match.abort_error_code.trim() ? match.abort_error_code.trim() : null,
|
|
11196
11239
|
label: match && typeof match.label === "string" && match.label.trim() ? match.label.trim() : null,
|
|
11197
11240
|
response_label: match && typeof match.response_label === "string" && match.response_label.trim() ? match.response_label.trim() : null,
|
|
11198
11241
|
text: event && typeof event === "object" && !Array.isArray(event) && typeof event.text === "string" ? event.text.slice(0, 300) : sample.slice(0, 300),
|
|
@@ -12826,6 +12869,10 @@ async function registerNetworkMocks(mocks) {
|
|
|
12826
12869
|
const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock, responseBodyContract) : [];
|
|
12827
12870
|
const status = response.status || mock.status || 200;
|
|
12828
12871
|
const delayMs = numberValue(response.delay_ms) || 0;
|
|
12872
|
+
const shouldAbort = response.abort === true;
|
|
12873
|
+
const abortErrorCode = typeof response.abort_error_code === "string" && response.abort_error_code.trim()
|
|
12874
|
+
? response.abort_error_code.trim()
|
|
12875
|
+
: "failed";
|
|
12829
12876
|
const event = {
|
|
12830
12877
|
ok: true,
|
|
12831
12878
|
label: mock.label,
|
|
@@ -12838,8 +12885,13 @@ async function registerNetworkMocks(mocks) {
|
|
|
12838
12885
|
sequence_cycle: responseSelection === "sequence" && responseIndex !== null && mock.repeat_responses === true && hitIndex >= responses.length,
|
|
12839
12886
|
url: request.url(),
|
|
12840
12887
|
method,
|
|
12841
|
-
status,
|
|
12842
12888
|
};
|
|
12889
|
+
if (shouldAbort) {
|
|
12890
|
+
event.abort = true;
|
|
12891
|
+
event.abort_error_code = abortErrorCode;
|
|
12892
|
+
} else {
|
|
12893
|
+
event.status = status;
|
|
12894
|
+
}
|
|
12843
12895
|
if (delayMs) event.delay_ms = delayMs;
|
|
12844
12896
|
if (shouldCaptureRequestBody) {
|
|
12845
12897
|
event.request_body_matches = requestBodyFailures.length === 0;
|
|
@@ -12849,6 +12901,10 @@ async function registerNetworkMocks(mocks) {
|
|
|
12849
12901
|
}
|
|
12850
12902
|
networkMockEvents.push(event);
|
|
12851
12903
|
if (delayMs) await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
12904
|
+
if (shouldAbort) {
|
|
12905
|
+
await route.abort(abortErrorCode);
|
|
12906
|
+
return;
|
|
12907
|
+
}
|
|
12852
12908
|
await route.fulfill({
|
|
12853
12909
|
status,
|
|
12854
12910
|
headers,
|
|
@@ -14946,6 +15002,7 @@ function createRiddleApiClient(config = {}) {
|
|
|
14946
15002
|
RIDDLE_PROOF_PLAYABILITY_VERSION,
|
|
14947
15003
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
14948
15004
|
RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
|
|
15005
|
+
RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES,
|
|
14949
15006
|
RIDDLE_PROOF_PROFILE_RESULT_VERSION,
|
|
14950
15007
|
RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
|
|
14951
15008
|
RIDDLE_PROOF_PROFILE_STATUSES,
|
package/dist/index.d.cts
CHANGED
|
@@ -10,5 +10,5 @@ export { CreateCaptureDiagnosticInput, DEFAULT_DIAGNOSTIC_ARRAY_LIMIT, DEFAULT_D
|
|
|
10
10
|
export { BuildVisualProofSessionInput, RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION, RIDDLE_PROOF_VISUAL_SESSION_VERSION, VisualProofSessionMismatch, buildVisualProofSession, compareVisualProofSessionFingerprint, parseVisualProofSession, visualSessionFingerprint, visualSessionFingerprintBasis } from './proof-session.cjs';
|
|
11
11
|
export { AssessPlayabilityOptions, RIDDLE_PROOF_PLAYABILITY_ASSESSMENT_VERSION, RIDDLE_PROOF_PLAYABILITY_VERSION, RiddleProofPlayabilityAssessment, RiddleProofPlayabilityEvidence, assessPlayabilityEvidence, extractPlayabilityEvidence, isRiddleProofPlayabilityMode } from './playability.cjs';
|
|
12
12
|
export { AssessBasicGameplayOptions, AttachBasicGameplayArtifactOptions, BASIC_GAMEPLAY_ACTION_TYPES, BASIC_GAMEPLAY_PROGRESS_CHECK_TYPES, BasicGameplayActionResult, BasicGameplayActionType, BasicGameplayArtifactResolution, BasicGameplayAssessmentSummary, BasicGameplayBoundsOffender, BasicGameplayCanvasState, BasicGameplayCatchRecord, BasicGameplayChangeSummary, BasicGameplayFailureCode, BasicGameplayFixReference, BasicGameplayMetric, BasicGameplayMobileEvidence, BasicGameplayProgressCheckType, BasicGameplayProgressionCheck, BasicGameplayProofArtifact, BasicGameplayResponsiveViewportEvidence, BasicGameplayRouteReference, BasicGameplaySnapshot, BasicGameplaySuiteFailure, BasicGameplayWarningCode, CreateBasicGameplayCatchSummaryInput, RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION, RiddleProofBasicGameplayAssessment, RiddleProofBasicGameplayCatchSummary, RiddleProofBasicGameplayEvidence, RiddleProofBasicGameplayRouteAssessment, RiddleProofBasicGameplayRouteEvidence, assessBasicGameplayEvidence, assessBasicGameplayProgressionCheck, assessBasicGameplayProgressionChecks, assessBasicGameplayRoute, attachBasicGameplayArtifactScreenshotHashes, augmentBasicGameplayAssessmentWithProgressionChecks, compactBasicGameplayText, createBasicGameplayCatchRecords, createBasicGameplayCatchSummary, extractBasicGameplayEvidence, resolveBasicGameplayProgressionCheckWithArtifactScreenshots, sanitizeBasicGameplayJsonString } from './basic-gameplay.cjs';
|
|
13
|
-
export { NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, RiddleProofProfile, RiddleProofProfileArtifactRef, RiddleProofProfileBaselinePolicy, RiddleProofProfileBoundsOffender, RiddleProofProfileCheck, RiddleProofProfileCheckResult, RiddleProofProfileCheckType, RiddleProofProfileEvidence, RiddleProofProfileFailureAction, RiddleProofProfileNetworkMock, RiddleProofProfileNetworkMockResponse, RiddleProofProfileResult, RiddleProofProfileRouteEvidence, RiddleProofProfileRouteInventoryRoute, RiddleProofProfileRunner, RiddleProofProfileSetupAction, RiddleProofProfileSetupActionType, RiddleProofProfileStatus, RiddleProofProfileTarget, RiddleProofProfileViewport, RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult } from './profile.cjs';
|
|
13
|
+
export { NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, RiddleProofProfile, RiddleProofProfileArtifactRef, RiddleProofProfileBaselinePolicy, RiddleProofProfileBoundsOffender, RiddleProofProfileCheck, RiddleProofProfileCheckResult, RiddleProofProfileCheckType, RiddleProofProfileEvidence, RiddleProofProfileFailureAction, RiddleProofProfileNetworkAbortErrorCode, RiddleProofProfileNetworkMock, RiddleProofProfileNetworkMockResponse, RiddleProofProfileResult, RiddleProofProfileRouteEvidence, RiddleProofProfileRouteInventoryRoute, RiddleProofProfileRunner, RiddleProofProfileSetupAction, RiddleProofProfileSetupActionType, RiddleProofProfileStatus, RiddleProofProfileTarget, RiddleProofProfileViewport, RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult } from './profile.cjs';
|
|
14
14
|
export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RiddleApiError, RiddleClientConfig, RiddleFetch, RiddlePollJobOptions, RiddlePollJobResult, RiddlePollProgressSnapshot, RiddlePollSummary, RiddlePreviewDeployResult, RiddlePreviewFramework, RiddleRunScriptInput, RiddleServerPreviewInput, RiddleServerPreviewResult, createRiddleApiClient, deployRiddlePreview, deployRiddleStaticPreview, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, riddleRequestJson, runRiddleScript, runRiddleServerPreview } from './riddle-client.cjs';
|
package/dist/index.d.ts
CHANGED
|
@@ -10,5 +10,5 @@ export { CreateCaptureDiagnosticInput, DEFAULT_DIAGNOSTIC_ARRAY_LIMIT, DEFAULT_D
|
|
|
10
10
|
export { BuildVisualProofSessionInput, RIDDLE_PROOF_VISUAL_SESSION_FINGERPRINT_VERSION, RIDDLE_PROOF_VISUAL_SESSION_VERSION, VisualProofSessionMismatch, buildVisualProofSession, compareVisualProofSessionFingerprint, parseVisualProofSession, visualSessionFingerprint, visualSessionFingerprintBasis } from './proof-session.js';
|
|
11
11
|
export { AssessPlayabilityOptions, RIDDLE_PROOF_PLAYABILITY_ASSESSMENT_VERSION, RIDDLE_PROOF_PLAYABILITY_VERSION, RiddleProofPlayabilityAssessment, RiddleProofPlayabilityEvidence, assessPlayabilityEvidence, extractPlayabilityEvidence, isRiddleProofPlayabilityMode } from './playability.js';
|
|
12
12
|
export { AssessBasicGameplayOptions, AttachBasicGameplayArtifactOptions, BASIC_GAMEPLAY_ACTION_TYPES, BASIC_GAMEPLAY_PROGRESS_CHECK_TYPES, BasicGameplayActionResult, BasicGameplayActionType, BasicGameplayArtifactResolution, BasicGameplayAssessmentSummary, BasicGameplayBoundsOffender, BasicGameplayCanvasState, BasicGameplayCatchRecord, BasicGameplayChangeSummary, BasicGameplayFailureCode, BasicGameplayFixReference, BasicGameplayMetric, BasicGameplayMobileEvidence, BasicGameplayProgressCheckType, BasicGameplayProgressionCheck, BasicGameplayProofArtifact, BasicGameplayResponsiveViewportEvidence, BasicGameplayRouteReference, BasicGameplaySnapshot, BasicGameplaySuiteFailure, BasicGameplayWarningCode, CreateBasicGameplayCatchSummaryInput, RIDDLE_PROOF_BASIC_GAMEPLAY_ASSESSMENT_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_CATCH_VERSION, RIDDLE_PROOF_BASIC_GAMEPLAY_VERSION, RiddleProofBasicGameplayAssessment, RiddleProofBasicGameplayCatchSummary, RiddleProofBasicGameplayEvidence, RiddleProofBasicGameplayRouteAssessment, RiddleProofBasicGameplayRouteEvidence, assessBasicGameplayEvidence, assessBasicGameplayProgressionCheck, assessBasicGameplayProgressionChecks, assessBasicGameplayRoute, attachBasicGameplayArtifactScreenshotHashes, augmentBasicGameplayAssessmentWithProgressionChecks, compactBasicGameplayText, createBasicGameplayCatchRecords, createBasicGameplayCatchSummary, extractBasicGameplayEvidence, resolveBasicGameplayProgressionCheckWithArtifactScreenshots, sanitizeBasicGameplayJsonString } from './basic-gameplay.js';
|
|
13
|
-
export { NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, RiddleProofProfile, RiddleProofProfileArtifactRef, RiddleProofProfileBaselinePolicy, RiddleProofProfileBoundsOffender, RiddleProofProfileCheck, RiddleProofProfileCheckResult, RiddleProofProfileCheckType, RiddleProofProfileEvidence, RiddleProofProfileFailureAction, RiddleProofProfileNetworkMock, RiddleProofProfileNetworkMockResponse, RiddleProofProfileResult, RiddleProofProfileRouteEvidence, RiddleProofProfileRouteInventoryRoute, RiddleProofProfileRunner, RiddleProofProfileSetupAction, RiddleProofProfileSetupActionType, RiddleProofProfileStatus, RiddleProofProfileTarget, RiddleProofProfileViewport, RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult } from './profile.js';
|
|
13
|
+
export { NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, RiddleProofProfile, RiddleProofProfileArtifactRef, RiddleProofProfileBaselinePolicy, RiddleProofProfileBoundsOffender, RiddleProofProfileCheck, RiddleProofProfileCheckResult, RiddleProofProfileCheckType, RiddleProofProfileEvidence, RiddleProofProfileFailureAction, RiddleProofProfileNetworkAbortErrorCode, RiddleProofProfileNetworkMock, RiddleProofProfileNetworkMockResponse, RiddleProofProfileResult, RiddleProofProfileRouteEvidence, RiddleProofProfileRouteInventoryRoute, RiddleProofProfileRunner, RiddleProofProfileSetupAction, RiddleProofProfileSetupActionType, RiddleProofProfileStatus, RiddleProofProfileTarget, RiddleProofProfileViewport, RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult } from './profile.js';
|
|
14
14
|
export { DEFAULT_RIDDLE_API_BASE_URL, DEFAULT_RIDDLE_API_KEY_FILE, RiddleApiError, RiddleClientConfig, RiddleFetch, RiddlePollJobOptions, RiddlePollJobResult, RiddlePollProgressSnapshot, RiddlePollSummary, RiddlePreviewDeployResult, RiddlePreviewFramework, RiddleRunScriptInput, RiddleServerPreviewInput, RiddleServerPreviewResult, createRiddleApiClient, deployRiddlePreview, deployRiddleStaticPreview, isTerminalRiddleJobStatus, parseRiddleViewport, pollRiddleJob, resolveRiddleApiKey, riddleRequestJson, runRiddleScript, runRiddleServerPreview } from './riddle-client.js';
|
package/dist/index.js
CHANGED
|
@@ -40,6 +40,7 @@ import {
|
|
|
40
40
|
import {
|
|
41
41
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
42
42
|
RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
|
|
43
|
+
RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES,
|
|
43
44
|
RIDDLE_PROOF_PROFILE_RESULT_VERSION,
|
|
44
45
|
RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
|
|
45
46
|
RIDDLE_PROOF_PROFILE_STATUSES,
|
|
@@ -59,7 +60,7 @@ import {
|
|
|
59
60
|
resolveRiddleProofProfileTimeoutSec,
|
|
60
61
|
slugifyRiddleProofProfileName,
|
|
61
62
|
summarizeRiddleProofProfileResult
|
|
62
|
-
} from "./chunk-
|
|
63
|
+
} from "./chunk-DVMBXDIF.js";
|
|
63
64
|
import {
|
|
64
65
|
DEFAULT_RIDDLE_API_BASE_URL,
|
|
65
66
|
DEFAULT_RIDDLE_API_KEY_FILE,
|
|
@@ -157,6 +158,7 @@ export {
|
|
|
157
158
|
RIDDLE_PROOF_PLAYABILITY_VERSION,
|
|
158
159
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
159
160
|
RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
|
|
161
|
+
RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES,
|
|
160
162
|
RIDDLE_PROOF_PROFILE_RESULT_VERSION,
|
|
161
163
|
RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
|
|
162
164
|
RIDDLE_PROOF_PROFILE_STATUSES,
|
package/dist/profile.cjs
CHANGED
|
@@ -22,6 +22,7 @@ var profile_exports = {};
|
|
|
22
22
|
__export(profile_exports, {
|
|
23
23
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES: () => RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
24
24
|
RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: () => RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
|
|
25
|
+
RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES: () => RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES,
|
|
25
26
|
RIDDLE_PROOF_PROFILE_RESULT_VERSION: () => RIDDLE_PROOF_PROFILE_RESULT_VERSION,
|
|
26
27
|
RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: () => RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
|
|
27
28
|
RIDDLE_PROOF_PROFILE_STATUSES: () => RIDDLE_PROOF_PROFILE_STATUSES,
|
|
@@ -107,6 +108,22 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
|
|
|
107
108
|
"wait_for_text",
|
|
108
109
|
"window_call"
|
|
109
110
|
];
|
|
111
|
+
var RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES = [
|
|
112
|
+
"aborted",
|
|
113
|
+
"accessdenied",
|
|
114
|
+
"addressunreachable",
|
|
115
|
+
"blockedbyclient",
|
|
116
|
+
"blockedbyresponse",
|
|
117
|
+
"connectionaborted",
|
|
118
|
+
"connectionclosed",
|
|
119
|
+
"connectionfailed",
|
|
120
|
+
"connectionrefused",
|
|
121
|
+
"connectionreset",
|
|
122
|
+
"internetdisconnected",
|
|
123
|
+
"namenotresolved",
|
|
124
|
+
"timedout",
|
|
125
|
+
"failed"
|
|
126
|
+
];
|
|
110
127
|
var DEFAULT_VIEWPORTS = [
|
|
111
128
|
{ name: "desktop", width: 1280, height: 800 }
|
|
112
129
|
];
|
|
@@ -647,6 +664,7 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
|
647
664
|
const body = stringValue(input.body) ?? stringValue(input.body_text) ?? stringValue(input.bodyText) ?? defaults.body;
|
|
648
665
|
const hasJsonBody = Object.prototype.hasOwnProperty.call(input, "body_json") || Object.prototype.hasOwnProperty.call(input, "bodyJson") || Object.prototype.hasOwnProperty.call(input, "json");
|
|
649
666
|
const requestBody = normalizeNetworkMockRequestBodyConstraints(input, label);
|
|
667
|
+
const abort = normalizeNetworkMockAbort(input, label, defaults.abort, defaults.abort_error_code);
|
|
650
668
|
return {
|
|
651
669
|
label: stringValue(input.label) || stringValue(input.name) || defaults.label,
|
|
652
670
|
status,
|
|
@@ -655,6 +673,8 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
|
655
673
|
body,
|
|
656
674
|
body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json,
|
|
657
675
|
delay_ms: normalizeNetworkMockDelay(input, label, defaults.delay_ms),
|
|
676
|
+
abort: abort.abort,
|
|
677
|
+
abort_error_code: abort.abort_error_code,
|
|
658
678
|
capture_request_body: requestBody.capture_request_body,
|
|
659
679
|
request_body_contains: requestBody.request_body_contains,
|
|
660
680
|
request_body_patterns: requestBody.request_body_patterns,
|
|
@@ -662,6 +682,20 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
|
662
682
|
request_body_not_patterns: requestBody.request_body_not_patterns
|
|
663
683
|
};
|
|
664
684
|
}
|
|
685
|
+
function normalizeNetworkMockAbort(input, label, defaultAbort, defaultErrorCode) {
|
|
686
|
+
const abortInput = input.abort ?? input.route_abort ?? input.routeAbort;
|
|
687
|
+
const explicitAbort = typeof abortInput === "string" ? abortInput.trim().length > 0 : abortInput === true;
|
|
688
|
+
const abort = explicitAbort || defaultAbort === true;
|
|
689
|
+
if (!abort) return {};
|
|
690
|
+
const codeInput = stringValue(
|
|
691
|
+
typeof abortInput === "string" ? abortInput : input.abort_error_code ?? input.abortErrorCode ?? input.abort_error ?? input.abortError ?? input.network_error ?? input.networkError
|
|
692
|
+
) || defaultErrorCode || "failed";
|
|
693
|
+
const abort_error_code = codeInput.toLowerCase();
|
|
694
|
+
if (!RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES.includes(abort_error_code)) {
|
|
695
|
+
throw new Error(`${label}.abort_error_code must be one of ${RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES.join(", ")}.`);
|
|
696
|
+
}
|
|
697
|
+
return { abort: true, abort_error_code };
|
|
698
|
+
}
|
|
665
699
|
function normalizeNetworkMockDelay(input, label, defaultValue) {
|
|
666
700
|
const value = numberValue(
|
|
667
701
|
input.delay_ms ?? input.delayMs ?? input.wait_ms ?? input.waitMs ?? input.latency_ms ?? input.latencyMs
|
|
@@ -683,7 +717,9 @@ function normalizeNetworkMockResponses(value, mockIndex, defaults) {
|
|
|
683
717
|
headers: defaults.headers,
|
|
684
718
|
body: defaults.body,
|
|
685
719
|
body_json: defaults.body_json,
|
|
686
|
-
delay_ms: defaults.delay_ms
|
|
720
|
+
delay_ms: defaults.delay_ms,
|
|
721
|
+
abort: defaults.abort,
|
|
722
|
+
abort_error_code: defaults.abort_error_code
|
|
687
723
|
};
|
|
688
724
|
return value.map((response, responseIndex) => {
|
|
689
725
|
if (!isRecord(response)) {
|
|
@@ -1446,7 +1482,9 @@ function expectedFailedNetworkMockEvents(evidence) {
|
|
|
1446
1482
|
return (evidence.network_mocks || []).filter((event) => {
|
|
1447
1483
|
if (!isRecord(event) || event.ok === false) return false;
|
|
1448
1484
|
const status = numberValue(event.status);
|
|
1449
|
-
|
|
1485
|
+
const isHttpFailure = status !== void 0 && status >= 400;
|
|
1486
|
+
const isAbortedMock = event.abort === true && Boolean(stringValue(event.abort_error_code));
|
|
1487
|
+
return (isHttpFailure || isAbortedMock) && Boolean(stringValue(event.url));
|
|
1450
1488
|
});
|
|
1451
1489
|
}
|
|
1452
1490
|
function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
@@ -1456,7 +1494,8 @@ function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
|
1456
1494
|
if (!eventUrl) return void 0;
|
|
1457
1495
|
return expectedFailedNetworkMockEvents(evidence).find((mockEvent) => {
|
|
1458
1496
|
const status = numberValue(mockEvent.status);
|
|
1459
|
-
|
|
1497
|
+
const abortErrorCode = stringValue(mockEvent.abort_error_code);
|
|
1498
|
+
return stringValue(mockEvent.url) === eventUrl && (status !== void 0 && sample.includes(String(status)) || Boolean(abortErrorCode) && /Failed to load resource/i.test(sample));
|
|
1460
1499
|
});
|
|
1461
1500
|
}
|
|
1462
1501
|
function isExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
@@ -1468,6 +1507,7 @@ function expectedFailedNetworkMockConsoleEventSummary(event, evidence) {
|
|
|
1468
1507
|
return {
|
|
1469
1508
|
url: consoleEventLocationUrl(event) ?? null,
|
|
1470
1509
|
status: match ? numberValue(match.status) ?? null : null,
|
|
1510
|
+
abort_error_code: match ? stringValue(match.abort_error_code) ?? null : null,
|
|
1471
1511
|
label: match ? stringValue(match.label) ?? null : null,
|
|
1472
1512
|
response_label: match ? stringValue(match.response_label) ?? null : null,
|
|
1473
1513
|
text: isRecord(event) && typeof event.text === "string" ? event.text.slice(0, 300) : sample.slice(0, 300)
|
|
@@ -2484,7 +2524,8 @@ function expectedFailedNetworkMockEvents(evidence) {
|
|
|
2484
2524
|
if (!event || typeof event !== "object" || Array.isArray(event) || event.ok === false) return false;
|
|
2485
2525
|
const status = typeof event.status === "number" && Number.isFinite(event.status) ? event.status : undefined;
|
|
2486
2526
|
const url = typeof event.url === "string" && event.url.trim() ? event.url.trim() : undefined;
|
|
2487
|
-
|
|
2527
|
+
const abortErrorCode = typeof event.abort_error_code === "string" && event.abort_error_code.trim() ? event.abort_error_code.trim() : undefined;
|
|
2528
|
+
return ((status !== undefined && status >= 400) || (event.abort === true && Boolean(abortErrorCode))) && Boolean(url);
|
|
2488
2529
|
});
|
|
2489
2530
|
}
|
|
2490
2531
|
function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
@@ -2495,7 +2536,8 @@ function matchingExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
|
2495
2536
|
return expectedFailedNetworkMockEvents(evidence).find((mockEvent) => {
|
|
2496
2537
|
const status = typeof mockEvent.status === "number" && Number.isFinite(mockEvent.status) ? mockEvent.status : undefined;
|
|
2497
2538
|
const mockUrl = typeof mockEvent.url === "string" && mockEvent.url.trim() ? mockEvent.url.trim() : undefined;
|
|
2498
|
-
|
|
2539
|
+
const abortErrorCode = typeof mockEvent.abort_error_code === "string" && mockEvent.abort_error_code.trim() ? mockEvent.abort_error_code.trim() : undefined;
|
|
2540
|
+
return mockUrl === eventUrl && ((status !== undefined && sample.includes(String(status))) || (Boolean(abortErrorCode) && /Failed to load resource/i.test(sample)));
|
|
2499
2541
|
});
|
|
2500
2542
|
}
|
|
2501
2543
|
function isExpectedFailedNetworkMockConsoleEvent(event, evidence) {
|
|
@@ -2507,6 +2549,7 @@ function expectedFailedNetworkMockConsoleEventSummary(event, evidence) {
|
|
|
2507
2549
|
return {
|
|
2508
2550
|
url: consoleEventLocationUrl(event) || null,
|
|
2509
2551
|
status: match && typeof match.status === "number" && Number.isFinite(match.status) ? match.status : null,
|
|
2552
|
+
abort_error_code: match && typeof match.abort_error_code === "string" && match.abort_error_code.trim() ? match.abort_error_code.trim() : null,
|
|
2510
2553
|
label: match && typeof match.label === "string" && match.label.trim() ? match.label.trim() : null,
|
|
2511
2554
|
response_label: match && typeof match.response_label === "string" && match.response_label.trim() ? match.response_label.trim() : null,
|
|
2512
2555
|
text: event && typeof event === "object" && !Array.isArray(event) && typeof event.text === "string" ? event.text.slice(0, 300) : sample.slice(0, 300),
|
|
@@ -4140,6 +4183,10 @@ async function registerNetworkMocks(mocks) {
|
|
|
4140
4183
|
const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock, responseBodyContract) : [];
|
|
4141
4184
|
const status = response.status || mock.status || 200;
|
|
4142
4185
|
const delayMs = numberValue(response.delay_ms) || 0;
|
|
4186
|
+
const shouldAbort = response.abort === true;
|
|
4187
|
+
const abortErrorCode = typeof response.abort_error_code === "string" && response.abort_error_code.trim()
|
|
4188
|
+
? response.abort_error_code.trim()
|
|
4189
|
+
: "failed";
|
|
4143
4190
|
const event = {
|
|
4144
4191
|
ok: true,
|
|
4145
4192
|
label: mock.label,
|
|
@@ -4152,8 +4199,13 @@ async function registerNetworkMocks(mocks) {
|
|
|
4152
4199
|
sequence_cycle: responseSelection === "sequence" && responseIndex !== null && mock.repeat_responses === true && hitIndex >= responses.length,
|
|
4153
4200
|
url: request.url(),
|
|
4154
4201
|
method,
|
|
4155
|
-
status,
|
|
4156
4202
|
};
|
|
4203
|
+
if (shouldAbort) {
|
|
4204
|
+
event.abort = true;
|
|
4205
|
+
event.abort_error_code = abortErrorCode;
|
|
4206
|
+
} else {
|
|
4207
|
+
event.status = status;
|
|
4208
|
+
}
|
|
4157
4209
|
if (delayMs) event.delay_ms = delayMs;
|
|
4158
4210
|
if (shouldCaptureRequestBody) {
|
|
4159
4211
|
event.request_body_matches = requestBodyFailures.length === 0;
|
|
@@ -4163,6 +4215,10 @@ async function registerNetworkMocks(mocks) {
|
|
|
4163
4215
|
}
|
|
4164
4216
|
networkMockEvents.push(event);
|
|
4165
4217
|
if (delayMs) await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
4218
|
+
if (shouldAbort) {
|
|
4219
|
+
await route.abort(abortErrorCode);
|
|
4220
|
+
return;
|
|
4221
|
+
}
|
|
4166
4222
|
await route.fulfill({
|
|
4167
4223
|
status,
|
|
4168
4224
|
headers,
|
|
@@ -5868,6 +5924,7 @@ function extractRiddleProofProfileResult(input) {
|
|
|
5868
5924
|
0 && (module.exports = {
|
|
5869
5925
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
5870
5926
|
RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
|
|
5927
|
+
RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES,
|
|
5871
5928
|
RIDDLE_PROOF_PROFILE_RESULT_VERSION,
|
|
5872
5929
|
RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
|
|
5873
5930
|
RIDDLE_PROOF_PROFILE_STATUSES,
|
package/dist/profile.d.cts
CHANGED
|
@@ -9,6 +9,8 @@ declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "drag"
|
|
|
9
9
|
type RiddleProofProfileStatus = typeof RIDDLE_PROOF_PROFILE_STATUSES[number];
|
|
10
10
|
type RiddleProofProfileCheckType = typeof RIDDLE_PROOF_PROFILE_CHECK_TYPES[number];
|
|
11
11
|
type RiddleProofProfileSetupActionType = typeof RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES[number];
|
|
12
|
+
declare const RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES: readonly ["aborted", "accessdenied", "addressunreachable", "blockedbyclient", "blockedbyresponse", "connectionaborted", "connectionclosed", "connectionfailed", "connectionrefused", "connectionreset", "internetdisconnected", "namenotresolved", "timedout", "failed"];
|
|
13
|
+
type RiddleProofProfileNetworkAbortErrorCode = typeof RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES[number];
|
|
12
14
|
type RiddleProofProfileRunner = "riddle" | "local-playwright" | "browserless" | "github-actions" | (string & {});
|
|
13
15
|
type RiddleProofProfileFailureAction = "fail" | "neutral" | "review";
|
|
14
16
|
type RiddleProofProfileBaselinePolicy = "invariant_only" | "production_comparison" | "last_accepted_artifact" | "golden_reference_artifact" | (string & {});
|
|
@@ -68,6 +70,8 @@ interface RiddleProofProfileNetworkMockResponse {
|
|
|
68
70
|
body?: string;
|
|
69
71
|
body_json?: JsonValue;
|
|
70
72
|
delay_ms?: number;
|
|
73
|
+
abort?: boolean;
|
|
74
|
+
abort_error_code?: RiddleProofProfileNetworkAbortErrorCode;
|
|
71
75
|
capture_request_body?: boolean;
|
|
72
76
|
request_body_contains?: string[];
|
|
73
77
|
request_body_patterns?: string[];
|
|
@@ -326,4 +330,4 @@ declare function buildRiddleProofProfileScript(profile: RiddleProofProfile): str
|
|
|
326
330
|
declare function collectRiddleProfileArtifactRefs(input: unknown): RiddleProofProfileArtifactRef[];
|
|
327
331
|
declare function extractRiddleProofProfileResult(input: unknown): RiddleProofProfileResult | undefined;
|
|
328
332
|
|
|
329
|
-
export { type NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, type RiddleProofProfile, type RiddleProofProfileArtifactRef, type RiddleProofProfileBaselinePolicy, type RiddleProofProfileBoundsOffender, type RiddleProofProfileCheck, type RiddleProofProfileCheckResult, type RiddleProofProfileCheckType, type RiddleProofProfileEvidence, type RiddleProofProfileFailureAction, type RiddleProofProfileNetworkMock, type RiddleProofProfileNetworkMockResponse, type RiddleProofProfileResult, type RiddleProofProfileRouteEvidence, type RiddleProofProfileRouteInventoryRoute, type RiddleProofProfileRunner, type RiddleProofProfileSetupAction, type RiddleProofProfileSetupActionType, type RiddleProofProfileStatus, type RiddleProofProfileTarget, type RiddleProofProfileViewport, type RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult };
|
|
333
|
+
export { type NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, type RiddleProofProfile, type RiddleProofProfileArtifactRef, type RiddleProofProfileBaselinePolicy, type RiddleProofProfileBoundsOffender, type RiddleProofProfileCheck, type RiddleProofProfileCheckResult, type RiddleProofProfileCheckType, type RiddleProofProfileEvidence, type RiddleProofProfileFailureAction, type RiddleProofProfileNetworkAbortErrorCode, type RiddleProofProfileNetworkMock, type RiddleProofProfileNetworkMockResponse, type RiddleProofProfileResult, type RiddleProofProfileRouteEvidence, type RiddleProofProfileRouteInventoryRoute, type RiddleProofProfileRunner, type RiddleProofProfileSetupAction, type RiddleProofProfileSetupActionType, type RiddleProofProfileStatus, type RiddleProofProfileTarget, type RiddleProofProfileViewport, type RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult };
|
package/dist/profile.d.ts
CHANGED
|
@@ -9,6 +9,8 @@ declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "drag"
|
|
|
9
9
|
type RiddleProofProfileStatus = typeof RIDDLE_PROOF_PROFILE_STATUSES[number];
|
|
10
10
|
type RiddleProofProfileCheckType = typeof RIDDLE_PROOF_PROFILE_CHECK_TYPES[number];
|
|
11
11
|
type RiddleProofProfileSetupActionType = typeof RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES[number];
|
|
12
|
+
declare const RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES: readonly ["aborted", "accessdenied", "addressunreachable", "blockedbyclient", "blockedbyresponse", "connectionaborted", "connectionclosed", "connectionfailed", "connectionrefused", "connectionreset", "internetdisconnected", "namenotresolved", "timedout", "failed"];
|
|
13
|
+
type RiddleProofProfileNetworkAbortErrorCode = typeof RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES[number];
|
|
12
14
|
type RiddleProofProfileRunner = "riddle" | "local-playwright" | "browserless" | "github-actions" | (string & {});
|
|
13
15
|
type RiddleProofProfileFailureAction = "fail" | "neutral" | "review";
|
|
14
16
|
type RiddleProofProfileBaselinePolicy = "invariant_only" | "production_comparison" | "last_accepted_artifact" | "golden_reference_artifact" | (string & {});
|
|
@@ -68,6 +70,8 @@ interface RiddleProofProfileNetworkMockResponse {
|
|
|
68
70
|
body?: string;
|
|
69
71
|
body_json?: JsonValue;
|
|
70
72
|
delay_ms?: number;
|
|
73
|
+
abort?: boolean;
|
|
74
|
+
abort_error_code?: RiddleProofProfileNetworkAbortErrorCode;
|
|
71
75
|
capture_request_body?: boolean;
|
|
72
76
|
request_body_contains?: string[];
|
|
73
77
|
request_body_patterns?: string[];
|
|
@@ -326,4 +330,4 @@ declare function buildRiddleProofProfileScript(profile: RiddleProofProfile): str
|
|
|
326
330
|
declare function collectRiddleProfileArtifactRefs(input: unknown): RiddleProofProfileArtifactRef[];
|
|
327
331
|
declare function extractRiddleProofProfileResult(input: unknown): RiddleProofProfileResult | undefined;
|
|
328
332
|
|
|
329
|
-
export { type NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, type RiddleProofProfile, type RiddleProofProfileArtifactRef, type RiddleProofProfileBaselinePolicy, type RiddleProofProfileBoundsOffender, type RiddleProofProfileCheck, type RiddleProofProfileCheckResult, type RiddleProofProfileCheckType, type RiddleProofProfileEvidence, type RiddleProofProfileFailureAction, type RiddleProofProfileNetworkMock, type RiddleProofProfileNetworkMockResponse, type RiddleProofProfileResult, type RiddleProofProfileRouteEvidence, type RiddleProofProfileRouteInventoryRoute, type RiddleProofProfileRunner, type RiddleProofProfileSetupAction, type RiddleProofProfileSetupActionType, type RiddleProofProfileStatus, type RiddleProofProfileTarget, type RiddleProofProfileViewport, type RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult };
|
|
333
|
+
export { type NormalizeRiddleProofProfileOptions, RIDDLE_PROOF_PROFILE_CHECK_TYPES, RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION, RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES, RIDDLE_PROOF_PROFILE_RESULT_VERSION, RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES, RIDDLE_PROOF_PROFILE_STATUSES, RIDDLE_PROOF_PROFILE_VERSION, type RiddleProofProfile, type RiddleProofProfileArtifactRef, type RiddleProofProfileBaselinePolicy, type RiddleProofProfileBoundsOffender, type RiddleProofProfileCheck, type RiddleProofProfileCheckResult, type RiddleProofProfileCheckType, type RiddleProofProfileEvidence, type RiddleProofProfileFailureAction, type RiddleProofProfileNetworkAbortErrorCode, type RiddleProofProfileNetworkMock, type RiddleProofProfileNetworkMockResponse, type RiddleProofProfileResult, type RiddleProofProfileRouteEvidence, type RiddleProofProfileRouteInventoryRoute, type RiddleProofProfileRunner, type RiddleProofProfileSetupAction, type RiddleProofProfileSetupActionType, type RiddleProofProfileStatus, type RiddleProofProfileTarget, type RiddleProofProfileViewport, type RiddleProofProfileViewportEvidence, assessRiddleProofProfileEvidence, buildRiddleProofProfileScript, collectRiddleProfileArtifactRefs, collectRiddleProofProfileWarnings, createRiddleProofProfileConfigurationError, createRiddleProofProfileEnvironmentBlockedResult, createRiddleProofProfileInsufficientResult, extractRiddleProofProfileResult, normalizeRiddleProofProfile, profileStatusExitCode, resolveRiddleProofProfileRouteUrl, resolveRiddleProofProfileTargetUrl, resolveRiddleProofProfileTimeoutSec, slugifyRiddleProofProfileName, summarizeRiddleProofProfileResult };
|
package/dist/profile.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
3
3
|
RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
|
|
4
|
+
RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES,
|
|
4
5
|
RIDDLE_PROOF_PROFILE_RESULT_VERSION,
|
|
5
6
|
RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
|
|
6
7
|
RIDDLE_PROOF_PROFILE_STATUSES,
|
|
@@ -20,10 +21,11 @@ import {
|
|
|
20
21
|
resolveRiddleProofProfileTimeoutSec,
|
|
21
22
|
slugifyRiddleProofProfileName,
|
|
22
23
|
summarizeRiddleProofProfileResult
|
|
23
|
-
} from "./chunk-
|
|
24
|
+
} from "./chunk-DVMBXDIF.js";
|
|
24
25
|
export {
|
|
25
26
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
26
27
|
RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
|
|
28
|
+
RIDDLE_PROOF_PROFILE_NETWORK_ABORT_ERROR_CODES,
|
|
27
29
|
RIDDLE_PROOF_PROFILE_RESULT_VERSION,
|
|
28
30
|
RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES,
|
|
29
31
|
RIDDLE_PROOF_PROFILE_STATUSES,
|
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "riddle-proof.profile.v1",
|
|
3
|
+
"name": "handled-recovery-action-malformed-success",
|
|
4
|
+
"target": {
|
|
5
|
+
"route": "/account",
|
|
6
|
+
"viewports": [
|
|
7
|
+
{ "name": "mobile", "width": 390, "height": 844 },
|
|
8
|
+
{ "name": "tablet", "width": 820, "height": 1180 },
|
|
9
|
+
{ "name": "desktop", "width": 1440, "height": 1000 }
|
|
10
|
+
],
|
|
11
|
+
"timeout_sec": 300,
|
|
12
|
+
"wait_ms": 800,
|
|
13
|
+
"network_mocks": [
|
|
14
|
+
{
|
|
15
|
+
"label": "account-summary",
|
|
16
|
+
"url": "**/api/account/summary",
|
|
17
|
+
"method": "GET",
|
|
18
|
+
"status": 200,
|
|
19
|
+
"content_type": "application/json",
|
|
20
|
+
"required_hit_count": 3,
|
|
21
|
+
"json": {
|
|
22
|
+
"available_time": "4h 0m",
|
|
23
|
+
"active_jobs": 2
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"label": "recent-jobs",
|
|
28
|
+
"url": "**/api/jobs?limit=10",
|
|
29
|
+
"method": "GET",
|
|
30
|
+
"status": 200,
|
|
31
|
+
"content_type": "application/json",
|
|
32
|
+
"required_hit_count": 3,
|
|
33
|
+
"json": {
|
|
34
|
+
"jobs": [
|
|
35
|
+
{
|
|
36
|
+
"id": "job_action_template_survives",
|
|
37
|
+
"status": "completed"
|
|
38
|
+
}
|
|
39
|
+
]
|
|
40
|
+
}
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"label": "existing-api-keys",
|
|
44
|
+
"url": "**/api/api-keys",
|
|
45
|
+
"method": "GET",
|
|
46
|
+
"status": 200,
|
|
47
|
+
"content_type": "application/json",
|
|
48
|
+
"required_hit_count": 3,
|
|
49
|
+
"json": {
|
|
50
|
+
"keys": [
|
|
51
|
+
{
|
|
52
|
+
"id": "key_action_template_existing",
|
|
53
|
+
"name": "Existing action template key",
|
|
54
|
+
"last4": "0001",
|
|
55
|
+
"status": "active"
|
|
56
|
+
}
|
|
57
|
+
]
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
"label": "create-api-key-malformed-success",
|
|
62
|
+
"url": "**/api/api-keys",
|
|
63
|
+
"method": "POST",
|
|
64
|
+
"status": 200,
|
|
65
|
+
"content_type": "application/json",
|
|
66
|
+
"required_hit_count": 3,
|
|
67
|
+
"max_hit_count": 3,
|
|
68
|
+
"capture_request_body": true,
|
|
69
|
+
"request_body_contains": ["Action template malformed success key"],
|
|
70
|
+
"body": "{not valid create success json"
|
|
71
|
+
}
|
|
72
|
+
],
|
|
73
|
+
"setup_actions": [
|
|
74
|
+
{ "type": "clear_storage", "storage": "both", "reload": true },
|
|
75
|
+
{ "type": "wait_for_selector", "selector": "[data-testid='account-page']", "timeout_ms": 30000 },
|
|
76
|
+
{ "type": "wait_for_text", "selector": "body", "text": "4h 0m", "timeout_ms": 30000 },
|
|
77
|
+
{ "type": "wait_for_text", "selector": "body", "text": "job_action_template_survives", "timeout_ms": 30000 },
|
|
78
|
+
{ "type": "wait_for_text", "selector": "body", "text": "Existing action template key", "timeout_ms": 30000 },
|
|
79
|
+
{ "type": "fill", "selector": "[data-testid='new-key-name']", "value": "Action template malformed success key" },
|
|
80
|
+
{ "type": "clear_console" },
|
|
81
|
+
{ "type": "screenshot", "label": "before-malformed-success-action" },
|
|
82
|
+
{ "type": "click", "selector": "[data-testid='create-key-button']", "text": "Create API key" },
|
|
83
|
+
{ "type": "wait_for_text", "selector": "body", "text": "Failed to create API key", "timeout_ms": 30000 },
|
|
84
|
+
{ "type": "assert_text_visible", "selector": "body", "text": "Existing action template key", "timeout_ms": 5000 },
|
|
85
|
+
{ "type": "assert_text_visible", "selector": "body", "text": "Active", "timeout_ms": 5000 },
|
|
86
|
+
{ "type": "assert_text_absent", "selector": "body", "text": "API Key Created!", "timeout_ms": 1000 },
|
|
87
|
+
{ "type": "assert_text_absent", "selector": "body", "text": "Expected property name", "timeout_ms": 1000 },
|
|
88
|
+
{ "type": "assert_text_absent", "selector": "body", "text": "SyntaxError", "timeout_ms": 1000 },
|
|
89
|
+
{ "type": "assert_text_absent", "selector": "body", "text": "[object Object]", "timeout_ms": 1000 },
|
|
90
|
+
{ "type": "screenshot", "label": "malformed-success-action-visible-recovery" }
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
"checks": [
|
|
94
|
+
{ "type": "route_loaded", "expected_path": "/account" },
|
|
95
|
+
{ "type": "selector_visible", "selector": "[data-testid='account-page']" },
|
|
96
|
+
{ "type": "selector_visible", "selector": "[data-testid='api-key-create-error']" },
|
|
97
|
+
{ "type": "text_visible", "text": "4h 0m" },
|
|
98
|
+
{ "type": "text_visible", "text": "2 active" },
|
|
99
|
+
{ "type": "text_visible", "text": "job_action_template_survives" },
|
|
100
|
+
{ "type": "text_visible", "text": "Existing action template key" },
|
|
101
|
+
{ "type": "text_visible", "text": "Failed to create API key" },
|
|
102
|
+
{ "type": "text_visible", "text": "Active" },
|
|
103
|
+
{ "type": "text_absent", "text": "API Key Created!" },
|
|
104
|
+
{ "type": "text_absent", "text": "Expected property name" },
|
|
105
|
+
{ "type": "text_absent", "text": "SyntaxError" },
|
|
106
|
+
{ "type": "text_absent", "text": "[object Object]" },
|
|
107
|
+
{ "type": "text_absent", "text": "Application error" },
|
|
108
|
+
{ "type": "selector_count_equals", "selector": "[data-testid='api-key-create-error']", "expected_count": 1 },
|
|
109
|
+
{ "type": "selector_count_equals", "selector": "[data-testid='recent-job-row']", "expected_count": 1 },
|
|
110
|
+
{ "type": "selector_count_equals", "selector": "[data-testid='api-key-row']", "expected_count": 1 },
|
|
111
|
+
{ "type": "selector_count_equals", "selector": "[data-testid='created-key-modal']", "expected_count": 0 },
|
|
112
|
+
{ "type": "no_horizontal_overflow", "max_overflow_px": 1 },
|
|
113
|
+
{ "type": "no_fatal_console_errors" },
|
|
114
|
+
{ "type": "no_console_warnings" }
|
|
115
|
+
],
|
|
116
|
+
"artifacts": ["screenshot", "console", "dom_summary", "proof_json"],
|
|
117
|
+
"baseline_policy": "invariant_only",
|
|
118
|
+
"failure_policy": {
|
|
119
|
+
"environment_blocked": "neutral",
|
|
120
|
+
"proof_insufficient": "fail",
|
|
121
|
+
"product_regression": "fail"
|
|
122
|
+
},
|
|
123
|
+
"metadata": {
|
|
124
|
+
"purpose": "Template for handled malformed action-success recovery: prove surrounding state still renders, the failed action shows one recovery message, success UI and raw parser text stay absent, the action request body is captured, and browser console evidence remains clean."
|
|
125
|
+
}
|
|
126
|
+
}
|