@riddledc/riddle-proof 0.7.45 → 0.7.47
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 +9 -5
- package/dist/{chunk-IJGMTTVP.js → chunk-NJDY7HYE.js} +96 -24
- package/dist/cli.cjs +96 -24
- package/dist/cli.js +1 -1
- package/dist/index.cjs +96 -24
- package/dist/index.js +1 -1
- package/dist/profile.cjs +96 -24
- package/dist/profile.d.cts +7 -0
- package/dist/profile.d.ts +7 -0
- package/dist/profile.js +1 -1
- package/dist/proof-run-engine.d.cts +3 -3
- package/dist/proof-run-engine.d.ts +3 -3
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -224,11 +224,15 @@ success pair across multiple viewports. Repeated sequences also record
|
|
|
224
224
|
`sequence_cycle: true` after the first cycle.
|
|
225
225
|
|
|
226
226
|
Set `capture_request_body: true` to include compact request-body evidence on
|
|
227
|
-
mock hits. Add `request_body_contains`
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
227
|
+
mock hits. Add `request_body_contains` / `request_body_patterns` or
|
|
228
|
+
`request_body_not_contains` / `request_body_not_patterns` when the request body
|
|
229
|
+
is part of the contract, such as proving that a save request references the
|
|
230
|
+
current build ID returned by a prior mocked build response and not a stale one.
|
|
231
|
+
Body assertions use the full request body for matching and store only length
|
|
232
|
+
plus a compact sample in the proof evidence. For sequenced mocks, the same
|
|
233
|
+
request-body fields may also be placed on individual `responses[]` entries when
|
|
234
|
+
each step has a different request contract, such as a fail-then-success retry
|
|
235
|
+
where the second request must carry newer state.
|
|
232
236
|
|
|
233
237
|
`target.setup_actions` is optional. Use it when the meaningful proof surface
|
|
234
238
|
appears only after a picker, tab, login stub, storage seed, form fill,
|
|
@@ -253,15 +253,7 @@ function normalizeNetworkMock(input, index) {
|
|
|
253
253
|
const payload = normalizeNetworkMockResponsePayload(input, `target.network_mocks[${index}]`);
|
|
254
254
|
const responsesInput = input.responses ?? input.sequence;
|
|
255
255
|
const responses = normalizeNetworkMockResponses(responsesInput, index, payload);
|
|
256
|
-
const
|
|
257
|
-
input.request_body_contains ?? input.requestBodyContains ?? input.body_contains ?? input.bodyContains,
|
|
258
|
-
`target.network_mocks[${index}].request_body_contains`
|
|
259
|
-
);
|
|
260
|
-
const requestBodyPatterns = normalizeStringList(
|
|
261
|
-
input.request_body_patterns ?? input.requestBodyPatterns ?? input.body_patterns ?? input.bodyPatterns,
|
|
262
|
-
`target.network_mocks[${index}].request_body_patterns`
|
|
263
|
-
);
|
|
264
|
-
validateRegexPatterns(requestBodyPatterns, `target.network_mocks[${index}].request_body_patterns`);
|
|
256
|
+
const requestBody = normalizeNetworkMockRequestBodyConstraints(input, `target.network_mocks[${index}]`);
|
|
265
257
|
const requiredHitCount = numberValue(
|
|
266
258
|
input.required_hit_count ?? input.requiredHitCount ?? input.required_hits ?? input.requiredHits ?? input.min_hits ?? input.minHits
|
|
267
259
|
);
|
|
@@ -277,9 +269,38 @@ function normalizeNetworkMock(input, index) {
|
|
|
277
269
|
repeat_responses: input.repeat_responses === true || input.repeatResponses === true || input.cycle_responses === true || input.cycleResponses === true,
|
|
278
270
|
required_hit_count: requiredHitCount,
|
|
279
271
|
required: input.required === false ? false : true,
|
|
280
|
-
capture_request_body:
|
|
272
|
+
capture_request_body: requestBody.capture_request_body,
|
|
273
|
+
request_body_contains: requestBody.request_body_contains,
|
|
274
|
+
request_body_patterns: requestBody.request_body_patterns,
|
|
275
|
+
request_body_not_contains: requestBody.request_body_not_contains,
|
|
276
|
+
request_body_not_patterns: requestBody.request_body_not_patterns
|
|
277
|
+
};
|
|
278
|
+
}
|
|
279
|
+
function normalizeNetworkMockRequestBodyConstraints(input, label) {
|
|
280
|
+
const requestBodyContains = normalizeStringList(
|
|
281
|
+
input.request_body_contains ?? input.requestBodyContains ?? input.body_contains ?? input.bodyContains,
|
|
282
|
+
`${label}.request_body_contains`
|
|
283
|
+
);
|
|
284
|
+
const requestBodyPatterns = normalizeStringList(
|
|
285
|
+
input.request_body_patterns ?? input.requestBodyPatterns ?? input.body_patterns ?? input.bodyPatterns,
|
|
286
|
+
`${label}.request_body_patterns`
|
|
287
|
+
);
|
|
288
|
+
validateRegexPatterns(requestBodyPatterns, `${label}.request_body_patterns`);
|
|
289
|
+
const requestBodyNotContains = normalizeStringList(
|
|
290
|
+
input.request_body_not_contains ?? input.requestBodyNotContains ?? input.request_body_absent ?? input.requestBodyAbsent ?? input.body_not_contains ?? input.bodyNotContains ?? input.body_absent ?? input.bodyAbsent,
|
|
291
|
+
`${label}.request_body_not_contains`
|
|
292
|
+
);
|
|
293
|
+
const requestBodyNotPatterns = normalizeStringList(
|
|
294
|
+
input.request_body_not_patterns ?? input.requestBodyNotPatterns ?? input.request_body_forbidden_patterns ?? input.requestBodyForbiddenPatterns ?? input.body_not_patterns ?? input.bodyNotPatterns ?? input.body_forbidden_patterns ?? input.bodyForbiddenPatterns,
|
|
295
|
+
`${label}.request_body_not_patterns`
|
|
296
|
+
);
|
|
297
|
+
validateRegexPatterns(requestBodyNotPatterns, `${label}.request_body_not_patterns`);
|
|
298
|
+
return {
|
|
299
|
+
capture_request_body: input.capture_request_body === true || input.captureRequestBody === true || Boolean(requestBodyContains?.length) || Boolean(requestBodyPatterns?.length) || Boolean(requestBodyNotContains?.length) || Boolean(requestBodyNotPatterns?.length),
|
|
281
300
|
request_body_contains: requestBodyContains,
|
|
282
|
-
request_body_patterns: requestBodyPatterns
|
|
301
|
+
request_body_patterns: requestBodyPatterns,
|
|
302
|
+
request_body_not_contains: requestBodyNotContains,
|
|
303
|
+
request_body_not_patterns: requestBodyNotPatterns
|
|
283
304
|
};
|
|
284
305
|
}
|
|
285
306
|
function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
@@ -289,20 +310,33 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
|
289
310
|
}
|
|
290
311
|
const body = stringValue(input.body) ?? stringValue(input.body_text) ?? stringValue(input.bodyText) ?? defaults.body;
|
|
291
312
|
const hasJsonBody = Object.prototype.hasOwnProperty.call(input, "body_json") || Object.prototype.hasOwnProperty.call(input, "bodyJson") || Object.prototype.hasOwnProperty.call(input, "json");
|
|
313
|
+
const requestBody = normalizeNetworkMockRequestBodyConstraints(input, label);
|
|
292
314
|
return {
|
|
293
315
|
label: stringValue(input.label) || stringValue(input.name) || defaults.label,
|
|
294
316
|
status,
|
|
295
317
|
content_type: stringValue(input.content_type) || stringValue(input.contentType) || defaults.content_type,
|
|
296
318
|
headers: stringRecord(input.headers) || defaults.headers,
|
|
297
319
|
body,
|
|
298
|
-
body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json
|
|
320
|
+
body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json,
|
|
321
|
+
capture_request_body: requestBody.capture_request_body,
|
|
322
|
+
request_body_contains: requestBody.request_body_contains,
|
|
323
|
+
request_body_patterns: requestBody.request_body_patterns,
|
|
324
|
+
request_body_not_contains: requestBody.request_body_not_contains,
|
|
325
|
+
request_body_not_patterns: requestBody.request_body_not_patterns
|
|
299
326
|
};
|
|
300
327
|
}
|
|
301
328
|
function normalizeNetworkMockResponses(value, mockIndex, defaults) {
|
|
302
329
|
if (value === void 0) return void 0;
|
|
303
330
|
if (!Array.isArray(value)) throw new Error(`target.network_mocks[${mockIndex}].responses must be an array.`);
|
|
304
331
|
if (!value.length) throw new Error(`target.network_mocks[${mockIndex}].responses must not be empty.`);
|
|
305
|
-
const responseDefaults = {
|
|
332
|
+
const responseDefaults = {
|
|
333
|
+
label: void 0,
|
|
334
|
+
status: defaults.status,
|
|
335
|
+
content_type: defaults.content_type,
|
|
336
|
+
headers: defaults.headers,
|
|
337
|
+
body: defaults.body,
|
|
338
|
+
body_json: defaults.body_json
|
|
339
|
+
};
|
|
306
340
|
return value.map((response, responseIndex) => {
|
|
307
341
|
if (!isRecord(response)) {
|
|
308
342
|
throw new Error(`target.network_mocks[${mockIndex}].responses[${responseIndex}] must be an object.`);
|
|
@@ -1045,6 +1079,9 @@ function assessNetworkMocksFromEvidence(profile, evidence) {
|
|
|
1045
1079
|
if (event.request_body_matches === false) {
|
|
1046
1080
|
failed.push({
|
|
1047
1081
|
label: event.label ?? null,
|
|
1082
|
+
response_label: event.response_label ?? null,
|
|
1083
|
+
hit_index: event.hit_index ?? null,
|
|
1084
|
+
response_index: event.response_index ?? null,
|
|
1048
1085
|
url: event.url ?? null,
|
|
1049
1086
|
method: event.method ?? null,
|
|
1050
1087
|
reason: "request_body_mismatch",
|
|
@@ -1428,6 +1465,9 @@ function assessProfile(profile, evidence) {
|
|
|
1428
1465
|
if (event && event.request_body_matches === false) {
|
|
1429
1466
|
failed.push({
|
|
1430
1467
|
label: event.label || null,
|
|
1468
|
+
response_label: event.response_label || null,
|
|
1469
|
+
hit_index: event.hit_index ?? null,
|
|
1470
|
+
response_index: event.response_index ?? null,
|
|
1431
1471
|
url: event.url || null,
|
|
1432
1472
|
method: event.method || null,
|
|
1433
1473
|
reason: "request_body_mismatch",
|
|
@@ -1892,18 +1932,21 @@ function compactNetworkMockRequestBody(value) {
|
|
|
1892
1932
|
function networkMockStringList(value) {
|
|
1893
1933
|
return Array.isArray(value) ? value.map((item) => String(item)).filter(Boolean) : [];
|
|
1894
1934
|
}
|
|
1895
|
-
function networkMockShouldCaptureRequestBody(
|
|
1896
|
-
return
|
|
1897
|
-
|
|
1898
|
-
|| networkMockStringList(
|
|
1899
|
-
|| networkMockStringList(
|
|
1900
|
-
|
|
1935
|
+
function networkMockShouldCaptureRequestBody(...sources) {
|
|
1936
|
+
return sources.some((source) => source && (
|
|
1937
|
+
source.capture_request_body === true
|
|
1938
|
+
|| networkMockStringList(source.request_body_contains).length > 0
|
|
1939
|
+
|| networkMockStringList(source.request_body_patterns).length > 0
|
|
1940
|
+
|| networkMockStringList(source.request_body_not_contains).length > 0
|
|
1941
|
+
|| networkMockStringList(source.request_body_not_patterns).length > 0
|
|
1942
|
+
));
|
|
1901
1943
|
}
|
|
1902
|
-
function
|
|
1944
|
+
function networkMockRequestBodyFailuresForSource(body, source) {
|
|
1903
1945
|
const failures = [];
|
|
1946
|
+
if (!source) return failures;
|
|
1904
1947
|
const rawBody = String(body || "");
|
|
1905
1948
|
const compactBody = compactNetworkMockRequestBody(rawBody);
|
|
1906
|
-
for (const expected of networkMockStringList(
|
|
1949
|
+
for (const expected of networkMockStringList(source.request_body_contains)) {
|
|
1907
1950
|
if (!rawBody.includes(expected) && !compactBody.includes(expected)) {
|
|
1908
1951
|
failures.push({
|
|
1909
1952
|
type: "request_body_missing_text",
|
|
@@ -1911,7 +1954,7 @@ function networkMockRequestBodyFailures(body, mock) {
|
|
|
1911
1954
|
});
|
|
1912
1955
|
}
|
|
1913
1956
|
}
|
|
1914
|
-
for (const pattern of networkMockStringList(
|
|
1957
|
+
for (const pattern of networkMockStringList(source.request_body_patterns)) {
|
|
1915
1958
|
try {
|
|
1916
1959
|
const regex = new RegExp(pattern);
|
|
1917
1960
|
if (!regex.test(rawBody) && !regex.test(compactBody)) {
|
|
@@ -1928,8 +1971,36 @@ function networkMockRequestBodyFailures(body, mock) {
|
|
|
1928
1971
|
});
|
|
1929
1972
|
}
|
|
1930
1973
|
}
|
|
1974
|
+
for (const forbidden of networkMockStringList(source.request_body_not_contains)) {
|
|
1975
|
+
if (rawBody.includes(forbidden) || compactBody.includes(forbidden)) {
|
|
1976
|
+
failures.push({
|
|
1977
|
+
type: "request_body_forbidden_text",
|
|
1978
|
+
text: String(forbidden).slice(0, 200),
|
|
1979
|
+
});
|
|
1980
|
+
}
|
|
1981
|
+
}
|
|
1982
|
+
for (const pattern of networkMockStringList(source.request_body_not_patterns)) {
|
|
1983
|
+
try {
|
|
1984
|
+
const regex = new RegExp(pattern);
|
|
1985
|
+
if (regex.test(rawBody) || regex.test(compactBody)) {
|
|
1986
|
+
failures.push({
|
|
1987
|
+
type: "request_body_forbidden_pattern_matched",
|
|
1988
|
+
pattern: String(pattern).slice(0, 200),
|
|
1989
|
+
});
|
|
1990
|
+
}
|
|
1991
|
+
} catch (error) {
|
|
1992
|
+
failures.push({
|
|
1993
|
+
type: "request_body_invalid_pattern",
|
|
1994
|
+
pattern: String(pattern).slice(0, 200),
|
|
1995
|
+
error: String(error && error.message ? error.message : error).slice(0, 500),
|
|
1996
|
+
});
|
|
1997
|
+
}
|
|
1998
|
+
}
|
|
1931
1999
|
return failures;
|
|
1932
2000
|
}
|
|
2001
|
+
function networkMockRequestBodyFailures(body, ...sources) {
|
|
2002
|
+
return sources.flatMap((source) => networkMockRequestBodyFailuresForSource(body, source));
|
|
2003
|
+
}
|
|
1933
2004
|
async function setupLocatorVisible(locator, index) {
|
|
1934
2005
|
return await locator.nth(index).isVisible({ timeout: 1000 }).catch(() => false);
|
|
1935
2006
|
}
|
|
@@ -1958,9 +2029,10 @@ async function registerNetworkMocks(mocks) {
|
|
|
1958
2029
|
body = JSON.stringify(response.body_json);
|
|
1959
2030
|
contentType = response.content_type || headers["content-type"] || headers["Content-Type"] || "application/json";
|
|
1960
2031
|
}
|
|
1961
|
-
const
|
|
2032
|
+
const responseBodyContract = responseIndex === null ? null : response;
|
|
2033
|
+
const shouldCaptureRequestBody = networkMockShouldCaptureRequestBody(mock, responseBodyContract);
|
|
1962
2034
|
const requestBody = shouldCaptureRequestBody && request.postData ? request.postData() || "" : "";
|
|
1963
|
-
const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock) : [];
|
|
2035
|
+
const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock, responseBodyContract) : [];
|
|
1964
2036
|
const status = response.status || mock.status || 200;
|
|
1965
2037
|
const event = {
|
|
1966
2038
|
ok: true,
|
package/dist/cli.cjs
CHANGED
|
@@ -7126,15 +7126,7 @@ function normalizeNetworkMock(input, index) {
|
|
|
7126
7126
|
const payload = normalizeNetworkMockResponsePayload(input, `target.network_mocks[${index}]`);
|
|
7127
7127
|
const responsesInput = input.responses ?? input.sequence;
|
|
7128
7128
|
const responses = normalizeNetworkMockResponses(responsesInput, index, payload);
|
|
7129
|
-
const
|
|
7130
|
-
input.request_body_contains ?? input.requestBodyContains ?? input.body_contains ?? input.bodyContains,
|
|
7131
|
-
`target.network_mocks[${index}].request_body_contains`
|
|
7132
|
-
);
|
|
7133
|
-
const requestBodyPatterns = normalizeStringList(
|
|
7134
|
-
input.request_body_patterns ?? input.requestBodyPatterns ?? input.body_patterns ?? input.bodyPatterns,
|
|
7135
|
-
`target.network_mocks[${index}].request_body_patterns`
|
|
7136
|
-
);
|
|
7137
|
-
validateRegexPatterns(requestBodyPatterns, `target.network_mocks[${index}].request_body_patterns`);
|
|
7129
|
+
const requestBody = normalizeNetworkMockRequestBodyConstraints(input, `target.network_mocks[${index}]`);
|
|
7138
7130
|
const requiredHitCount = numberValue(
|
|
7139
7131
|
input.required_hit_count ?? input.requiredHitCount ?? input.required_hits ?? input.requiredHits ?? input.min_hits ?? input.minHits
|
|
7140
7132
|
);
|
|
@@ -7150,9 +7142,38 @@ function normalizeNetworkMock(input, index) {
|
|
|
7150
7142
|
repeat_responses: input.repeat_responses === true || input.repeatResponses === true || input.cycle_responses === true || input.cycleResponses === true,
|
|
7151
7143
|
required_hit_count: requiredHitCount,
|
|
7152
7144
|
required: input.required === false ? false : true,
|
|
7153
|
-
capture_request_body:
|
|
7145
|
+
capture_request_body: requestBody.capture_request_body,
|
|
7146
|
+
request_body_contains: requestBody.request_body_contains,
|
|
7147
|
+
request_body_patterns: requestBody.request_body_patterns,
|
|
7148
|
+
request_body_not_contains: requestBody.request_body_not_contains,
|
|
7149
|
+
request_body_not_patterns: requestBody.request_body_not_patterns
|
|
7150
|
+
};
|
|
7151
|
+
}
|
|
7152
|
+
function normalizeNetworkMockRequestBodyConstraints(input, label) {
|
|
7153
|
+
const requestBodyContains = normalizeStringList(
|
|
7154
|
+
input.request_body_contains ?? input.requestBodyContains ?? input.body_contains ?? input.bodyContains,
|
|
7155
|
+
`${label}.request_body_contains`
|
|
7156
|
+
);
|
|
7157
|
+
const requestBodyPatterns = normalizeStringList(
|
|
7158
|
+
input.request_body_patterns ?? input.requestBodyPatterns ?? input.body_patterns ?? input.bodyPatterns,
|
|
7159
|
+
`${label}.request_body_patterns`
|
|
7160
|
+
);
|
|
7161
|
+
validateRegexPatterns(requestBodyPatterns, `${label}.request_body_patterns`);
|
|
7162
|
+
const requestBodyNotContains = normalizeStringList(
|
|
7163
|
+
input.request_body_not_contains ?? input.requestBodyNotContains ?? input.request_body_absent ?? input.requestBodyAbsent ?? input.body_not_contains ?? input.bodyNotContains ?? input.body_absent ?? input.bodyAbsent,
|
|
7164
|
+
`${label}.request_body_not_contains`
|
|
7165
|
+
);
|
|
7166
|
+
const requestBodyNotPatterns = normalizeStringList(
|
|
7167
|
+
input.request_body_not_patterns ?? input.requestBodyNotPatterns ?? input.request_body_forbidden_patterns ?? input.requestBodyForbiddenPatterns ?? input.body_not_patterns ?? input.bodyNotPatterns ?? input.body_forbidden_patterns ?? input.bodyForbiddenPatterns,
|
|
7168
|
+
`${label}.request_body_not_patterns`
|
|
7169
|
+
);
|
|
7170
|
+
validateRegexPatterns(requestBodyNotPatterns, `${label}.request_body_not_patterns`);
|
|
7171
|
+
return {
|
|
7172
|
+
capture_request_body: input.capture_request_body === true || input.captureRequestBody === true || Boolean(requestBodyContains?.length) || Boolean(requestBodyPatterns?.length) || Boolean(requestBodyNotContains?.length) || Boolean(requestBodyNotPatterns?.length),
|
|
7154
7173
|
request_body_contains: requestBodyContains,
|
|
7155
|
-
request_body_patterns: requestBodyPatterns
|
|
7174
|
+
request_body_patterns: requestBodyPatterns,
|
|
7175
|
+
request_body_not_contains: requestBodyNotContains,
|
|
7176
|
+
request_body_not_patterns: requestBodyNotPatterns
|
|
7156
7177
|
};
|
|
7157
7178
|
}
|
|
7158
7179
|
function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
@@ -7162,20 +7183,33 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
|
7162
7183
|
}
|
|
7163
7184
|
const body = stringValue2(input.body) ?? stringValue2(input.body_text) ?? stringValue2(input.bodyText) ?? defaults.body;
|
|
7164
7185
|
const hasJsonBody = Object.prototype.hasOwnProperty.call(input, "body_json") || Object.prototype.hasOwnProperty.call(input, "bodyJson") || Object.prototype.hasOwnProperty.call(input, "json");
|
|
7186
|
+
const requestBody = normalizeNetworkMockRequestBodyConstraints(input, label);
|
|
7165
7187
|
return {
|
|
7166
7188
|
label: stringValue2(input.label) || stringValue2(input.name) || defaults.label,
|
|
7167
7189
|
status,
|
|
7168
7190
|
content_type: stringValue2(input.content_type) || stringValue2(input.contentType) || defaults.content_type,
|
|
7169
7191
|
headers: stringRecord(input.headers) || defaults.headers,
|
|
7170
7192
|
body,
|
|
7171
|
-
body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json
|
|
7193
|
+
body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json,
|
|
7194
|
+
capture_request_body: requestBody.capture_request_body,
|
|
7195
|
+
request_body_contains: requestBody.request_body_contains,
|
|
7196
|
+
request_body_patterns: requestBody.request_body_patterns,
|
|
7197
|
+
request_body_not_contains: requestBody.request_body_not_contains,
|
|
7198
|
+
request_body_not_patterns: requestBody.request_body_not_patterns
|
|
7172
7199
|
};
|
|
7173
7200
|
}
|
|
7174
7201
|
function normalizeNetworkMockResponses(value, mockIndex, defaults) {
|
|
7175
7202
|
if (value === void 0) return void 0;
|
|
7176
7203
|
if (!Array.isArray(value)) throw new Error(`target.network_mocks[${mockIndex}].responses must be an array.`);
|
|
7177
7204
|
if (!value.length) throw new Error(`target.network_mocks[${mockIndex}].responses must not be empty.`);
|
|
7178
|
-
const responseDefaults = {
|
|
7205
|
+
const responseDefaults = {
|
|
7206
|
+
label: void 0,
|
|
7207
|
+
status: defaults.status,
|
|
7208
|
+
content_type: defaults.content_type,
|
|
7209
|
+
headers: defaults.headers,
|
|
7210
|
+
body: defaults.body,
|
|
7211
|
+
body_json: defaults.body_json
|
|
7212
|
+
};
|
|
7179
7213
|
return value.map((response, responseIndex) => {
|
|
7180
7214
|
if (!isRecord(response)) {
|
|
7181
7215
|
throw new Error(`target.network_mocks[${mockIndex}].responses[${responseIndex}] must be an object.`);
|
|
@@ -7918,6 +7952,9 @@ function assessNetworkMocksFromEvidence(profile, evidence) {
|
|
|
7918
7952
|
if (event.request_body_matches === false) {
|
|
7919
7953
|
failed.push({
|
|
7920
7954
|
label: event.label ?? null,
|
|
7955
|
+
response_label: event.response_label ?? null,
|
|
7956
|
+
hit_index: event.hit_index ?? null,
|
|
7957
|
+
response_index: event.response_index ?? null,
|
|
7921
7958
|
url: event.url ?? null,
|
|
7922
7959
|
method: event.method ?? null,
|
|
7923
7960
|
reason: "request_body_mismatch",
|
|
@@ -8285,6 +8322,9 @@ function assessProfile(profile, evidence) {
|
|
|
8285
8322
|
if (event && event.request_body_matches === false) {
|
|
8286
8323
|
failed.push({
|
|
8287
8324
|
label: event.label || null,
|
|
8325
|
+
response_label: event.response_label || null,
|
|
8326
|
+
hit_index: event.hit_index ?? null,
|
|
8327
|
+
response_index: event.response_index ?? null,
|
|
8288
8328
|
url: event.url || null,
|
|
8289
8329
|
method: event.method || null,
|
|
8290
8330
|
reason: "request_body_mismatch",
|
|
@@ -8749,18 +8789,21 @@ function compactNetworkMockRequestBody(value) {
|
|
|
8749
8789
|
function networkMockStringList(value) {
|
|
8750
8790
|
return Array.isArray(value) ? value.map((item) => String(item)).filter(Boolean) : [];
|
|
8751
8791
|
}
|
|
8752
|
-
function networkMockShouldCaptureRequestBody(
|
|
8753
|
-
return
|
|
8754
|
-
|
|
8755
|
-
|| networkMockStringList(
|
|
8756
|
-
|| networkMockStringList(
|
|
8757
|
-
|
|
8792
|
+
function networkMockShouldCaptureRequestBody(...sources) {
|
|
8793
|
+
return sources.some((source) => source && (
|
|
8794
|
+
source.capture_request_body === true
|
|
8795
|
+
|| networkMockStringList(source.request_body_contains).length > 0
|
|
8796
|
+
|| networkMockStringList(source.request_body_patterns).length > 0
|
|
8797
|
+
|| networkMockStringList(source.request_body_not_contains).length > 0
|
|
8798
|
+
|| networkMockStringList(source.request_body_not_patterns).length > 0
|
|
8799
|
+
));
|
|
8758
8800
|
}
|
|
8759
|
-
function
|
|
8801
|
+
function networkMockRequestBodyFailuresForSource(body, source) {
|
|
8760
8802
|
const failures = [];
|
|
8803
|
+
if (!source) return failures;
|
|
8761
8804
|
const rawBody = String(body || "");
|
|
8762
8805
|
const compactBody = compactNetworkMockRequestBody(rawBody);
|
|
8763
|
-
for (const expected of networkMockStringList(
|
|
8806
|
+
for (const expected of networkMockStringList(source.request_body_contains)) {
|
|
8764
8807
|
if (!rawBody.includes(expected) && !compactBody.includes(expected)) {
|
|
8765
8808
|
failures.push({
|
|
8766
8809
|
type: "request_body_missing_text",
|
|
@@ -8768,7 +8811,7 @@ function networkMockRequestBodyFailures(body, mock) {
|
|
|
8768
8811
|
});
|
|
8769
8812
|
}
|
|
8770
8813
|
}
|
|
8771
|
-
for (const pattern of networkMockStringList(
|
|
8814
|
+
for (const pattern of networkMockStringList(source.request_body_patterns)) {
|
|
8772
8815
|
try {
|
|
8773
8816
|
const regex = new RegExp(pattern);
|
|
8774
8817
|
if (!regex.test(rawBody) && !regex.test(compactBody)) {
|
|
@@ -8785,8 +8828,36 @@ function networkMockRequestBodyFailures(body, mock) {
|
|
|
8785
8828
|
});
|
|
8786
8829
|
}
|
|
8787
8830
|
}
|
|
8831
|
+
for (const forbidden of networkMockStringList(source.request_body_not_contains)) {
|
|
8832
|
+
if (rawBody.includes(forbidden) || compactBody.includes(forbidden)) {
|
|
8833
|
+
failures.push({
|
|
8834
|
+
type: "request_body_forbidden_text",
|
|
8835
|
+
text: String(forbidden).slice(0, 200),
|
|
8836
|
+
});
|
|
8837
|
+
}
|
|
8838
|
+
}
|
|
8839
|
+
for (const pattern of networkMockStringList(source.request_body_not_patterns)) {
|
|
8840
|
+
try {
|
|
8841
|
+
const regex = new RegExp(pattern);
|
|
8842
|
+
if (regex.test(rawBody) || regex.test(compactBody)) {
|
|
8843
|
+
failures.push({
|
|
8844
|
+
type: "request_body_forbidden_pattern_matched",
|
|
8845
|
+
pattern: String(pattern).slice(0, 200),
|
|
8846
|
+
});
|
|
8847
|
+
}
|
|
8848
|
+
} catch (error) {
|
|
8849
|
+
failures.push({
|
|
8850
|
+
type: "request_body_invalid_pattern",
|
|
8851
|
+
pattern: String(pattern).slice(0, 200),
|
|
8852
|
+
error: String(error && error.message ? error.message : error).slice(0, 500),
|
|
8853
|
+
});
|
|
8854
|
+
}
|
|
8855
|
+
}
|
|
8788
8856
|
return failures;
|
|
8789
8857
|
}
|
|
8858
|
+
function networkMockRequestBodyFailures(body, ...sources) {
|
|
8859
|
+
return sources.flatMap((source) => networkMockRequestBodyFailuresForSource(body, source));
|
|
8860
|
+
}
|
|
8790
8861
|
async function setupLocatorVisible(locator, index) {
|
|
8791
8862
|
return await locator.nth(index).isVisible({ timeout: 1000 }).catch(() => false);
|
|
8792
8863
|
}
|
|
@@ -8815,9 +8886,10 @@ async function registerNetworkMocks(mocks) {
|
|
|
8815
8886
|
body = JSON.stringify(response.body_json);
|
|
8816
8887
|
contentType = response.content_type || headers["content-type"] || headers["Content-Type"] || "application/json";
|
|
8817
8888
|
}
|
|
8818
|
-
const
|
|
8889
|
+
const responseBodyContract = responseIndex === null ? null : response;
|
|
8890
|
+
const shouldCaptureRequestBody = networkMockShouldCaptureRequestBody(mock, responseBodyContract);
|
|
8819
8891
|
const requestBody = shouldCaptureRequestBody && request.postData ? request.postData() || "" : "";
|
|
8820
|
-
const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock) : [];
|
|
8892
|
+
const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock, responseBodyContract) : [];
|
|
8821
8893
|
const status = response.status || mock.status || 200;
|
|
8822
8894
|
const event = {
|
|
8823
8895
|
ok: true,
|
package/dist/cli.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -8967,15 +8967,7 @@ function normalizeNetworkMock(input, index) {
|
|
|
8967
8967
|
const payload = normalizeNetworkMockResponsePayload(input, `target.network_mocks[${index}]`);
|
|
8968
8968
|
const responsesInput = input.responses ?? input.sequence;
|
|
8969
8969
|
const responses = normalizeNetworkMockResponses(responsesInput, index, payload);
|
|
8970
|
-
const
|
|
8971
|
-
input.request_body_contains ?? input.requestBodyContains ?? input.body_contains ?? input.bodyContains,
|
|
8972
|
-
`target.network_mocks[${index}].request_body_contains`
|
|
8973
|
-
);
|
|
8974
|
-
const requestBodyPatterns = normalizeStringList(
|
|
8975
|
-
input.request_body_patterns ?? input.requestBodyPatterns ?? input.body_patterns ?? input.bodyPatterns,
|
|
8976
|
-
`target.network_mocks[${index}].request_body_patterns`
|
|
8977
|
-
);
|
|
8978
|
-
validateRegexPatterns(requestBodyPatterns, `target.network_mocks[${index}].request_body_patterns`);
|
|
8970
|
+
const requestBody = normalizeNetworkMockRequestBodyConstraints(input, `target.network_mocks[${index}]`);
|
|
8979
8971
|
const requiredHitCount = numberValue3(
|
|
8980
8972
|
input.required_hit_count ?? input.requiredHitCount ?? input.required_hits ?? input.requiredHits ?? input.min_hits ?? input.minHits
|
|
8981
8973
|
);
|
|
@@ -8991,9 +8983,38 @@ function normalizeNetworkMock(input, index) {
|
|
|
8991
8983
|
repeat_responses: input.repeat_responses === true || input.repeatResponses === true || input.cycle_responses === true || input.cycleResponses === true,
|
|
8992
8984
|
required_hit_count: requiredHitCount,
|
|
8993
8985
|
required: input.required === false ? false : true,
|
|
8994
|
-
capture_request_body:
|
|
8986
|
+
capture_request_body: requestBody.capture_request_body,
|
|
8987
|
+
request_body_contains: requestBody.request_body_contains,
|
|
8988
|
+
request_body_patterns: requestBody.request_body_patterns,
|
|
8989
|
+
request_body_not_contains: requestBody.request_body_not_contains,
|
|
8990
|
+
request_body_not_patterns: requestBody.request_body_not_patterns
|
|
8991
|
+
};
|
|
8992
|
+
}
|
|
8993
|
+
function normalizeNetworkMockRequestBodyConstraints(input, label) {
|
|
8994
|
+
const requestBodyContains = normalizeStringList(
|
|
8995
|
+
input.request_body_contains ?? input.requestBodyContains ?? input.body_contains ?? input.bodyContains,
|
|
8996
|
+
`${label}.request_body_contains`
|
|
8997
|
+
);
|
|
8998
|
+
const requestBodyPatterns = normalizeStringList(
|
|
8999
|
+
input.request_body_patterns ?? input.requestBodyPatterns ?? input.body_patterns ?? input.bodyPatterns,
|
|
9000
|
+
`${label}.request_body_patterns`
|
|
9001
|
+
);
|
|
9002
|
+
validateRegexPatterns(requestBodyPatterns, `${label}.request_body_patterns`);
|
|
9003
|
+
const requestBodyNotContains = normalizeStringList(
|
|
9004
|
+
input.request_body_not_contains ?? input.requestBodyNotContains ?? input.request_body_absent ?? input.requestBodyAbsent ?? input.body_not_contains ?? input.bodyNotContains ?? input.body_absent ?? input.bodyAbsent,
|
|
9005
|
+
`${label}.request_body_not_contains`
|
|
9006
|
+
);
|
|
9007
|
+
const requestBodyNotPatterns = normalizeStringList(
|
|
9008
|
+
input.request_body_not_patterns ?? input.requestBodyNotPatterns ?? input.request_body_forbidden_patterns ?? input.requestBodyForbiddenPatterns ?? input.body_not_patterns ?? input.bodyNotPatterns ?? input.body_forbidden_patterns ?? input.bodyForbiddenPatterns,
|
|
9009
|
+
`${label}.request_body_not_patterns`
|
|
9010
|
+
);
|
|
9011
|
+
validateRegexPatterns(requestBodyNotPatterns, `${label}.request_body_not_patterns`);
|
|
9012
|
+
return {
|
|
9013
|
+
capture_request_body: input.capture_request_body === true || input.captureRequestBody === true || Boolean(requestBodyContains?.length) || Boolean(requestBodyPatterns?.length) || Boolean(requestBodyNotContains?.length) || Boolean(requestBodyNotPatterns?.length),
|
|
8995
9014
|
request_body_contains: requestBodyContains,
|
|
8996
|
-
request_body_patterns: requestBodyPatterns
|
|
9015
|
+
request_body_patterns: requestBodyPatterns,
|
|
9016
|
+
request_body_not_contains: requestBodyNotContains,
|
|
9017
|
+
request_body_not_patterns: requestBodyNotPatterns
|
|
8997
9018
|
};
|
|
8998
9019
|
}
|
|
8999
9020
|
function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
@@ -9003,20 +9024,33 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
|
9003
9024
|
}
|
|
9004
9025
|
const body = stringValue5(input.body) ?? stringValue5(input.body_text) ?? stringValue5(input.bodyText) ?? defaults.body;
|
|
9005
9026
|
const hasJsonBody = Object.prototype.hasOwnProperty.call(input, "body_json") || Object.prototype.hasOwnProperty.call(input, "bodyJson") || Object.prototype.hasOwnProperty.call(input, "json");
|
|
9027
|
+
const requestBody = normalizeNetworkMockRequestBodyConstraints(input, label);
|
|
9006
9028
|
return {
|
|
9007
9029
|
label: stringValue5(input.label) || stringValue5(input.name) || defaults.label,
|
|
9008
9030
|
status,
|
|
9009
9031
|
content_type: stringValue5(input.content_type) || stringValue5(input.contentType) || defaults.content_type,
|
|
9010
9032
|
headers: stringRecord(input.headers) || defaults.headers,
|
|
9011
9033
|
body,
|
|
9012
|
-
body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json
|
|
9034
|
+
body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json,
|
|
9035
|
+
capture_request_body: requestBody.capture_request_body,
|
|
9036
|
+
request_body_contains: requestBody.request_body_contains,
|
|
9037
|
+
request_body_patterns: requestBody.request_body_patterns,
|
|
9038
|
+
request_body_not_contains: requestBody.request_body_not_contains,
|
|
9039
|
+
request_body_not_patterns: requestBody.request_body_not_patterns
|
|
9013
9040
|
};
|
|
9014
9041
|
}
|
|
9015
9042
|
function normalizeNetworkMockResponses(value, mockIndex, defaults) {
|
|
9016
9043
|
if (value === void 0) return void 0;
|
|
9017
9044
|
if (!Array.isArray(value)) throw new Error(`target.network_mocks[${mockIndex}].responses must be an array.`);
|
|
9018
9045
|
if (!value.length) throw new Error(`target.network_mocks[${mockIndex}].responses must not be empty.`);
|
|
9019
|
-
const responseDefaults = {
|
|
9046
|
+
const responseDefaults = {
|
|
9047
|
+
label: void 0,
|
|
9048
|
+
status: defaults.status,
|
|
9049
|
+
content_type: defaults.content_type,
|
|
9050
|
+
headers: defaults.headers,
|
|
9051
|
+
body: defaults.body,
|
|
9052
|
+
body_json: defaults.body_json
|
|
9053
|
+
};
|
|
9020
9054
|
return value.map((response, responseIndex) => {
|
|
9021
9055
|
if (!isRecord2(response)) {
|
|
9022
9056
|
throw new Error(`target.network_mocks[${mockIndex}].responses[${responseIndex}] must be an object.`);
|
|
@@ -9759,6 +9793,9 @@ function assessNetworkMocksFromEvidence(profile, evidence) {
|
|
|
9759
9793
|
if (event.request_body_matches === false) {
|
|
9760
9794
|
failed.push({
|
|
9761
9795
|
label: event.label ?? null,
|
|
9796
|
+
response_label: event.response_label ?? null,
|
|
9797
|
+
hit_index: event.hit_index ?? null,
|
|
9798
|
+
response_index: event.response_index ?? null,
|
|
9762
9799
|
url: event.url ?? null,
|
|
9763
9800
|
method: event.method ?? null,
|
|
9764
9801
|
reason: "request_body_mismatch",
|
|
@@ -10142,6 +10179,9 @@ function assessProfile(profile, evidence) {
|
|
|
10142
10179
|
if (event && event.request_body_matches === false) {
|
|
10143
10180
|
failed.push({
|
|
10144
10181
|
label: event.label || null,
|
|
10182
|
+
response_label: event.response_label || null,
|
|
10183
|
+
hit_index: event.hit_index ?? null,
|
|
10184
|
+
response_index: event.response_index ?? null,
|
|
10145
10185
|
url: event.url || null,
|
|
10146
10186
|
method: event.method || null,
|
|
10147
10187
|
reason: "request_body_mismatch",
|
|
@@ -10606,18 +10646,21 @@ function compactNetworkMockRequestBody(value) {
|
|
|
10606
10646
|
function networkMockStringList(value) {
|
|
10607
10647
|
return Array.isArray(value) ? value.map((item) => String(item)).filter(Boolean) : [];
|
|
10608
10648
|
}
|
|
10609
|
-
function networkMockShouldCaptureRequestBody(
|
|
10610
|
-
return
|
|
10611
|
-
|
|
10612
|
-
|| networkMockStringList(
|
|
10613
|
-
|| networkMockStringList(
|
|
10614
|
-
|
|
10649
|
+
function networkMockShouldCaptureRequestBody(...sources) {
|
|
10650
|
+
return sources.some((source) => source && (
|
|
10651
|
+
source.capture_request_body === true
|
|
10652
|
+
|| networkMockStringList(source.request_body_contains).length > 0
|
|
10653
|
+
|| networkMockStringList(source.request_body_patterns).length > 0
|
|
10654
|
+
|| networkMockStringList(source.request_body_not_contains).length > 0
|
|
10655
|
+
|| networkMockStringList(source.request_body_not_patterns).length > 0
|
|
10656
|
+
));
|
|
10615
10657
|
}
|
|
10616
|
-
function
|
|
10658
|
+
function networkMockRequestBodyFailuresForSource(body, source) {
|
|
10617
10659
|
const failures = [];
|
|
10660
|
+
if (!source) return failures;
|
|
10618
10661
|
const rawBody = String(body || "");
|
|
10619
10662
|
const compactBody = compactNetworkMockRequestBody(rawBody);
|
|
10620
|
-
for (const expected of networkMockStringList(
|
|
10663
|
+
for (const expected of networkMockStringList(source.request_body_contains)) {
|
|
10621
10664
|
if (!rawBody.includes(expected) && !compactBody.includes(expected)) {
|
|
10622
10665
|
failures.push({
|
|
10623
10666
|
type: "request_body_missing_text",
|
|
@@ -10625,7 +10668,7 @@ function networkMockRequestBodyFailures(body, mock) {
|
|
|
10625
10668
|
});
|
|
10626
10669
|
}
|
|
10627
10670
|
}
|
|
10628
|
-
for (const pattern of networkMockStringList(
|
|
10671
|
+
for (const pattern of networkMockStringList(source.request_body_patterns)) {
|
|
10629
10672
|
try {
|
|
10630
10673
|
const regex = new RegExp(pattern);
|
|
10631
10674
|
if (!regex.test(rawBody) && !regex.test(compactBody)) {
|
|
@@ -10642,8 +10685,36 @@ function networkMockRequestBodyFailures(body, mock) {
|
|
|
10642
10685
|
});
|
|
10643
10686
|
}
|
|
10644
10687
|
}
|
|
10688
|
+
for (const forbidden of networkMockStringList(source.request_body_not_contains)) {
|
|
10689
|
+
if (rawBody.includes(forbidden) || compactBody.includes(forbidden)) {
|
|
10690
|
+
failures.push({
|
|
10691
|
+
type: "request_body_forbidden_text",
|
|
10692
|
+
text: String(forbidden).slice(0, 200),
|
|
10693
|
+
});
|
|
10694
|
+
}
|
|
10695
|
+
}
|
|
10696
|
+
for (const pattern of networkMockStringList(source.request_body_not_patterns)) {
|
|
10697
|
+
try {
|
|
10698
|
+
const regex = new RegExp(pattern);
|
|
10699
|
+
if (regex.test(rawBody) || regex.test(compactBody)) {
|
|
10700
|
+
failures.push({
|
|
10701
|
+
type: "request_body_forbidden_pattern_matched",
|
|
10702
|
+
pattern: String(pattern).slice(0, 200),
|
|
10703
|
+
});
|
|
10704
|
+
}
|
|
10705
|
+
} catch (error) {
|
|
10706
|
+
failures.push({
|
|
10707
|
+
type: "request_body_invalid_pattern",
|
|
10708
|
+
pattern: String(pattern).slice(0, 200),
|
|
10709
|
+
error: String(error && error.message ? error.message : error).slice(0, 500),
|
|
10710
|
+
});
|
|
10711
|
+
}
|
|
10712
|
+
}
|
|
10645
10713
|
return failures;
|
|
10646
10714
|
}
|
|
10715
|
+
function networkMockRequestBodyFailures(body, ...sources) {
|
|
10716
|
+
return sources.flatMap((source) => networkMockRequestBodyFailuresForSource(body, source));
|
|
10717
|
+
}
|
|
10647
10718
|
async function setupLocatorVisible(locator, index) {
|
|
10648
10719
|
return await locator.nth(index).isVisible({ timeout: 1000 }).catch(() => false);
|
|
10649
10720
|
}
|
|
@@ -10672,9 +10743,10 @@ async function registerNetworkMocks(mocks) {
|
|
|
10672
10743
|
body = JSON.stringify(response.body_json);
|
|
10673
10744
|
contentType = response.content_type || headers["content-type"] || headers["Content-Type"] || "application/json";
|
|
10674
10745
|
}
|
|
10675
|
-
const
|
|
10746
|
+
const responseBodyContract = responseIndex === null ? null : response;
|
|
10747
|
+
const shouldCaptureRequestBody = networkMockShouldCaptureRequestBody(mock, responseBodyContract);
|
|
10676
10748
|
const requestBody = shouldCaptureRequestBody && request.postData ? request.postData() || "" : "";
|
|
10677
|
-
const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock) : [];
|
|
10749
|
+
const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock, responseBodyContract) : [];
|
|
10678
10750
|
const status = response.status || mock.status || 200;
|
|
10679
10751
|
const event = {
|
|
10680
10752
|
ok: true,
|
package/dist/index.js
CHANGED
|
@@ -58,7 +58,7 @@ import {
|
|
|
58
58
|
resolveRiddleProofProfileTimeoutSec,
|
|
59
59
|
slugifyRiddleProofProfileName,
|
|
60
60
|
summarizeRiddleProofProfileResult
|
|
61
|
-
} from "./chunk-
|
|
61
|
+
} from "./chunk-NJDY7HYE.js";
|
|
62
62
|
import {
|
|
63
63
|
DEFAULT_RIDDLE_API_BASE_URL,
|
|
64
64
|
DEFAULT_RIDDLE_API_KEY_FILE,
|
package/dist/profile.cjs
CHANGED
|
@@ -296,15 +296,7 @@ function normalizeNetworkMock(input, index) {
|
|
|
296
296
|
const payload = normalizeNetworkMockResponsePayload(input, `target.network_mocks[${index}]`);
|
|
297
297
|
const responsesInput = input.responses ?? input.sequence;
|
|
298
298
|
const responses = normalizeNetworkMockResponses(responsesInput, index, payload);
|
|
299
|
-
const
|
|
300
|
-
input.request_body_contains ?? input.requestBodyContains ?? input.body_contains ?? input.bodyContains,
|
|
301
|
-
`target.network_mocks[${index}].request_body_contains`
|
|
302
|
-
);
|
|
303
|
-
const requestBodyPatterns = normalizeStringList(
|
|
304
|
-
input.request_body_patterns ?? input.requestBodyPatterns ?? input.body_patterns ?? input.bodyPatterns,
|
|
305
|
-
`target.network_mocks[${index}].request_body_patterns`
|
|
306
|
-
);
|
|
307
|
-
validateRegexPatterns(requestBodyPatterns, `target.network_mocks[${index}].request_body_patterns`);
|
|
299
|
+
const requestBody = normalizeNetworkMockRequestBodyConstraints(input, `target.network_mocks[${index}]`);
|
|
308
300
|
const requiredHitCount = numberValue(
|
|
309
301
|
input.required_hit_count ?? input.requiredHitCount ?? input.required_hits ?? input.requiredHits ?? input.min_hits ?? input.minHits
|
|
310
302
|
);
|
|
@@ -320,9 +312,38 @@ function normalizeNetworkMock(input, index) {
|
|
|
320
312
|
repeat_responses: input.repeat_responses === true || input.repeatResponses === true || input.cycle_responses === true || input.cycleResponses === true,
|
|
321
313
|
required_hit_count: requiredHitCount,
|
|
322
314
|
required: input.required === false ? false : true,
|
|
323
|
-
capture_request_body:
|
|
315
|
+
capture_request_body: requestBody.capture_request_body,
|
|
316
|
+
request_body_contains: requestBody.request_body_contains,
|
|
317
|
+
request_body_patterns: requestBody.request_body_patterns,
|
|
318
|
+
request_body_not_contains: requestBody.request_body_not_contains,
|
|
319
|
+
request_body_not_patterns: requestBody.request_body_not_patterns
|
|
320
|
+
};
|
|
321
|
+
}
|
|
322
|
+
function normalizeNetworkMockRequestBodyConstraints(input, label) {
|
|
323
|
+
const requestBodyContains = normalizeStringList(
|
|
324
|
+
input.request_body_contains ?? input.requestBodyContains ?? input.body_contains ?? input.bodyContains,
|
|
325
|
+
`${label}.request_body_contains`
|
|
326
|
+
);
|
|
327
|
+
const requestBodyPatterns = normalizeStringList(
|
|
328
|
+
input.request_body_patterns ?? input.requestBodyPatterns ?? input.body_patterns ?? input.bodyPatterns,
|
|
329
|
+
`${label}.request_body_patterns`
|
|
330
|
+
);
|
|
331
|
+
validateRegexPatterns(requestBodyPatterns, `${label}.request_body_patterns`);
|
|
332
|
+
const requestBodyNotContains = normalizeStringList(
|
|
333
|
+
input.request_body_not_contains ?? input.requestBodyNotContains ?? input.request_body_absent ?? input.requestBodyAbsent ?? input.body_not_contains ?? input.bodyNotContains ?? input.body_absent ?? input.bodyAbsent,
|
|
334
|
+
`${label}.request_body_not_contains`
|
|
335
|
+
);
|
|
336
|
+
const requestBodyNotPatterns = normalizeStringList(
|
|
337
|
+
input.request_body_not_patterns ?? input.requestBodyNotPatterns ?? input.request_body_forbidden_patterns ?? input.requestBodyForbiddenPatterns ?? input.body_not_patterns ?? input.bodyNotPatterns ?? input.body_forbidden_patterns ?? input.bodyForbiddenPatterns,
|
|
338
|
+
`${label}.request_body_not_patterns`
|
|
339
|
+
);
|
|
340
|
+
validateRegexPatterns(requestBodyNotPatterns, `${label}.request_body_not_patterns`);
|
|
341
|
+
return {
|
|
342
|
+
capture_request_body: input.capture_request_body === true || input.captureRequestBody === true || Boolean(requestBodyContains?.length) || Boolean(requestBodyPatterns?.length) || Boolean(requestBodyNotContains?.length) || Boolean(requestBodyNotPatterns?.length),
|
|
324
343
|
request_body_contains: requestBodyContains,
|
|
325
|
-
request_body_patterns: requestBodyPatterns
|
|
344
|
+
request_body_patterns: requestBodyPatterns,
|
|
345
|
+
request_body_not_contains: requestBodyNotContains,
|
|
346
|
+
request_body_not_patterns: requestBodyNotPatterns
|
|
326
347
|
};
|
|
327
348
|
}
|
|
328
349
|
function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
@@ -332,20 +353,33 @@ function normalizeNetworkMockResponsePayload(input, label, defaults = {}) {
|
|
|
332
353
|
}
|
|
333
354
|
const body = stringValue(input.body) ?? stringValue(input.body_text) ?? stringValue(input.bodyText) ?? defaults.body;
|
|
334
355
|
const hasJsonBody = Object.prototype.hasOwnProperty.call(input, "body_json") || Object.prototype.hasOwnProperty.call(input, "bodyJson") || Object.prototype.hasOwnProperty.call(input, "json");
|
|
356
|
+
const requestBody = normalizeNetworkMockRequestBodyConstraints(input, label);
|
|
335
357
|
return {
|
|
336
358
|
label: stringValue(input.label) || stringValue(input.name) || defaults.label,
|
|
337
359
|
status,
|
|
338
360
|
content_type: stringValue(input.content_type) || stringValue(input.contentType) || defaults.content_type,
|
|
339
361
|
headers: stringRecord(input.headers) || defaults.headers,
|
|
340
362
|
body,
|
|
341
|
-
body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json
|
|
363
|
+
body_json: hasJsonBody ? toJsonValue(input.body_json ?? input.bodyJson ?? input.json) : defaults.body_json,
|
|
364
|
+
capture_request_body: requestBody.capture_request_body,
|
|
365
|
+
request_body_contains: requestBody.request_body_contains,
|
|
366
|
+
request_body_patterns: requestBody.request_body_patterns,
|
|
367
|
+
request_body_not_contains: requestBody.request_body_not_contains,
|
|
368
|
+
request_body_not_patterns: requestBody.request_body_not_patterns
|
|
342
369
|
};
|
|
343
370
|
}
|
|
344
371
|
function normalizeNetworkMockResponses(value, mockIndex, defaults) {
|
|
345
372
|
if (value === void 0) return void 0;
|
|
346
373
|
if (!Array.isArray(value)) throw new Error(`target.network_mocks[${mockIndex}].responses must be an array.`);
|
|
347
374
|
if (!value.length) throw new Error(`target.network_mocks[${mockIndex}].responses must not be empty.`);
|
|
348
|
-
const responseDefaults = {
|
|
375
|
+
const responseDefaults = {
|
|
376
|
+
label: void 0,
|
|
377
|
+
status: defaults.status,
|
|
378
|
+
content_type: defaults.content_type,
|
|
379
|
+
headers: defaults.headers,
|
|
380
|
+
body: defaults.body,
|
|
381
|
+
body_json: defaults.body_json
|
|
382
|
+
};
|
|
349
383
|
return value.map((response, responseIndex) => {
|
|
350
384
|
if (!isRecord(response)) {
|
|
351
385
|
throw new Error(`target.network_mocks[${mockIndex}].responses[${responseIndex}] must be an object.`);
|
|
@@ -1088,6 +1122,9 @@ function assessNetworkMocksFromEvidence(profile, evidence) {
|
|
|
1088
1122
|
if (event.request_body_matches === false) {
|
|
1089
1123
|
failed.push({
|
|
1090
1124
|
label: event.label ?? null,
|
|
1125
|
+
response_label: event.response_label ?? null,
|
|
1126
|
+
hit_index: event.hit_index ?? null,
|
|
1127
|
+
response_index: event.response_index ?? null,
|
|
1091
1128
|
url: event.url ?? null,
|
|
1092
1129
|
method: event.method ?? null,
|
|
1093
1130
|
reason: "request_body_mismatch",
|
|
@@ -1471,6 +1508,9 @@ function assessProfile(profile, evidence) {
|
|
|
1471
1508
|
if (event && event.request_body_matches === false) {
|
|
1472
1509
|
failed.push({
|
|
1473
1510
|
label: event.label || null,
|
|
1511
|
+
response_label: event.response_label || null,
|
|
1512
|
+
hit_index: event.hit_index ?? null,
|
|
1513
|
+
response_index: event.response_index ?? null,
|
|
1474
1514
|
url: event.url || null,
|
|
1475
1515
|
method: event.method || null,
|
|
1476
1516
|
reason: "request_body_mismatch",
|
|
@@ -1935,18 +1975,21 @@ function compactNetworkMockRequestBody(value) {
|
|
|
1935
1975
|
function networkMockStringList(value) {
|
|
1936
1976
|
return Array.isArray(value) ? value.map((item) => String(item)).filter(Boolean) : [];
|
|
1937
1977
|
}
|
|
1938
|
-
function networkMockShouldCaptureRequestBody(
|
|
1939
|
-
return
|
|
1940
|
-
|
|
1941
|
-
|| networkMockStringList(
|
|
1942
|
-
|| networkMockStringList(
|
|
1943
|
-
|
|
1978
|
+
function networkMockShouldCaptureRequestBody(...sources) {
|
|
1979
|
+
return sources.some((source) => source && (
|
|
1980
|
+
source.capture_request_body === true
|
|
1981
|
+
|| networkMockStringList(source.request_body_contains).length > 0
|
|
1982
|
+
|| networkMockStringList(source.request_body_patterns).length > 0
|
|
1983
|
+
|| networkMockStringList(source.request_body_not_contains).length > 0
|
|
1984
|
+
|| networkMockStringList(source.request_body_not_patterns).length > 0
|
|
1985
|
+
));
|
|
1944
1986
|
}
|
|
1945
|
-
function
|
|
1987
|
+
function networkMockRequestBodyFailuresForSource(body, source) {
|
|
1946
1988
|
const failures = [];
|
|
1989
|
+
if (!source) return failures;
|
|
1947
1990
|
const rawBody = String(body || "");
|
|
1948
1991
|
const compactBody = compactNetworkMockRequestBody(rawBody);
|
|
1949
|
-
for (const expected of networkMockStringList(
|
|
1992
|
+
for (const expected of networkMockStringList(source.request_body_contains)) {
|
|
1950
1993
|
if (!rawBody.includes(expected) && !compactBody.includes(expected)) {
|
|
1951
1994
|
failures.push({
|
|
1952
1995
|
type: "request_body_missing_text",
|
|
@@ -1954,7 +1997,7 @@ function networkMockRequestBodyFailures(body, mock) {
|
|
|
1954
1997
|
});
|
|
1955
1998
|
}
|
|
1956
1999
|
}
|
|
1957
|
-
for (const pattern of networkMockStringList(
|
|
2000
|
+
for (const pattern of networkMockStringList(source.request_body_patterns)) {
|
|
1958
2001
|
try {
|
|
1959
2002
|
const regex = new RegExp(pattern);
|
|
1960
2003
|
if (!regex.test(rawBody) && !regex.test(compactBody)) {
|
|
@@ -1971,8 +2014,36 @@ function networkMockRequestBodyFailures(body, mock) {
|
|
|
1971
2014
|
});
|
|
1972
2015
|
}
|
|
1973
2016
|
}
|
|
2017
|
+
for (const forbidden of networkMockStringList(source.request_body_not_contains)) {
|
|
2018
|
+
if (rawBody.includes(forbidden) || compactBody.includes(forbidden)) {
|
|
2019
|
+
failures.push({
|
|
2020
|
+
type: "request_body_forbidden_text",
|
|
2021
|
+
text: String(forbidden).slice(0, 200),
|
|
2022
|
+
});
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
for (const pattern of networkMockStringList(source.request_body_not_patterns)) {
|
|
2026
|
+
try {
|
|
2027
|
+
const regex = new RegExp(pattern);
|
|
2028
|
+
if (regex.test(rawBody) || regex.test(compactBody)) {
|
|
2029
|
+
failures.push({
|
|
2030
|
+
type: "request_body_forbidden_pattern_matched",
|
|
2031
|
+
pattern: String(pattern).slice(0, 200),
|
|
2032
|
+
});
|
|
2033
|
+
}
|
|
2034
|
+
} catch (error) {
|
|
2035
|
+
failures.push({
|
|
2036
|
+
type: "request_body_invalid_pattern",
|
|
2037
|
+
pattern: String(pattern).slice(0, 200),
|
|
2038
|
+
error: String(error && error.message ? error.message : error).slice(0, 500),
|
|
2039
|
+
});
|
|
2040
|
+
}
|
|
2041
|
+
}
|
|
1974
2042
|
return failures;
|
|
1975
2043
|
}
|
|
2044
|
+
function networkMockRequestBodyFailures(body, ...sources) {
|
|
2045
|
+
return sources.flatMap((source) => networkMockRequestBodyFailuresForSource(body, source));
|
|
2046
|
+
}
|
|
1976
2047
|
async function setupLocatorVisible(locator, index) {
|
|
1977
2048
|
return await locator.nth(index).isVisible({ timeout: 1000 }).catch(() => false);
|
|
1978
2049
|
}
|
|
@@ -2001,9 +2072,10 @@ async function registerNetworkMocks(mocks) {
|
|
|
2001
2072
|
body = JSON.stringify(response.body_json);
|
|
2002
2073
|
contentType = response.content_type || headers["content-type"] || headers["Content-Type"] || "application/json";
|
|
2003
2074
|
}
|
|
2004
|
-
const
|
|
2075
|
+
const responseBodyContract = responseIndex === null ? null : response;
|
|
2076
|
+
const shouldCaptureRequestBody = networkMockShouldCaptureRequestBody(mock, responseBodyContract);
|
|
2005
2077
|
const requestBody = shouldCaptureRequestBody && request.postData ? request.postData() || "" : "";
|
|
2006
|
-
const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock) : [];
|
|
2078
|
+
const requestBodyFailures = shouldCaptureRequestBody ? networkMockRequestBodyFailures(requestBody, mock, responseBodyContract) : [];
|
|
2007
2079
|
const status = response.status || mock.status || 200;
|
|
2008
2080
|
const event = {
|
|
2009
2081
|
ok: true,
|
package/dist/profile.d.cts
CHANGED
|
@@ -41,6 +41,11 @@ interface RiddleProofProfileNetworkMockResponse {
|
|
|
41
41
|
headers?: Record<string, string>;
|
|
42
42
|
body?: string;
|
|
43
43
|
body_json?: JsonValue;
|
|
44
|
+
capture_request_body?: boolean;
|
|
45
|
+
request_body_contains?: string[];
|
|
46
|
+
request_body_patterns?: string[];
|
|
47
|
+
request_body_not_contains?: string[];
|
|
48
|
+
request_body_not_patterns?: string[];
|
|
44
49
|
}
|
|
45
50
|
interface RiddleProofProfileNetworkMock extends RiddleProofProfileNetworkMockResponse {
|
|
46
51
|
label: string;
|
|
@@ -53,6 +58,8 @@ interface RiddleProofProfileNetworkMock extends RiddleProofProfileNetworkMockRes
|
|
|
53
58
|
capture_request_body?: boolean;
|
|
54
59
|
request_body_contains?: string[];
|
|
55
60
|
request_body_patterns?: string[];
|
|
61
|
+
request_body_not_contains?: string[];
|
|
62
|
+
request_body_not_patterns?: string[];
|
|
56
63
|
}
|
|
57
64
|
interface RiddleProofProfileRouteInventoryRoute {
|
|
58
65
|
name?: string;
|
package/dist/profile.d.ts
CHANGED
|
@@ -41,6 +41,11 @@ interface RiddleProofProfileNetworkMockResponse {
|
|
|
41
41
|
headers?: Record<string, string>;
|
|
42
42
|
body?: string;
|
|
43
43
|
body_json?: JsonValue;
|
|
44
|
+
capture_request_body?: boolean;
|
|
45
|
+
request_body_contains?: string[];
|
|
46
|
+
request_body_patterns?: string[];
|
|
47
|
+
request_body_not_contains?: string[];
|
|
48
|
+
request_body_not_patterns?: string[];
|
|
44
49
|
}
|
|
45
50
|
interface RiddleProofProfileNetworkMock extends RiddleProofProfileNetworkMockResponse {
|
|
46
51
|
label: string;
|
|
@@ -53,6 +58,8 @@ interface RiddleProofProfileNetworkMock extends RiddleProofProfileNetworkMockRes
|
|
|
53
58
|
capture_request_body?: boolean;
|
|
54
59
|
request_body_contains?: string[];
|
|
55
60
|
request_body_patterns?: string[];
|
|
61
|
+
request_body_not_contains?: string[];
|
|
62
|
+
request_body_not_patterns?: string[];
|
|
56
63
|
}
|
|
57
64
|
interface RiddleProofProfileRouteInventoryRoute {
|
|
58
65
|
name?: string;
|
package/dist/profile.js
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
resolveRiddleProofProfileTimeoutSec,
|
|
20
20
|
slugifyRiddleProofProfileName,
|
|
21
21
|
summarizeRiddleProofProfileResult
|
|
22
|
-
} from "./chunk-
|
|
22
|
+
} from "./chunk-NJDY7HYE.js";
|
|
23
23
|
export {
|
|
24
24
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
25
25
|
RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
|
|
@@ -292,7 +292,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
|
|
|
292
292
|
blocking?: boolean;
|
|
293
293
|
details?: Record<string, unknown>;
|
|
294
294
|
ok: boolean;
|
|
295
|
-
action: "
|
|
295
|
+
action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
|
|
296
296
|
state_path: string;
|
|
297
297
|
stage: any;
|
|
298
298
|
summary: string;
|
|
@@ -382,7 +382,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
|
|
|
382
382
|
continueWithStage?: WorkflowStage | null;
|
|
383
383
|
blocking?: boolean;
|
|
384
384
|
details?: Record<string, unknown>;
|
|
385
|
-
action: "
|
|
385
|
+
action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
|
|
386
386
|
state_path: string;
|
|
387
387
|
stage: any;
|
|
388
388
|
checkpoint: string;
|
|
@@ -659,7 +659,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
|
|
|
659
659
|
error?: undefined;
|
|
660
660
|
} | {
|
|
661
661
|
ok: boolean;
|
|
662
|
-
action: "
|
|
662
|
+
action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
|
|
663
663
|
state_path: string;
|
|
664
664
|
stage: any;
|
|
665
665
|
summary: string;
|
|
@@ -292,7 +292,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
|
|
|
292
292
|
blocking?: boolean;
|
|
293
293
|
details?: Record<string, unknown>;
|
|
294
294
|
ok: boolean;
|
|
295
|
-
action: "
|
|
295
|
+
action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
|
|
296
296
|
state_path: string;
|
|
297
297
|
stage: any;
|
|
298
298
|
summary: string;
|
|
@@ -382,7 +382,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
|
|
|
382
382
|
continueWithStage?: WorkflowStage | null;
|
|
383
383
|
blocking?: boolean;
|
|
384
384
|
details?: Record<string, unknown>;
|
|
385
|
-
action: "
|
|
385
|
+
action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
|
|
386
386
|
state_path: string;
|
|
387
387
|
stage: any;
|
|
388
388
|
checkpoint: string;
|
|
@@ -659,7 +659,7 @@ declare function executeWorkflow(params: WorkflowParams, pluginConfig: any, reso
|
|
|
659
659
|
error?: undefined;
|
|
660
660
|
} | {
|
|
661
661
|
ok: boolean;
|
|
662
|
-
action: "
|
|
662
|
+
action: "setup" | "recon" | "author" | "implement" | "verify" | "ship" | "run";
|
|
663
663
|
state_path: string;
|
|
664
664
|
stage: any;
|
|
665
665
|
summary: string;
|