@riddledc/riddle-proof 0.7.58 → 0.7.60
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 +17 -0
- package/dist/{chunk-7ZBK2GQX.js → chunk-FLQ4HHTT.js} +226 -38
- package/dist/cli.cjs +226 -38
- package/dist/cli.js +1 -1
- package/dist/index.cjs +226 -38
- package/dist/index.js +1 -1
- package/dist/profile.cjs +226 -38
- package/dist/profile.d.cts +4 -1
- package/dist/profile.d.ts +4 -1
- package/dist/profile.js +1 -1
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -6895,6 +6895,8 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
|
|
|
6895
6895
|
"selector_count_eq",
|
|
6896
6896
|
"selector_text_order",
|
|
6897
6897
|
"frame_text_visible",
|
|
6898
|
+
"frame_url_equals",
|
|
6899
|
+
"frame_url_matches",
|
|
6898
6900
|
"frame_no_horizontal_overflow",
|
|
6899
6901
|
"text_visible",
|
|
6900
6902
|
"text_absent",
|
|
@@ -7109,6 +7111,11 @@ function normalizeSetupAction(input, index) {
|
|
|
7109
7111
|
if (!isRecord(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
|
|
7110
7112
|
const type = normalizeSetupActionType(stringValue2(input.type), index);
|
|
7111
7113
|
const selector = stringValue2(input.selector);
|
|
7114
|
+
const frameSelector = stringFromOwn(input, "frame_selector", "frameSelector", "iframe_selector", "iframeSelector");
|
|
7115
|
+
const frameIndex = numberValue(valueFromOwn(input, "frame_index", "frameIndex", "iframe_index", "iframeIndex"));
|
|
7116
|
+
if (frameIndex !== void 0 && (!Number.isInteger(frameIndex) || frameIndex < 0)) {
|
|
7117
|
+
throw new Error(`target.setup_actions[${index}].frame_index must be a non-negative integer.`);
|
|
7118
|
+
}
|
|
7112
7119
|
if ((type === "click" || type === "fill" || type === "set_input_value" || type === "wait_for_selector" || type === "wait_for_text" || type === "assert_text_visible" || type === "assert_text_absent" || type === "assert_selector_count") && !selector) {
|
|
7113
7120
|
throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
|
|
7114
7121
|
}
|
|
@@ -7161,6 +7168,8 @@ function normalizeSetupAction(input, index) {
|
|
|
7161
7168
|
return {
|
|
7162
7169
|
type,
|
|
7163
7170
|
selector,
|
|
7171
|
+
frame_selector: frameSelector,
|
|
7172
|
+
frame_index: frameIndex,
|
|
7164
7173
|
force: type === "click" && (input.force === true || input.force_click === true || input.forceClick === true),
|
|
7165
7174
|
key,
|
|
7166
7175
|
value,
|
|
@@ -7372,12 +7381,19 @@ function normalizeCheck(input, index) {
|
|
|
7372
7381
|
if ((type === "selector_visible" || type === "selector_absent" || type === "selector_count_at_least" || type === "selector_count_equals" || type === "selector_count_equal" || type === "selector_count_eq") && !stringValue2(input.selector)) {
|
|
7373
7382
|
throw new Error(`checks[${index}] ${type} requires selector.`);
|
|
7374
7383
|
}
|
|
7375
|
-
if ((type === "frame_text_visible" || type === "frame_no_horizontal_overflow") && !stringValue2(input.selector)) {
|
|
7384
|
+
if ((type === "frame_text_visible" || type === "frame_url_equals" || type === "frame_url_matches" || type === "frame_no_horizontal_overflow") && !stringValue2(input.selector)) {
|
|
7376
7385
|
throw new Error(`checks[${index}] ${type} requires selector.`);
|
|
7377
7386
|
}
|
|
7378
7387
|
if (type === "frame_text_visible" && !stringValue2(input.text) && !stringValue2(input.pattern)) {
|
|
7379
7388
|
throw new Error(`checks[${index}] frame_text_visible requires text or pattern.`);
|
|
7380
7389
|
}
|
|
7390
|
+
const expectedUrl = stringFromOwn(input, "expected_url", "expectedUrl", "url", "expected_value", "expectedValue", "value");
|
|
7391
|
+
if (type === "frame_url_equals" && expectedUrl === void 0) {
|
|
7392
|
+
throw new Error(`checks[${index}] frame_url_equals requires expected_url.`);
|
|
7393
|
+
}
|
|
7394
|
+
if (type === "frame_url_matches" && !stringValue2(input.pattern)) {
|
|
7395
|
+
throw new Error(`checks[${index}] frame_url_matches requires pattern.`);
|
|
7396
|
+
}
|
|
7381
7397
|
if ((type === "text_visible" || type === "text_absent") && !stringValue2(input.text) && !stringValue2(input.pattern)) {
|
|
7382
7398
|
throw new Error(`checks[${index}] ${type} requires text or pattern.`);
|
|
7383
7399
|
}
|
|
@@ -7410,6 +7426,7 @@ function normalizeCheck(input, index) {
|
|
|
7410
7426
|
expected_path: stringValue2(input.expected_path),
|
|
7411
7427
|
param: stringValue2(input.param) || stringValue2(input.search_param) || stringValue2(input.searchParam) || stringValue2(input.key),
|
|
7412
7428
|
expected_value: expectedValue,
|
|
7429
|
+
expected_url: expectedUrl,
|
|
7413
7430
|
expected_routes: expectedRoutes,
|
|
7414
7431
|
selector: stringValue2(input.selector),
|
|
7415
7432
|
expected_texts: expectedTexts,
|
|
@@ -7877,6 +7894,35 @@ function assessCheckFromEvidence(check, evidence) {
|
|
|
7877
7894
|
message: failed ? `Frame selector ${key} did not contain expected text in ${failed} viewport(s).` : void 0
|
|
7878
7895
|
};
|
|
7879
7896
|
}
|
|
7897
|
+
if (check.type === "frame_url_equals" || check.type === "frame_url_matches") {
|
|
7898
|
+
const key = selectorKey(check);
|
|
7899
|
+
const expectedUrl = check.expected_url || check.expected_value || "";
|
|
7900
|
+
const results = viewports.map((viewport) => {
|
|
7901
|
+
const frames = frameEvidenceForSelector(viewport, key);
|
|
7902
|
+
const urls = frames.map((frame) => String(frame.url || "")).filter(Boolean);
|
|
7903
|
+
const matches = urls.filter((url) => check.type === "frame_url_equals" ? url === expectedUrl : matchText(url, check));
|
|
7904
|
+
return {
|
|
7905
|
+
viewport: viewport.name,
|
|
7906
|
+
frame_count: frames.length,
|
|
7907
|
+
matched_count: matches.length,
|
|
7908
|
+
matched: matches.length > 0,
|
|
7909
|
+
urls: urls.slice(0, 10)
|
|
7910
|
+
};
|
|
7911
|
+
});
|
|
7912
|
+
const failed = results.filter((result) => !result.matched).length;
|
|
7913
|
+
return {
|
|
7914
|
+
type: check.type,
|
|
7915
|
+
label: checkLabel(check),
|
|
7916
|
+
status: failed ? "failed" : "passed",
|
|
7917
|
+
evidence: {
|
|
7918
|
+
selector: key,
|
|
7919
|
+
expected_url: check.type === "frame_url_equals" ? expectedUrl : null,
|
|
7920
|
+
pattern: check.type === "frame_url_matches" ? check.pattern || null : null,
|
|
7921
|
+
viewports: results.map((result) => toJsonValue(result))
|
|
7922
|
+
},
|
|
7923
|
+
message: failed ? `Frame selector ${key} URL assertion failed in ${failed} viewport(s).` : void 0
|
|
7924
|
+
};
|
|
7925
|
+
}
|
|
7880
7926
|
if (check.type === "frame_no_horizontal_overflow") {
|
|
7881
7927
|
const key = selectorKey(check);
|
|
7882
7928
|
const maxOverflow = check.max_overflow_px ?? 4;
|
|
@@ -8047,6 +8093,8 @@ function assessSetupActionsFromEvidence(profile, evidence) {
|
|
|
8047
8093
|
viewport: viewport.name,
|
|
8048
8094
|
action: result.action ?? result.type ?? null,
|
|
8049
8095
|
selector: result.selector ?? null,
|
|
8096
|
+
frame_selector: result.frame_selector ?? null,
|
|
8097
|
+
frame_index: result.frame_index ?? null,
|
|
8050
8098
|
reason: result.reason ?? result.error ?? null
|
|
8051
8099
|
});
|
|
8052
8100
|
}
|
|
@@ -8543,10 +8591,12 @@ function assessProfile(profile, evidence) {
|
|
|
8543
8591
|
if (result && result.ok === false) {
|
|
8544
8592
|
failed.push({
|
|
8545
8593
|
viewport: viewport.name,
|
|
8546
|
-
|
|
8547
|
-
|
|
8548
|
-
|
|
8549
|
-
|
|
8594
|
+
action: result.action || result.type || null,
|
|
8595
|
+
selector: result.selector || null,
|
|
8596
|
+
frame_selector: result.frame_selector || null,
|
|
8597
|
+
frame_index: result.frame_index ?? null,
|
|
8598
|
+
reason: result.reason || result.error || null,
|
|
8599
|
+
});
|
|
8550
8600
|
}
|
|
8551
8601
|
}
|
|
8552
8602
|
if (results.length < actionCount && results.every((result) => !result || result.ok !== false)) {
|
|
@@ -8748,6 +8798,36 @@ function assessProfile(profile, evidence) {
|
|
|
8748
8798
|
});
|
|
8749
8799
|
continue;
|
|
8750
8800
|
}
|
|
8801
|
+
if (check.type === "frame_url_equals" || check.type === "frame_url_matches") {
|
|
8802
|
+
const selector = check.selector || "";
|
|
8803
|
+
const expectedUrl = check.expected_url || check.expected_value || "";
|
|
8804
|
+
const results = checkViewports.map((viewport) => {
|
|
8805
|
+
const frames = frameEvidenceForSelector(viewport, selector);
|
|
8806
|
+
const urls = frames.map((frame) => String(frame.url || "")).filter(Boolean);
|
|
8807
|
+
const matches = urls.filter((url) => check.type === "frame_url_equals" ? url === expectedUrl : textMatches(url, check));
|
|
8808
|
+
return {
|
|
8809
|
+
viewport: viewport.name,
|
|
8810
|
+
frame_count: frames.length,
|
|
8811
|
+
matched_count: matches.length,
|
|
8812
|
+
matched: matches.length > 0,
|
|
8813
|
+
urls: urls.slice(0, 10),
|
|
8814
|
+
};
|
|
8815
|
+
});
|
|
8816
|
+
const failed = results.filter((result) => !result.matched).length;
|
|
8817
|
+
checks.push({
|
|
8818
|
+
type: check.type,
|
|
8819
|
+
label: check.label || check.type,
|
|
8820
|
+
status: failed ? "failed" : "passed",
|
|
8821
|
+
evidence: {
|
|
8822
|
+
selector,
|
|
8823
|
+
expected_url: check.type === "frame_url_equals" ? expectedUrl : null,
|
|
8824
|
+
pattern: check.type === "frame_url_matches" ? check.pattern || null : null,
|
|
8825
|
+
viewports: results,
|
|
8826
|
+
},
|
|
8827
|
+
message: failed ? "Frame selector " + selector + " URL assertion failed in " + failed + " viewport(s)." : undefined,
|
|
8828
|
+
});
|
|
8829
|
+
continue;
|
|
8830
|
+
}
|
|
8751
8831
|
if (check.type === "frame_no_horizontal_overflow") {
|
|
8752
8832
|
const selector = check.selector || "";
|
|
8753
8833
|
const maxOverflow = check.max_overflow_px == null ? 4 : check.max_overflow_px;
|
|
@@ -9009,8 +9089,8 @@ function setupJsonValue(value) {
|
|
|
9009
9089
|
function setupValuesEqual(left, right) {
|
|
9010
9090
|
return JSON.stringify(setupJsonValue(left)) === JSON.stringify(setupJsonValue(right));
|
|
9011
9091
|
}
|
|
9012
|
-
async function setupReadWindowValue(path) {
|
|
9013
|
-
return await
|
|
9092
|
+
async function setupReadWindowValue(context, path) {
|
|
9093
|
+
return await context.evaluate(({ path }) => {
|
|
9014
9094
|
const toJsonValue = (value) => {
|
|
9015
9095
|
if (value === null || value === undefined) return null;
|
|
9016
9096
|
if (typeof value === "string" || typeof value === "boolean") return value;
|
|
@@ -9032,6 +9112,80 @@ async function setupReadWindowValue(path) {
|
|
|
9032
9112
|
return { ok: true, value: toJsonValue(current) };
|
|
9033
9113
|
}, { path });
|
|
9034
9114
|
}
|
|
9115
|
+
function setupFrameSelector(action) {
|
|
9116
|
+
return String(action?.frame_selector || action?.frameSelector || action?.iframe_selector || action?.iframeSelector || "").trim();
|
|
9117
|
+
}
|
|
9118
|
+
function setupFrameIndex(action) {
|
|
9119
|
+
const raw = action?.frame_index ?? action?.frameIndex ?? action?.iframe_index ?? action?.iframeIndex ?? 0;
|
|
9120
|
+
const number = Number(raw);
|
|
9121
|
+
return Number.isInteger(number) && number >= 0 ? number : 0;
|
|
9122
|
+
}
|
|
9123
|
+
function setupScopeEvidence(scope) {
|
|
9124
|
+
if (!scope || !scope.frame_selector) return {};
|
|
9125
|
+
return {
|
|
9126
|
+
frame_selector: scope.frame_selector,
|
|
9127
|
+
frame_index: scope.frame_index,
|
|
9128
|
+
frame_count: scope.frame_count,
|
|
9129
|
+
};
|
|
9130
|
+
}
|
|
9131
|
+
function setupScopeFailure(base, scope) {
|
|
9132
|
+
return {
|
|
9133
|
+
...base,
|
|
9134
|
+
...setupScopeEvidence(scope),
|
|
9135
|
+
reason: scope?.reason || "frame_scope_unavailable",
|
|
9136
|
+
error: scope?.error || undefined,
|
|
9137
|
+
};
|
|
9138
|
+
}
|
|
9139
|
+
async function setupActionScope(action, timeout) {
|
|
9140
|
+
const frameSelector = setupFrameSelector(action);
|
|
9141
|
+
if (!frameSelector) return { ok: true, context: page };
|
|
9142
|
+
const frameIndex = setupFrameIndex(action);
|
|
9143
|
+
let frameCount = 0;
|
|
9144
|
+
let locator = null;
|
|
9145
|
+
try {
|
|
9146
|
+
await page.waitForSelector(frameSelector, { state: "attached", timeout });
|
|
9147
|
+
locator = page.locator(frameSelector);
|
|
9148
|
+
frameCount = await locator.count();
|
|
9149
|
+
} catch (error) {
|
|
9150
|
+
return {
|
|
9151
|
+
ok: false,
|
|
9152
|
+
reason: "frame_selector_not_found",
|
|
9153
|
+
frame_selector: frameSelector,
|
|
9154
|
+
frame_index: frameIndex,
|
|
9155
|
+
frame_count: frameCount,
|
|
9156
|
+
error: String(error && error.message ? error.message : error).slice(0, 1000),
|
|
9157
|
+
};
|
|
9158
|
+
}
|
|
9159
|
+
if (!frameCount) {
|
|
9160
|
+
return { ok: false, reason: "frame_selector_not_found", frame_selector: frameSelector, frame_index: frameIndex, frame_count: frameCount };
|
|
9161
|
+
}
|
|
9162
|
+
if (frameIndex >= frameCount) {
|
|
9163
|
+
return { ok: false, reason: "frame_index_out_of_range", frame_selector: frameSelector, frame_index: frameIndex, frame_count: frameCount };
|
|
9164
|
+
}
|
|
9165
|
+
const handle = await locator.nth(frameIndex).elementHandle({ timeout }).catch((error) => ({ __riddle_error: error }));
|
|
9166
|
+
if (!handle || handle.__riddle_error) {
|
|
9167
|
+
return {
|
|
9168
|
+
ok: false,
|
|
9169
|
+
reason: "frame_element_unavailable",
|
|
9170
|
+
frame_selector: frameSelector,
|
|
9171
|
+
frame_index: frameIndex,
|
|
9172
|
+
frame_count: frameCount,
|
|
9173
|
+
error: handle?.__riddle_error ? String(handle.__riddle_error && handle.__riddle_error.message ? handle.__riddle_error.message : handle.__riddle_error).slice(0, 1000) : undefined,
|
|
9174
|
+
};
|
|
9175
|
+
}
|
|
9176
|
+
const frame = typeof handle.contentFrame === "function" ? await handle.contentFrame().catch((error) => ({ __riddle_error: error })) : null;
|
|
9177
|
+
if (!frame || frame.__riddle_error) {
|
|
9178
|
+
return {
|
|
9179
|
+
ok: false,
|
|
9180
|
+
reason: "content_frame_unavailable",
|
|
9181
|
+
frame_selector: frameSelector,
|
|
9182
|
+
frame_index: frameIndex,
|
|
9183
|
+
frame_count: frameCount,
|
|
9184
|
+
error: frame?.__riddle_error ? String(frame.__riddle_error && frame.__riddle_error.message ? frame.__riddle_error.message : frame.__riddle_error).slice(0, 1000) : undefined,
|
|
9185
|
+
};
|
|
9186
|
+
}
|
|
9187
|
+
return { ok: true, context: frame, frame_selector: frameSelector, frame_index: frameIndex, frame_count: frameCount };
|
|
9188
|
+
}
|
|
9035
9189
|
async function setupLocatorText(locator, index) {
|
|
9036
9190
|
return await locator.nth(index).textContent({ timeout: 1000 }).catch(() => "");
|
|
9037
9191
|
}
|
|
@@ -9193,7 +9347,8 @@ async function registerNetworkMocks(mocks) {
|
|
|
9193
9347
|
}
|
|
9194
9348
|
async function executeSetupAction(action, ordinal) {
|
|
9195
9349
|
const type = setupActionType(action);
|
|
9196
|
-
const
|
|
9350
|
+
const frameSelector = setupFrameSelector(action);
|
|
9351
|
+
const base = { ok: false, action: type || "unknown", ordinal, selector: action.selector || null, frame_selector: frameSelector || null };
|
|
9197
9352
|
const timeout = setupNumber(action.timeout_ms, 5000);
|
|
9198
9353
|
try {
|
|
9199
9354
|
if (type === "wait") {
|
|
@@ -9202,51 +9357,65 @@ async function executeSetupAction(action, ordinal) {
|
|
|
9202
9357
|
return { ...base, ok: true, ms };
|
|
9203
9358
|
}
|
|
9204
9359
|
if (type === "wait_for_selector") {
|
|
9205
|
-
await
|
|
9206
|
-
return
|
|
9360
|
+
const scope = await setupActionScope(action, timeout);
|
|
9361
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
9362
|
+
await scope.context.waitForSelector(action.selector, { state: "visible", timeout });
|
|
9363
|
+
return { ...base, ...setupScopeEvidence(scope), ok: true, timeout_ms: timeout };
|
|
9207
9364
|
}
|
|
9208
9365
|
if (type === "press") {
|
|
9209
9366
|
const key = String(action.key || "").trim();
|
|
9210
9367
|
if (!key) return { ...base, reason: "missing_key" };
|
|
9368
|
+
const scope = await setupActionScope(action, timeout);
|
|
9369
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
9211
9370
|
if (!action.selector) {
|
|
9212
|
-
|
|
9213
|
-
|
|
9371
|
+
if (scope.frame_selector) {
|
|
9372
|
+
await scope.context.locator("body").press(key, { timeout });
|
|
9373
|
+
} else {
|
|
9374
|
+
await page.keyboard.press(key);
|
|
9375
|
+
}
|
|
9376
|
+
return { ...base, ...setupScopeEvidence(scope), ok: true, key };
|
|
9214
9377
|
}
|
|
9215
|
-
const locator =
|
|
9378
|
+
const locator = scope.context.locator(action.selector);
|
|
9216
9379
|
const count = await locator.count();
|
|
9217
9380
|
if (!count) return { ...base, reason: "selector_not_found", count, key };
|
|
9218
9381
|
const targetIndex = Number.isInteger(action.index) ? action.index : 0;
|
|
9219
9382
|
if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex, key };
|
|
9220
9383
|
await locator.nth(targetIndex).press(key, { timeout });
|
|
9221
|
-
return { ...base, ok: true, count, target_index: targetIndex, key };
|
|
9384
|
+
return { ...base, ...setupScopeEvidence(scope), ok: true, count, target_index: targetIndex, key };
|
|
9222
9385
|
}
|
|
9223
9386
|
if (type === "local_storage" || type === "session_storage") {
|
|
9224
9387
|
const value = setupActionValue(action);
|
|
9225
|
-
await
|
|
9388
|
+
const scope = await setupActionScope(action, timeout);
|
|
9389
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
9390
|
+
await scope.context.evaluate(({ type, key, value }) => {
|
|
9226
9391
|
const storage = type === "session_storage" ? window.sessionStorage : window.localStorage;
|
|
9227
9392
|
storage.setItem(key, value);
|
|
9228
9393
|
}, { type, key: action.key, value });
|
|
9229
9394
|
if (action.reload === true) {
|
|
9230
9395
|
await page.reload({ waitUntil: "domcontentloaded", timeout: 45000 });
|
|
9231
9396
|
}
|
|
9232
|
-
return { ...base, ok: true, key: action.key, value_length: value.length, reload: action.reload === true };
|
|
9397
|
+
return { ...base, ...setupScopeEvidence(scope), ok: true, key: action.key, value_length: value.length, reload: action.reload === true };
|
|
9233
9398
|
}
|
|
9234
9399
|
if (type === "clear_storage") {
|
|
9235
9400
|
const storage = action.storage || "both";
|
|
9236
|
-
await
|
|
9401
|
+
const scope = await setupActionScope(action, timeout);
|
|
9402
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
9403
|
+
await scope.context.evaluate(({ storage }) => {
|
|
9237
9404
|
if (storage === "local" || storage === "both") window.localStorage.clear();
|
|
9238
9405
|
if (storage === "session" || storage === "both") window.sessionStorage.clear();
|
|
9239
9406
|
}, { storage });
|
|
9240
9407
|
if (action.reload === true) {
|
|
9241
9408
|
await page.reload({ waitUntil: "domcontentloaded", timeout: 45000 });
|
|
9242
9409
|
}
|
|
9243
|
-
return { ...base, ok: true, storage, reload: action.reload === true };
|
|
9410
|
+
return { ...base, ...setupScopeEvidence(scope), ok: true, storage, reload: action.reload === true };
|
|
9244
9411
|
}
|
|
9245
9412
|
if (type === "window_call") {
|
|
9246
9413
|
const path = String(action.path || action.function_path || action.functionPath || "");
|
|
9247
9414
|
const args = Array.isArray(action.args) ? action.args : [];
|
|
9248
9415
|
if (!path) return { ...base, path, reason: "missing_path" };
|
|
9249
|
-
const
|
|
9416
|
+
const scope = await setupActionScope(action, timeout);
|
|
9417
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
9418
|
+
const result = await scope.context.evaluate(async ({ path, args }) => {
|
|
9250
9419
|
const toJsonValue = (value) => {
|
|
9251
9420
|
if (value === null || value === undefined) return null;
|
|
9252
9421
|
if (typeof value === "string" || typeof value === "boolean") return value;
|
|
@@ -9286,6 +9455,7 @@ async function executeSetupAction(action, ordinal) {
|
|
|
9286
9455
|
const expectationMet = !hasExpectation || setupValuesEqual(result.returned, expected);
|
|
9287
9456
|
return {
|
|
9288
9457
|
...base,
|
|
9458
|
+
...setupScopeEvidence(scope),
|
|
9289
9459
|
ok: Boolean(result.ok && expectationMet),
|
|
9290
9460
|
path,
|
|
9291
9461
|
arg_count: args.length,
|
|
@@ -9316,13 +9486,16 @@ async function executeSetupAction(action, ordinal) {
|
|
|
9316
9486
|
: action.expect;
|
|
9317
9487
|
if (!path) return { ...base, path, reason: "missing_path" };
|
|
9318
9488
|
if (!hasExpected) return { ...base, path, reason: "missing_expected_value" };
|
|
9489
|
+
const scope = await setupActionScope(action, timeout);
|
|
9490
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
9319
9491
|
const startedAt = Date.now();
|
|
9320
9492
|
let result = null;
|
|
9321
9493
|
while (Date.now() - startedAt <= timeout) {
|
|
9322
|
-
result = await setupReadWindowValue(path);
|
|
9494
|
+
result = await setupReadWindowValue(scope.context, path);
|
|
9323
9495
|
if (result.ok && setupValuesEqual(result.value, expected)) {
|
|
9324
9496
|
return {
|
|
9325
9497
|
...base,
|
|
9498
|
+
...setupScopeEvidence(scope),
|
|
9326
9499
|
ok: true,
|
|
9327
9500
|
path,
|
|
9328
9501
|
value: setupJsonValue(result.value),
|
|
@@ -9334,6 +9507,7 @@ async function executeSetupAction(action, ordinal) {
|
|
|
9334
9507
|
}
|
|
9335
9508
|
return {
|
|
9336
9509
|
...base,
|
|
9510
|
+
...setupScopeEvidence(scope),
|
|
9337
9511
|
path,
|
|
9338
9512
|
reason: result?.ok ? "unexpected_value" : result?.reason || "path_not_found",
|
|
9339
9513
|
missing_part: result?.missing_part || undefined,
|
|
@@ -9350,11 +9524,13 @@ async function executeSetupAction(action, ordinal) {
|
|
|
9350
9524
|
const hasExpected = expected !== undefined;
|
|
9351
9525
|
if (!path) return { ...base, path, reason: "missing_path" };
|
|
9352
9526
|
if (!hasExpected && minValue === undefined && maxValue === undefined) return { ...base, path, reason: "missing_number_expectation" };
|
|
9527
|
+
const scope = await setupActionScope(action, timeout);
|
|
9528
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
9353
9529
|
const startedAt = Date.now();
|
|
9354
9530
|
let result = null;
|
|
9355
9531
|
let lastReason = "path_not_found";
|
|
9356
9532
|
while (Date.now() - startedAt <= timeout) {
|
|
9357
|
-
result = await setupReadWindowValue(path);
|
|
9533
|
+
result = await setupReadWindowValue(scope.context, path);
|
|
9358
9534
|
if (result.ok) {
|
|
9359
9535
|
const actual = setupFiniteNumber(result.value);
|
|
9360
9536
|
if (actual === undefined) {
|
|
@@ -9368,6 +9544,7 @@ async function executeSetupAction(action, ordinal) {
|
|
|
9368
9544
|
} else {
|
|
9369
9545
|
return {
|
|
9370
9546
|
...base,
|
|
9547
|
+
...setupScopeEvidence(scope),
|
|
9371
9548
|
ok: true,
|
|
9372
9549
|
path,
|
|
9373
9550
|
value: actual,
|
|
@@ -9384,6 +9561,7 @@ async function executeSetupAction(action, ordinal) {
|
|
|
9384
9561
|
}
|
|
9385
9562
|
return {
|
|
9386
9563
|
...base,
|
|
9564
|
+
...setupScopeEvidence(scope),
|
|
9387
9565
|
path,
|
|
9388
9566
|
reason: lastReason,
|
|
9389
9567
|
missing_part: result?.missing_part || undefined,
|
|
@@ -9395,7 +9573,9 @@ async function executeSetupAction(action, ordinal) {
|
|
|
9395
9573
|
};
|
|
9396
9574
|
}
|
|
9397
9575
|
if (type === "click") {
|
|
9398
|
-
const
|
|
9576
|
+
const scope = await setupActionScope(action, timeout);
|
|
9577
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
9578
|
+
const locator = scope.context.locator(action.selector);
|
|
9399
9579
|
const count = await locator.count();
|
|
9400
9580
|
if (!count) return { ...base, reason: "selector_not_found", count };
|
|
9401
9581
|
let targetIndex = Number.isInteger(action.index) ? action.index : 0;
|
|
@@ -9427,33 +9607,39 @@ async function executeSetupAction(action, ordinal) {
|
|
|
9427
9607
|
? { timeout, noWaitAfter: true, force: true }
|
|
9428
9608
|
: { timeout, noWaitAfter: true };
|
|
9429
9609
|
await locator.nth(targetIndex).click(clickOptions);
|
|
9430
|
-
return { ...base, ok: true, count, target_index: targetIndex, text: matchedText, force: action.force === true || undefined };
|
|
9610
|
+
return { ...base, ...setupScopeEvidence(scope), ok: true, count, target_index: targetIndex, text: matchedText, force: action.force === true || undefined };
|
|
9431
9611
|
}
|
|
9432
9612
|
if (type === "fill" || type === "set_input_value") {
|
|
9433
|
-
const
|
|
9613
|
+
const scope = await setupActionScope(action, timeout);
|
|
9614
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
9615
|
+
const locator = scope.context.locator(action.selector);
|
|
9434
9616
|
const count = await locator.count();
|
|
9435
9617
|
if (!count) return { ...base, reason: "selector_not_found", count };
|
|
9436
9618
|
const targetIndex = Number.isInteger(action.index) ? action.index : 0;
|
|
9437
9619
|
if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
|
|
9438
9620
|
const value = setupActionValue(action);
|
|
9439
9621
|
await locator.nth(targetIndex).fill(value, { timeout });
|
|
9440
|
-
return { ...base, ok: true, count, target_index: targetIndex, value_length: value.length };
|
|
9622
|
+
return { ...base, ...setupScopeEvidence(scope), ok: true, count, target_index: targetIndex, value_length: value.length };
|
|
9441
9623
|
}
|
|
9442
9624
|
if (type === "assert_selector_count") {
|
|
9443
|
-
const
|
|
9625
|
+
const scope = await setupActionScope(action, timeout);
|
|
9626
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
9627
|
+
const locator = scope.context.locator(action.selector);
|
|
9444
9628
|
const expectedCount = setupNumber(action.expected_count, -1);
|
|
9445
9629
|
if (!Number.isInteger(expectedCount) || expectedCount < 0) return { ...base, reason: "invalid_expected_count", expected_count: action.expected_count };
|
|
9446
9630
|
const startedAt = Date.now();
|
|
9447
9631
|
let count = 0;
|
|
9448
9632
|
while (Date.now() - startedAt <= timeout) {
|
|
9449
9633
|
count = await locator.count().catch(() => 0);
|
|
9450
|
-
if (count === expectedCount) return { ...base, ok: true, count, expected_count: expectedCount, timeout_ms: timeout };
|
|
9634
|
+
if (count === expectedCount) return { ...base, ...setupScopeEvidence(scope), ok: true, count, expected_count: expectedCount, timeout_ms: timeout };
|
|
9451
9635
|
await page.waitForTimeout(100);
|
|
9452
9636
|
}
|
|
9453
|
-
return { ...base, reason: "selector_count_mismatch", count, expected_count: expectedCount, timeout_ms: timeout };
|
|
9637
|
+
return { ...base, ...setupScopeEvidence(scope), reason: "selector_count_mismatch", count, expected_count: expectedCount, timeout_ms: timeout };
|
|
9454
9638
|
}
|
|
9455
9639
|
if (type === "wait_for_text") {
|
|
9456
|
-
const
|
|
9640
|
+
const scope = await setupActionScope(action, timeout);
|
|
9641
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
9642
|
+
const locator = scope.context.locator(action.selector);
|
|
9457
9643
|
const startedAt = Date.now();
|
|
9458
9644
|
let lastText = "";
|
|
9459
9645
|
while (Date.now() - startedAt <= timeout) {
|
|
@@ -9462,15 +9648,17 @@ async function executeSetupAction(action, ordinal) {
|
|
|
9462
9648
|
const text = await setupLocatorText(locator, index);
|
|
9463
9649
|
lastText = text || lastText;
|
|
9464
9650
|
if (setupTextMatches(text, action)) {
|
|
9465
|
-
return { ...base, ok: true, text: compactSetupResultText(text), target_index: index, timeout_ms: timeout };
|
|
9651
|
+
return { ...base, ...setupScopeEvidence(scope), ok: true, text: compactSetupResultText(text), target_index: index, timeout_ms: timeout };
|
|
9466
9652
|
}
|
|
9467
9653
|
}
|
|
9468
9654
|
await page.waitForTimeout(100);
|
|
9469
9655
|
}
|
|
9470
|
-
return { ...base, reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
|
|
9656
|
+
return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
|
|
9471
9657
|
}
|
|
9472
9658
|
if (type === "assert_text_visible" || type === "assert_text_absent") {
|
|
9473
|
-
const
|
|
9659
|
+
const scope = await setupActionScope(action, timeout);
|
|
9660
|
+
if (!scope.ok) return setupScopeFailure(base, scope);
|
|
9661
|
+
const locator = scope.context.locator(action.selector);
|
|
9474
9662
|
const startedAt = Date.now();
|
|
9475
9663
|
let lastText = "";
|
|
9476
9664
|
let matchedText = "";
|
|
@@ -9489,7 +9677,7 @@ async function executeSetupAction(action, ordinal) {
|
|
|
9489
9677
|
if (type === "assert_text_visible") {
|
|
9490
9678
|
const visible = await setupLocatorVisible(locator, index);
|
|
9491
9679
|
if (visible) {
|
|
9492
|
-
return { ...base, ok: true, count, text: compactSetupResultText(text), target_index: index, timeout_ms: timeout };
|
|
9680
|
+
return { ...base, ...setupScopeEvidence(scope), ok: true, count, text: compactSetupResultText(text), target_index: index, timeout_ms: timeout };
|
|
9493
9681
|
}
|
|
9494
9682
|
hiddenMatch = true;
|
|
9495
9683
|
break;
|
|
@@ -9498,17 +9686,17 @@ async function executeSetupAction(action, ordinal) {
|
|
|
9498
9686
|
}
|
|
9499
9687
|
}
|
|
9500
9688
|
if (type === "assert_text_absent" && !matched) {
|
|
9501
|
-
return { ...base, ok: true, count, timeout_ms: timeout };
|
|
9689
|
+
return { ...base, ...setupScopeEvidence(scope), ok: true, count, timeout_ms: timeout };
|
|
9502
9690
|
}
|
|
9503
9691
|
await page.waitForTimeout(100);
|
|
9504
9692
|
}
|
|
9505
9693
|
if (type === "assert_text_visible") {
|
|
9506
9694
|
if (hiddenMatch) {
|
|
9507
|
-
return { ...base, reason: "matching_element_not_visible", text: compactSetupResultText(matchedText), timeout_ms: timeout };
|
|
9695
|
+
return { ...base, ...setupScopeEvidence(scope), reason: "matching_element_not_visible", text: compactSetupResultText(matchedText), timeout_ms: timeout };
|
|
9508
9696
|
}
|
|
9509
|
-
return { ...base, reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
|
|
9697
|
+
return { ...base, ...setupScopeEvidence(scope), reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
|
|
9510
9698
|
}
|
|
9511
|
-
return { ...base, reason: "text_still_present", text: compactSetupResultText(matchedText || lastText), timeout_ms: timeout };
|
|
9699
|
+
return { ...base, ...setupScopeEvidence(scope), reason: "text_still_present", text: compactSetupResultText(matchedText || lastText), timeout_ms: timeout };
|
|
9512
9700
|
}
|
|
9513
9701
|
return { ...base, reason: "unsupported_action" };
|
|
9514
9702
|
} catch (error) {
|
|
@@ -10111,7 +10299,7 @@ async function captureViewport(viewport) {
|
|
|
10111
10299
|
if ((check.type === "text_visible" || check.type === "text_absent") && (check.text || check.pattern)) {
|
|
10112
10300
|
text_matches[textKey(check)] = textMatches(dom.body_text || dom.body_text_sample || "", check);
|
|
10113
10301
|
}
|
|
10114
|
-
if ((check.type === "frame_text_visible" || check.type === "frame_no_horizontal_overflow") && check.selector) {
|
|
10302
|
+
if ((check.type === "frame_text_visible" || check.type === "frame_url_equals" || check.type === "frame_url_matches" || check.type === "frame_no_horizontal_overflow") && check.selector) {
|
|
10115
10303
|
selectors[check.selector] = selectors[check.selector] || await selectorStats(check.selector);
|
|
10116
10304
|
frames[check.selector] = frames[check.selector] || await frameEvidence(check.selector);
|
|
10117
10305
|
}
|
package/dist/cli.js
CHANGED