@riddledc/riddle-proof 0.7.27 → 0.7.29
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 -3
- package/dist/{chunk-FUWINYNX.js → chunk-NUGGW7NX.js} +60 -1
- package/dist/cli.cjs +60 -1
- package/dist/cli.js +1 -1
- package/dist/index.cjs +60 -1
- package/dist/index.js +1 -1
- package/dist/profile.cjs +60 -1
- package/dist/profile.d.cts +5 -1
- package/dist/profile.d.ts +5 -1
- package/dist/profile.js +1 -1
- package/dist/proof-run-core.d.cts +1 -1
- package/dist/proof-run-core.d.ts +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -109,7 +109,30 @@ or as a stronger proof base before a change loop.
|
|
|
109
109
|
{ "name": "desktop", "width": 1440, "height": 1000 }
|
|
110
110
|
],
|
|
111
111
|
"auth": "none",
|
|
112
|
+
"network_mocks": [
|
|
113
|
+
{
|
|
114
|
+
"label": "plans-api",
|
|
115
|
+
"url": "**/api/plans",
|
|
116
|
+
"method": "GET",
|
|
117
|
+
"status": 200,
|
|
118
|
+
"content_type": "application/json",
|
|
119
|
+
"json": {
|
|
120
|
+
"plans": [{ "name": "Builder", "price": "$20" }]
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
],
|
|
112
124
|
"setup_actions": [
|
|
125
|
+
{
|
|
126
|
+
"type": "local_storage",
|
|
127
|
+
"key": "demo-auth",
|
|
128
|
+
"json": { "role": "tester" },
|
|
129
|
+
"reload": true
|
|
130
|
+
},
|
|
131
|
+
{
|
|
132
|
+
"type": "fill",
|
|
133
|
+
"selector": "[data-testid='email']",
|
|
134
|
+
"value": "builder@example.com"
|
|
135
|
+
},
|
|
113
136
|
{ "type": "click", "selector": "[data-testid='show-plans']" },
|
|
114
137
|
{ "type": "wait_for_text", "selector": "body", "text": "Start building" }
|
|
115
138
|
]
|
|
@@ -145,14 +168,23 @@ The package includes a generic starter profile at
|
|
|
145
168
|
profile directory and replace the selector/text checks with app-specific
|
|
146
169
|
invariants.
|
|
147
170
|
|
|
171
|
+
`target.network_mocks` is optional. The Riddle runner registers these mocks
|
|
172
|
+
before navigation, records each hit, and adds an implicit
|
|
173
|
+
`network_mocks_succeeded` check when mocks are present. A mock supports
|
|
174
|
+
`url`/`glob`/`pattern`, optional `method`, `status`, `content_type`, `headers`,
|
|
175
|
+
string `body`, JSON `json` / `body_json`, and `required: false` for
|
|
176
|
+
best-effort mocks.
|
|
177
|
+
|
|
148
178
|
`target.setup_actions` is optional. Use it when the meaningful proof surface
|
|
149
|
-
appears only after a picker, tab, login stub,
|
|
150
|
-
bounded interaction. Supported setup actions are
|
|
179
|
+
appears only after a picker, tab, login stub, storage seed, form fill,
|
|
180
|
+
transport control, or other bounded interaction. Supported setup actions are
|
|
181
|
+
`click`, `fill`, `set_input_value`, `local_storage`, `wait`,
|
|
151
182
|
`wait_for_selector`, and `wait_for_text`; a failed setup action is recorded as
|
|
152
183
|
a failed `setup_actions_succeeded` check so the profile cannot pass without
|
|
153
184
|
reaching the intended state. Text-matched `click` actions prefer visible
|
|
154
185
|
matching elements, which keeps responsive layouts from selecting hidden desktop
|
|
155
|
-
or mobile-only links.
|
|
186
|
+
or mobile-only links. `local_storage` accepts a `key` plus string `value` or
|
|
187
|
+
JSON `json` / `value_json`, and can reload the page with `reload: true`.
|
|
156
188
|
|
|
157
189
|
`target.timeout_sec` is optional. Use it for known-heavy profile targets so the
|
|
158
190
|
profile carries its own hosted Riddle worker budget; an explicit CLI `--timeout`
|
|
@@ -22,6 +22,9 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
|
|
|
22
22
|
];
|
|
23
23
|
var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
|
|
24
24
|
"click",
|
|
25
|
+
"fill",
|
|
26
|
+
"set_input_value",
|
|
27
|
+
"local_storage",
|
|
25
28
|
"wait",
|
|
26
29
|
"wait_for_selector",
|
|
27
30
|
"wait_for_text"
|
|
@@ -35,6 +38,18 @@ function isRecord(value) {
|
|
|
35
38
|
function stringValue(value) {
|
|
36
39
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
37
40
|
}
|
|
41
|
+
function hasOwn(value, key) {
|
|
42
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
43
|
+
}
|
|
44
|
+
function stringFromOwn(input, ...keys) {
|
|
45
|
+
for (const key of keys) {
|
|
46
|
+
if (hasOwn(input, key)) {
|
|
47
|
+
const value = input[key];
|
|
48
|
+
if (value !== void 0 && value !== null) return String(value);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return void 0;
|
|
52
|
+
}
|
|
38
53
|
function numberValue(value) {
|
|
39
54
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
40
55
|
}
|
|
@@ -171,15 +186,30 @@ function normalizeSetupAction(input, index) {
|
|
|
171
186
|
if (!isRecord(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
|
|
172
187
|
const type = normalizeSetupActionType(stringValue(input.type), index);
|
|
173
188
|
const selector = stringValue(input.selector);
|
|
174
|
-
if ((type === "click" || type === "wait_for_selector" || type === "wait_for_text") && !selector) {
|
|
189
|
+
if ((type === "click" || type === "fill" || type === "set_input_value" || type === "wait_for_selector" || type === "wait_for_text") && !selector) {
|
|
175
190
|
throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
|
|
176
191
|
}
|
|
177
192
|
if (type === "wait_for_text" && !stringValue(input.text) && !stringValue(input.pattern)) {
|
|
178
193
|
throw new Error(`target.setup_actions[${index}] wait_for_text requires text or pattern.`);
|
|
179
194
|
}
|
|
195
|
+
const value = stringFromOwn(input, "value", "input_value", "inputValue");
|
|
196
|
+
const hasJsonValue = hasOwn(input, "value_json") || hasOwn(input, "valueJson") || hasOwn(input, "json");
|
|
197
|
+
if ((type === "fill" || type === "set_input_value") && value === void 0 && !hasJsonValue) {
|
|
198
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
|
|
199
|
+
}
|
|
200
|
+
const key = stringValue(input.key);
|
|
201
|
+
if (type === "local_storage" && !key) {
|
|
202
|
+
throw new Error(`target.setup_actions[${index}] local_storage requires key.`);
|
|
203
|
+
}
|
|
204
|
+
if (type === "local_storage" && value === void 0 && !hasJsonValue) {
|
|
205
|
+
throw new Error(`target.setup_actions[${index}] local_storage requires value.`);
|
|
206
|
+
}
|
|
180
207
|
return {
|
|
181
208
|
type,
|
|
182
209
|
selector,
|
|
210
|
+
key,
|
|
211
|
+
value,
|
|
212
|
+
value_json: hasJsonValue ? toJsonValue(input.value_json ?? input.valueJson ?? input.json) : void 0,
|
|
183
213
|
text: stringValue(input.text),
|
|
184
214
|
pattern: stringValue(input.pattern),
|
|
185
215
|
flags: stringValue(input.flags),
|
|
@@ -187,6 +217,7 @@ function normalizeSetupAction(input, index) {
|
|
|
187
217
|
ms: numberValue(input.ms) ?? numberValue(input.wait_ms) ?? numberValue(input.waitMs),
|
|
188
218
|
timeout_ms: numberValue(input.timeout_ms) ?? numberValue(input.timeoutMs),
|
|
189
219
|
after_ms: numberValue(input.after_ms) ?? numberValue(input.afterMs),
|
|
220
|
+
reload: input.reload === true,
|
|
190
221
|
continue_on_failure: input.continue_on_failure === true || input.continueOnFailure === true
|
|
191
222
|
};
|
|
192
223
|
}
|
|
@@ -1107,6 +1138,14 @@ function setupTextMatches(sample, action) {
|
|
|
1107
1138
|
}
|
|
1108
1139
|
return String(sample || "").includes(action.text || "");
|
|
1109
1140
|
}
|
|
1141
|
+
function setupHasOwn(action, key) {
|
|
1142
|
+
return Boolean(action) && Object.keys(action).includes(key);
|
|
1143
|
+
}
|
|
1144
|
+
function setupActionValue(action) {
|
|
1145
|
+
if (setupHasOwn(action, "value_json")) return JSON.stringify(action.value_json);
|
|
1146
|
+
if (setupHasOwn(action, "value")) return String(action.value ?? "");
|
|
1147
|
+
return "";
|
|
1148
|
+
}
|
|
1110
1149
|
async function setupLocatorText(locator, index) {
|
|
1111
1150
|
return await locator.nth(index).textContent({ timeout: 1000 }).catch(() => "");
|
|
1112
1151
|
}
|
|
@@ -1175,6 +1214,16 @@ async function executeSetupAction(action, ordinal) {
|
|
|
1175
1214
|
await page.waitForSelector(action.selector, { state: "visible", timeout });
|
|
1176
1215
|
return { ...base, ok: true, timeout_ms: timeout };
|
|
1177
1216
|
}
|
|
1217
|
+
if (type === "local_storage") {
|
|
1218
|
+
const value = setupActionValue(action);
|
|
1219
|
+
await page.evaluate(({ key, value }) => {
|
|
1220
|
+
window.localStorage.setItem(key, value);
|
|
1221
|
+
}, { key: action.key, value });
|
|
1222
|
+
if (action.reload === true) {
|
|
1223
|
+
await page.reload({ waitUntil: "domcontentloaded", timeout: 45000 });
|
|
1224
|
+
}
|
|
1225
|
+
return { ...base, ok: true, key: action.key, value_length: value.length, reload: action.reload === true };
|
|
1226
|
+
}
|
|
1178
1227
|
if (type === "click") {
|
|
1179
1228
|
const locator = page.locator(action.selector);
|
|
1180
1229
|
const count = await locator.count();
|
|
@@ -1207,6 +1256,16 @@ async function executeSetupAction(action, ordinal) {
|
|
|
1207
1256
|
await locator.nth(targetIndex).click({ timeout });
|
|
1208
1257
|
return { ...base, ok: true, count, target_index: targetIndex, text: matchedText };
|
|
1209
1258
|
}
|
|
1259
|
+
if (type === "fill" || type === "set_input_value") {
|
|
1260
|
+
const locator = page.locator(action.selector);
|
|
1261
|
+
const count = await locator.count();
|
|
1262
|
+
if (!count) return { ...base, reason: "selector_not_found", count };
|
|
1263
|
+
const targetIndex = Number.isInteger(action.index) ? action.index : 0;
|
|
1264
|
+
if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
|
|
1265
|
+
const value = setupActionValue(action);
|
|
1266
|
+
await locator.nth(targetIndex).fill(value, { timeout });
|
|
1267
|
+
return { ...base, ok: true, count, target_index: targetIndex, value_length: value.length };
|
|
1268
|
+
}
|
|
1210
1269
|
if (type === "wait_for_text") {
|
|
1211
1270
|
const locator = page.locator(action.selector);
|
|
1212
1271
|
const startedAt = Date.now();
|
package/dist/cli.cjs
CHANGED
|
@@ -6895,6 +6895,9 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
|
|
|
6895
6895
|
];
|
|
6896
6896
|
var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
|
|
6897
6897
|
"click",
|
|
6898
|
+
"fill",
|
|
6899
|
+
"set_input_value",
|
|
6900
|
+
"local_storage",
|
|
6898
6901
|
"wait",
|
|
6899
6902
|
"wait_for_selector",
|
|
6900
6903
|
"wait_for_text"
|
|
@@ -6908,6 +6911,18 @@ function isRecord(value) {
|
|
|
6908
6911
|
function stringValue2(value) {
|
|
6909
6912
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
6910
6913
|
}
|
|
6914
|
+
function hasOwn(value, key) {
|
|
6915
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
6916
|
+
}
|
|
6917
|
+
function stringFromOwn(input, ...keys) {
|
|
6918
|
+
for (const key of keys) {
|
|
6919
|
+
if (hasOwn(input, key)) {
|
|
6920
|
+
const value = input[key];
|
|
6921
|
+
if (value !== void 0 && value !== null) return String(value);
|
|
6922
|
+
}
|
|
6923
|
+
}
|
|
6924
|
+
return void 0;
|
|
6925
|
+
}
|
|
6911
6926
|
function numberValue(value) {
|
|
6912
6927
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
6913
6928
|
}
|
|
@@ -7044,15 +7059,30 @@ function normalizeSetupAction(input, index) {
|
|
|
7044
7059
|
if (!isRecord(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
|
|
7045
7060
|
const type = normalizeSetupActionType(stringValue2(input.type), index);
|
|
7046
7061
|
const selector = stringValue2(input.selector);
|
|
7047
|
-
if ((type === "click" || type === "wait_for_selector" || type === "wait_for_text") && !selector) {
|
|
7062
|
+
if ((type === "click" || type === "fill" || type === "set_input_value" || type === "wait_for_selector" || type === "wait_for_text") && !selector) {
|
|
7048
7063
|
throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
|
|
7049
7064
|
}
|
|
7050
7065
|
if (type === "wait_for_text" && !stringValue2(input.text) && !stringValue2(input.pattern)) {
|
|
7051
7066
|
throw new Error(`target.setup_actions[${index}] wait_for_text requires text or pattern.`);
|
|
7052
7067
|
}
|
|
7068
|
+
const value = stringFromOwn(input, "value", "input_value", "inputValue");
|
|
7069
|
+
const hasJsonValue = hasOwn(input, "value_json") || hasOwn(input, "valueJson") || hasOwn(input, "json");
|
|
7070
|
+
if ((type === "fill" || type === "set_input_value") && value === void 0 && !hasJsonValue) {
|
|
7071
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
|
|
7072
|
+
}
|
|
7073
|
+
const key = stringValue2(input.key);
|
|
7074
|
+
if (type === "local_storage" && !key) {
|
|
7075
|
+
throw new Error(`target.setup_actions[${index}] local_storage requires key.`);
|
|
7076
|
+
}
|
|
7077
|
+
if (type === "local_storage" && value === void 0 && !hasJsonValue) {
|
|
7078
|
+
throw new Error(`target.setup_actions[${index}] local_storage requires value.`);
|
|
7079
|
+
}
|
|
7053
7080
|
return {
|
|
7054
7081
|
type,
|
|
7055
7082
|
selector,
|
|
7083
|
+
key,
|
|
7084
|
+
value,
|
|
7085
|
+
value_json: hasJsonValue ? toJsonValue(input.value_json ?? input.valueJson ?? input.json) : void 0,
|
|
7056
7086
|
text: stringValue2(input.text),
|
|
7057
7087
|
pattern: stringValue2(input.pattern),
|
|
7058
7088
|
flags: stringValue2(input.flags),
|
|
@@ -7060,6 +7090,7 @@ function normalizeSetupAction(input, index) {
|
|
|
7060
7090
|
ms: numberValue(input.ms) ?? numberValue(input.wait_ms) ?? numberValue(input.waitMs),
|
|
7061
7091
|
timeout_ms: numberValue(input.timeout_ms) ?? numberValue(input.timeoutMs),
|
|
7062
7092
|
after_ms: numberValue(input.after_ms) ?? numberValue(input.afterMs),
|
|
7093
|
+
reload: input.reload === true,
|
|
7063
7094
|
continue_on_failure: input.continue_on_failure === true || input.continueOnFailure === true
|
|
7064
7095
|
};
|
|
7065
7096
|
}
|
|
@@ -7964,6 +7995,14 @@ function setupTextMatches(sample, action) {
|
|
|
7964
7995
|
}
|
|
7965
7996
|
return String(sample || "").includes(action.text || "");
|
|
7966
7997
|
}
|
|
7998
|
+
function setupHasOwn(action, key) {
|
|
7999
|
+
return Boolean(action) && Object.keys(action).includes(key);
|
|
8000
|
+
}
|
|
8001
|
+
function setupActionValue(action) {
|
|
8002
|
+
if (setupHasOwn(action, "value_json")) return JSON.stringify(action.value_json);
|
|
8003
|
+
if (setupHasOwn(action, "value")) return String(action.value ?? "");
|
|
8004
|
+
return "";
|
|
8005
|
+
}
|
|
7967
8006
|
async function setupLocatorText(locator, index) {
|
|
7968
8007
|
return await locator.nth(index).textContent({ timeout: 1000 }).catch(() => "");
|
|
7969
8008
|
}
|
|
@@ -8032,6 +8071,16 @@ async function executeSetupAction(action, ordinal) {
|
|
|
8032
8071
|
await page.waitForSelector(action.selector, { state: "visible", timeout });
|
|
8033
8072
|
return { ...base, ok: true, timeout_ms: timeout };
|
|
8034
8073
|
}
|
|
8074
|
+
if (type === "local_storage") {
|
|
8075
|
+
const value = setupActionValue(action);
|
|
8076
|
+
await page.evaluate(({ key, value }) => {
|
|
8077
|
+
window.localStorage.setItem(key, value);
|
|
8078
|
+
}, { key: action.key, value });
|
|
8079
|
+
if (action.reload === true) {
|
|
8080
|
+
await page.reload({ waitUntil: "domcontentloaded", timeout: 45000 });
|
|
8081
|
+
}
|
|
8082
|
+
return { ...base, ok: true, key: action.key, value_length: value.length, reload: action.reload === true };
|
|
8083
|
+
}
|
|
8035
8084
|
if (type === "click") {
|
|
8036
8085
|
const locator = page.locator(action.selector);
|
|
8037
8086
|
const count = await locator.count();
|
|
@@ -8064,6 +8113,16 @@ async function executeSetupAction(action, ordinal) {
|
|
|
8064
8113
|
await locator.nth(targetIndex).click({ timeout });
|
|
8065
8114
|
return { ...base, ok: true, count, target_index: targetIndex, text: matchedText };
|
|
8066
8115
|
}
|
|
8116
|
+
if (type === "fill" || type === "set_input_value") {
|
|
8117
|
+
const locator = page.locator(action.selector);
|
|
8118
|
+
const count = await locator.count();
|
|
8119
|
+
if (!count) return { ...base, reason: "selector_not_found", count };
|
|
8120
|
+
const targetIndex = Number.isInteger(action.index) ? action.index : 0;
|
|
8121
|
+
if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
|
|
8122
|
+
const value = setupActionValue(action);
|
|
8123
|
+
await locator.nth(targetIndex).fill(value, { timeout });
|
|
8124
|
+
return { ...base, ok: true, count, target_index: targetIndex, value_length: value.length };
|
|
8125
|
+
}
|
|
8067
8126
|
if (type === "wait_for_text") {
|
|
8068
8127
|
const locator = page.locator(action.selector);
|
|
8069
8128
|
const startedAt = Date.now();
|
package/dist/cli.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -8736,6 +8736,9 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
|
|
|
8736
8736
|
];
|
|
8737
8737
|
var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
|
|
8738
8738
|
"click",
|
|
8739
|
+
"fill",
|
|
8740
|
+
"set_input_value",
|
|
8741
|
+
"local_storage",
|
|
8739
8742
|
"wait",
|
|
8740
8743
|
"wait_for_selector",
|
|
8741
8744
|
"wait_for_text"
|
|
@@ -8749,6 +8752,18 @@ function isRecord2(value) {
|
|
|
8749
8752
|
function stringValue5(value) {
|
|
8750
8753
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
8751
8754
|
}
|
|
8755
|
+
function hasOwn(value, key) {
|
|
8756
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
8757
|
+
}
|
|
8758
|
+
function stringFromOwn(input, ...keys) {
|
|
8759
|
+
for (const key of keys) {
|
|
8760
|
+
if (hasOwn(input, key)) {
|
|
8761
|
+
const value = input[key];
|
|
8762
|
+
if (value !== void 0 && value !== null) return String(value);
|
|
8763
|
+
}
|
|
8764
|
+
}
|
|
8765
|
+
return void 0;
|
|
8766
|
+
}
|
|
8752
8767
|
function numberValue3(value) {
|
|
8753
8768
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
8754
8769
|
}
|
|
@@ -8885,15 +8900,30 @@ function normalizeSetupAction(input, index) {
|
|
|
8885
8900
|
if (!isRecord2(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
|
|
8886
8901
|
const type = normalizeSetupActionType(stringValue5(input.type), index);
|
|
8887
8902
|
const selector = stringValue5(input.selector);
|
|
8888
|
-
if ((type === "click" || type === "wait_for_selector" || type === "wait_for_text") && !selector) {
|
|
8903
|
+
if ((type === "click" || type === "fill" || type === "set_input_value" || type === "wait_for_selector" || type === "wait_for_text") && !selector) {
|
|
8889
8904
|
throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
|
|
8890
8905
|
}
|
|
8891
8906
|
if (type === "wait_for_text" && !stringValue5(input.text) && !stringValue5(input.pattern)) {
|
|
8892
8907
|
throw new Error(`target.setup_actions[${index}] wait_for_text requires text or pattern.`);
|
|
8893
8908
|
}
|
|
8909
|
+
const value = stringFromOwn(input, "value", "input_value", "inputValue");
|
|
8910
|
+
const hasJsonValue = hasOwn(input, "value_json") || hasOwn(input, "valueJson") || hasOwn(input, "json");
|
|
8911
|
+
if ((type === "fill" || type === "set_input_value") && value === void 0 && !hasJsonValue) {
|
|
8912
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
|
|
8913
|
+
}
|
|
8914
|
+
const key = stringValue5(input.key);
|
|
8915
|
+
if (type === "local_storage" && !key) {
|
|
8916
|
+
throw new Error(`target.setup_actions[${index}] local_storage requires key.`);
|
|
8917
|
+
}
|
|
8918
|
+
if (type === "local_storage" && value === void 0 && !hasJsonValue) {
|
|
8919
|
+
throw new Error(`target.setup_actions[${index}] local_storage requires value.`);
|
|
8920
|
+
}
|
|
8894
8921
|
return {
|
|
8895
8922
|
type,
|
|
8896
8923
|
selector,
|
|
8924
|
+
key,
|
|
8925
|
+
value,
|
|
8926
|
+
value_json: hasJsonValue ? toJsonValue(input.value_json ?? input.valueJson ?? input.json) : void 0,
|
|
8897
8927
|
text: stringValue5(input.text),
|
|
8898
8928
|
pattern: stringValue5(input.pattern),
|
|
8899
8929
|
flags: stringValue5(input.flags),
|
|
@@ -8901,6 +8931,7 @@ function normalizeSetupAction(input, index) {
|
|
|
8901
8931
|
ms: numberValue3(input.ms) ?? numberValue3(input.wait_ms) ?? numberValue3(input.waitMs),
|
|
8902
8932
|
timeout_ms: numberValue3(input.timeout_ms) ?? numberValue3(input.timeoutMs),
|
|
8903
8933
|
after_ms: numberValue3(input.after_ms) ?? numberValue3(input.afterMs),
|
|
8934
|
+
reload: input.reload === true,
|
|
8904
8935
|
continue_on_failure: input.continue_on_failure === true || input.continueOnFailure === true
|
|
8905
8936
|
};
|
|
8906
8937
|
}
|
|
@@ -9821,6 +9852,14 @@ function setupTextMatches(sample, action) {
|
|
|
9821
9852
|
}
|
|
9822
9853
|
return String(sample || "").includes(action.text || "");
|
|
9823
9854
|
}
|
|
9855
|
+
function setupHasOwn(action, key) {
|
|
9856
|
+
return Boolean(action) && Object.keys(action).includes(key);
|
|
9857
|
+
}
|
|
9858
|
+
function setupActionValue(action) {
|
|
9859
|
+
if (setupHasOwn(action, "value_json")) return JSON.stringify(action.value_json);
|
|
9860
|
+
if (setupHasOwn(action, "value")) return String(action.value ?? "");
|
|
9861
|
+
return "";
|
|
9862
|
+
}
|
|
9824
9863
|
async function setupLocatorText(locator, index) {
|
|
9825
9864
|
return await locator.nth(index).textContent({ timeout: 1000 }).catch(() => "");
|
|
9826
9865
|
}
|
|
@@ -9889,6 +9928,16 @@ async function executeSetupAction(action, ordinal) {
|
|
|
9889
9928
|
await page.waitForSelector(action.selector, { state: "visible", timeout });
|
|
9890
9929
|
return { ...base, ok: true, timeout_ms: timeout };
|
|
9891
9930
|
}
|
|
9931
|
+
if (type === "local_storage") {
|
|
9932
|
+
const value = setupActionValue(action);
|
|
9933
|
+
await page.evaluate(({ key, value }) => {
|
|
9934
|
+
window.localStorage.setItem(key, value);
|
|
9935
|
+
}, { key: action.key, value });
|
|
9936
|
+
if (action.reload === true) {
|
|
9937
|
+
await page.reload({ waitUntil: "domcontentloaded", timeout: 45000 });
|
|
9938
|
+
}
|
|
9939
|
+
return { ...base, ok: true, key: action.key, value_length: value.length, reload: action.reload === true };
|
|
9940
|
+
}
|
|
9892
9941
|
if (type === "click") {
|
|
9893
9942
|
const locator = page.locator(action.selector);
|
|
9894
9943
|
const count = await locator.count();
|
|
@@ -9921,6 +9970,16 @@ async function executeSetupAction(action, ordinal) {
|
|
|
9921
9970
|
await locator.nth(targetIndex).click({ timeout });
|
|
9922
9971
|
return { ...base, ok: true, count, target_index: targetIndex, text: matchedText };
|
|
9923
9972
|
}
|
|
9973
|
+
if (type === "fill" || type === "set_input_value") {
|
|
9974
|
+
const locator = page.locator(action.selector);
|
|
9975
|
+
const count = await locator.count();
|
|
9976
|
+
if (!count) return { ...base, reason: "selector_not_found", count };
|
|
9977
|
+
const targetIndex = Number.isInteger(action.index) ? action.index : 0;
|
|
9978
|
+
if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
|
|
9979
|
+
const value = setupActionValue(action);
|
|
9980
|
+
await locator.nth(targetIndex).fill(value, { timeout });
|
|
9981
|
+
return { ...base, ok: true, count, target_index: targetIndex, value_length: value.length };
|
|
9982
|
+
}
|
|
9924
9983
|
if (type === "wait_for_text") {
|
|
9925
9984
|
const locator = page.locator(action.selector);
|
|
9926
9985
|
const startedAt = Date.now();
|
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-NUGGW7NX.js";
|
|
62
62
|
import {
|
|
63
63
|
DEFAULT_RIDDLE_API_BASE_URL,
|
|
64
64
|
DEFAULT_RIDDLE_API_KEY_FILE,
|
package/dist/profile.cjs
CHANGED
|
@@ -65,6 +65,9 @@ var RIDDLE_PROOF_PROFILE_CHECK_TYPES = [
|
|
|
65
65
|
];
|
|
66
66
|
var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
|
|
67
67
|
"click",
|
|
68
|
+
"fill",
|
|
69
|
+
"set_input_value",
|
|
70
|
+
"local_storage",
|
|
68
71
|
"wait",
|
|
69
72
|
"wait_for_selector",
|
|
70
73
|
"wait_for_text"
|
|
@@ -78,6 +81,18 @@ function isRecord(value) {
|
|
|
78
81
|
function stringValue(value) {
|
|
79
82
|
return typeof value === "string" && value.trim() ? value.trim() : void 0;
|
|
80
83
|
}
|
|
84
|
+
function hasOwn(value, key) {
|
|
85
|
+
return Object.prototype.hasOwnProperty.call(value, key);
|
|
86
|
+
}
|
|
87
|
+
function stringFromOwn(input, ...keys) {
|
|
88
|
+
for (const key of keys) {
|
|
89
|
+
if (hasOwn(input, key)) {
|
|
90
|
+
const value = input[key];
|
|
91
|
+
if (value !== void 0 && value !== null) return String(value);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
return void 0;
|
|
95
|
+
}
|
|
81
96
|
function numberValue(value) {
|
|
82
97
|
return typeof value === "number" && Number.isFinite(value) ? value : void 0;
|
|
83
98
|
}
|
|
@@ -214,15 +229,30 @@ function normalizeSetupAction(input, index) {
|
|
|
214
229
|
if (!isRecord(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
|
|
215
230
|
const type = normalizeSetupActionType(stringValue(input.type), index);
|
|
216
231
|
const selector = stringValue(input.selector);
|
|
217
|
-
if ((type === "click" || type === "wait_for_selector" || type === "wait_for_text") && !selector) {
|
|
232
|
+
if ((type === "click" || type === "fill" || type === "set_input_value" || type === "wait_for_selector" || type === "wait_for_text") && !selector) {
|
|
218
233
|
throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
|
|
219
234
|
}
|
|
220
235
|
if (type === "wait_for_text" && !stringValue(input.text) && !stringValue(input.pattern)) {
|
|
221
236
|
throw new Error(`target.setup_actions[${index}] wait_for_text requires text or pattern.`);
|
|
222
237
|
}
|
|
238
|
+
const value = stringFromOwn(input, "value", "input_value", "inputValue");
|
|
239
|
+
const hasJsonValue = hasOwn(input, "value_json") || hasOwn(input, "valueJson") || hasOwn(input, "json");
|
|
240
|
+
if ((type === "fill" || type === "set_input_value") && value === void 0 && !hasJsonValue) {
|
|
241
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires value.`);
|
|
242
|
+
}
|
|
243
|
+
const key = stringValue(input.key);
|
|
244
|
+
if (type === "local_storage" && !key) {
|
|
245
|
+
throw new Error(`target.setup_actions[${index}] local_storage requires key.`);
|
|
246
|
+
}
|
|
247
|
+
if (type === "local_storage" && value === void 0 && !hasJsonValue) {
|
|
248
|
+
throw new Error(`target.setup_actions[${index}] local_storage requires value.`);
|
|
249
|
+
}
|
|
223
250
|
return {
|
|
224
251
|
type,
|
|
225
252
|
selector,
|
|
253
|
+
key,
|
|
254
|
+
value,
|
|
255
|
+
value_json: hasJsonValue ? toJsonValue(input.value_json ?? input.valueJson ?? input.json) : void 0,
|
|
226
256
|
text: stringValue(input.text),
|
|
227
257
|
pattern: stringValue(input.pattern),
|
|
228
258
|
flags: stringValue(input.flags),
|
|
@@ -230,6 +260,7 @@ function normalizeSetupAction(input, index) {
|
|
|
230
260
|
ms: numberValue(input.ms) ?? numberValue(input.wait_ms) ?? numberValue(input.waitMs),
|
|
231
261
|
timeout_ms: numberValue(input.timeout_ms) ?? numberValue(input.timeoutMs),
|
|
232
262
|
after_ms: numberValue(input.after_ms) ?? numberValue(input.afterMs),
|
|
263
|
+
reload: input.reload === true,
|
|
233
264
|
continue_on_failure: input.continue_on_failure === true || input.continueOnFailure === true
|
|
234
265
|
};
|
|
235
266
|
}
|
|
@@ -1150,6 +1181,14 @@ function setupTextMatches(sample, action) {
|
|
|
1150
1181
|
}
|
|
1151
1182
|
return String(sample || "").includes(action.text || "");
|
|
1152
1183
|
}
|
|
1184
|
+
function setupHasOwn(action, key) {
|
|
1185
|
+
return Boolean(action) && Object.keys(action).includes(key);
|
|
1186
|
+
}
|
|
1187
|
+
function setupActionValue(action) {
|
|
1188
|
+
if (setupHasOwn(action, "value_json")) return JSON.stringify(action.value_json);
|
|
1189
|
+
if (setupHasOwn(action, "value")) return String(action.value ?? "");
|
|
1190
|
+
return "";
|
|
1191
|
+
}
|
|
1153
1192
|
async function setupLocatorText(locator, index) {
|
|
1154
1193
|
return await locator.nth(index).textContent({ timeout: 1000 }).catch(() => "");
|
|
1155
1194
|
}
|
|
@@ -1218,6 +1257,16 @@ async function executeSetupAction(action, ordinal) {
|
|
|
1218
1257
|
await page.waitForSelector(action.selector, { state: "visible", timeout });
|
|
1219
1258
|
return { ...base, ok: true, timeout_ms: timeout };
|
|
1220
1259
|
}
|
|
1260
|
+
if (type === "local_storage") {
|
|
1261
|
+
const value = setupActionValue(action);
|
|
1262
|
+
await page.evaluate(({ key, value }) => {
|
|
1263
|
+
window.localStorage.setItem(key, value);
|
|
1264
|
+
}, { key: action.key, value });
|
|
1265
|
+
if (action.reload === true) {
|
|
1266
|
+
await page.reload({ waitUntil: "domcontentloaded", timeout: 45000 });
|
|
1267
|
+
}
|
|
1268
|
+
return { ...base, ok: true, key: action.key, value_length: value.length, reload: action.reload === true };
|
|
1269
|
+
}
|
|
1221
1270
|
if (type === "click") {
|
|
1222
1271
|
const locator = page.locator(action.selector);
|
|
1223
1272
|
const count = await locator.count();
|
|
@@ -1250,6 +1299,16 @@ async function executeSetupAction(action, ordinal) {
|
|
|
1250
1299
|
await locator.nth(targetIndex).click({ timeout });
|
|
1251
1300
|
return { ...base, ok: true, count, target_index: targetIndex, text: matchedText };
|
|
1252
1301
|
}
|
|
1302
|
+
if (type === "fill" || type === "set_input_value") {
|
|
1303
|
+
const locator = page.locator(action.selector);
|
|
1304
|
+
const count = await locator.count();
|
|
1305
|
+
if (!count) return { ...base, reason: "selector_not_found", count };
|
|
1306
|
+
const targetIndex = Number.isInteger(action.index) ? action.index : 0;
|
|
1307
|
+
if (targetIndex < 0 || targetIndex >= count) return { ...base, reason: "index_out_of_range", count, target_index: targetIndex };
|
|
1308
|
+
const value = setupActionValue(action);
|
|
1309
|
+
await locator.nth(targetIndex).fill(value, { timeout });
|
|
1310
|
+
return { ...base, ok: true, count, target_index: targetIndex, value_length: value.length };
|
|
1311
|
+
}
|
|
1253
1312
|
if (type === "wait_for_text") {
|
|
1254
1313
|
const locator = page.locator(action.selector);
|
|
1255
1314
|
const startedAt = Date.now();
|
package/dist/profile.d.cts
CHANGED
|
@@ -5,7 +5,7 @@ declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evide
|
|
|
5
5
|
declare const RIDDLE_PROOF_PROFILE_RESULT_VERSION: "riddle-proof.profile-result.v1";
|
|
6
6
|
declare const RIDDLE_PROOF_PROFILE_STATUSES: readonly ["passed", "product_regression", "proof_insufficient", "environment_blocked", "configuration_error", "needs_human_review"];
|
|
7
7
|
declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "selector_visible", "selector_count_at_least", "text_visible", "text_absent", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
|
|
8
|
-
declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "wait", "wait_for_selector", "wait_for_text"];
|
|
8
|
+
declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "fill", "set_input_value", "local_storage", "wait", "wait_for_selector", "wait_for_text"];
|
|
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];
|
|
@@ -20,6 +20,9 @@ interface RiddleProofProfileViewport {
|
|
|
20
20
|
interface RiddleProofProfileSetupAction {
|
|
21
21
|
type: RiddleProofProfileSetupActionType;
|
|
22
22
|
selector?: string;
|
|
23
|
+
key?: string;
|
|
24
|
+
value?: string;
|
|
25
|
+
value_json?: JsonValue;
|
|
23
26
|
text?: string;
|
|
24
27
|
pattern?: string;
|
|
25
28
|
flags?: string;
|
|
@@ -27,6 +30,7 @@ interface RiddleProofProfileSetupAction {
|
|
|
27
30
|
ms?: number;
|
|
28
31
|
timeout_ms?: number;
|
|
29
32
|
after_ms?: number;
|
|
33
|
+
reload?: boolean;
|
|
30
34
|
continue_on_failure?: boolean;
|
|
31
35
|
}
|
|
32
36
|
interface RiddleProofProfileNetworkMock {
|
package/dist/profile.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ declare const RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION: "riddle-proof.profile-evide
|
|
|
5
5
|
declare const RIDDLE_PROOF_PROFILE_RESULT_VERSION: "riddle-proof.profile-result.v1";
|
|
6
6
|
declare const RIDDLE_PROOF_PROFILE_STATUSES: readonly ["passed", "product_regression", "proof_insufficient", "environment_blocked", "configuration_error", "needs_human_review"];
|
|
7
7
|
declare const RIDDLE_PROOF_PROFILE_CHECK_TYPES: readonly ["route_loaded", "selector_visible", "selector_count_at_least", "text_visible", "text_absent", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
|
|
8
|
-
declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "wait", "wait_for_selector", "wait_for_text"];
|
|
8
|
+
declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "fill", "set_input_value", "local_storage", "wait", "wait_for_selector", "wait_for_text"];
|
|
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];
|
|
@@ -20,6 +20,9 @@ interface RiddleProofProfileViewport {
|
|
|
20
20
|
interface RiddleProofProfileSetupAction {
|
|
21
21
|
type: RiddleProofProfileSetupActionType;
|
|
22
22
|
selector?: string;
|
|
23
|
+
key?: string;
|
|
24
|
+
value?: string;
|
|
25
|
+
value_json?: JsonValue;
|
|
23
26
|
text?: string;
|
|
24
27
|
pattern?: string;
|
|
25
28
|
flags?: string;
|
|
@@ -27,6 +30,7 @@ interface RiddleProofProfileSetupAction {
|
|
|
27
30
|
ms?: number;
|
|
28
31
|
timeout_ms?: number;
|
|
29
32
|
after_ms?: number;
|
|
33
|
+
reload?: boolean;
|
|
30
34
|
continue_on_failure?: boolean;
|
|
31
35
|
}
|
|
32
36
|
interface RiddleProofProfileNetworkMock {
|
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-NUGGW7NX.js";
|
|
23
23
|
export {
|
|
24
24
|
RIDDLE_PROOF_PROFILE_CHECK_TYPES,
|
|
25
25
|
RIDDLE_PROOF_PROFILE_EVIDENCE_VERSION,
|
|
@@ -120,7 +120,7 @@ declare function buildSetupArgs(params: WorkflowParams, config: ReturnType<typeo
|
|
|
120
120
|
target_image_hash: string;
|
|
121
121
|
viewport_matrix_json: string;
|
|
122
122
|
deterministic_setup_json: string;
|
|
123
|
-
reference: "
|
|
123
|
+
reference: "prod" | "before" | "both";
|
|
124
124
|
base_branch: string;
|
|
125
125
|
before_ref: string;
|
|
126
126
|
allow_static_preview_fallback: string;
|
package/dist/proof-run-core.d.ts
CHANGED
|
@@ -120,7 +120,7 @@ declare function buildSetupArgs(params: WorkflowParams, config: ReturnType<typeo
|
|
|
120
120
|
target_image_hash: string;
|
|
121
121
|
viewport_matrix_json: string;
|
|
122
122
|
deterministic_setup_json: string;
|
|
123
|
-
reference: "
|
|
123
|
+
reference: "prod" | "before" | "both";
|
|
124
124
|
base_branch: string;
|
|
125
125
|
before_ref: string;
|
|
126
126
|
allow_static_preview_fallback: string;
|