@riddledc/riddle-proof 0.7.47 → 0.7.48
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 +15 -10
- package/dist/{chunk-NJDY7HYE.js → chunk-V2KNQTQD.js} +66 -1
- package/dist/cli.cjs +66 -1
- package/dist/cli.js +1 -1
- package/dist/index.cjs +66 -1
- package/dist/index.js +1 -1
- package/dist/profile.cjs +66 -1
- package/dist/profile.d.cts +2 -1
- package/dist/profile.d.ts +2 -1
- 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
|
@@ -237,16 +237,21 @@ where the second request must carry newer state.
|
|
|
237
237
|
`target.setup_actions` is optional. Use it when the meaningful proof surface
|
|
238
238
|
appears only after a picker, tab, login stub, storage seed, form fill,
|
|
239
239
|
transport control, or other bounded interaction. Supported setup actions are
|
|
240
|
-
`click`, `fill`, `set_input_value`, `
|
|
241
|
-
`
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
240
|
+
`click`, `fill`, `set_input_value`, `assert_text_visible`,
|
|
241
|
+
`assert_text_absent`, `assert_selector_count`, `local_storage`,
|
|
242
|
+
`session_storage`, `clear_storage`, `wait`, `wait_for_selector`, and
|
|
243
|
+
`wait_for_text`; a failed setup action is recorded as a failed
|
|
244
|
+
`setup_actions_succeeded` check so the profile cannot pass without reaching
|
|
245
|
+
the intended state. Text-matched `click` actions prefer visible matching
|
|
246
|
+
elements, which keeps responsive layouts from selecting hidden desktop or
|
|
247
|
+
mobile-only links. Use setup assertions when the pre-click or pre-navigation
|
|
248
|
+
state is part of the contract, for example a fresh row must be present, stale
|
|
249
|
+
copy must be absent, or exactly one source link must exist before clicking into
|
|
250
|
+
the final route. `assert_selector_count` accepts `expected_count`.
|
|
251
|
+
`local_storage` and `session_storage` accept a `key` plus string `value` or
|
|
252
|
+
JSON `json` / `value_json`, and can reload the page with `reload: true`.
|
|
253
|
+
`clear_storage` clears `local`, `session`, or `both` browser storage scopes,
|
|
254
|
+
defaults to `both`, and can also reload with `reload: true`.
|
|
250
255
|
|
|
251
256
|
`target.timeout_sec` is optional. Use it for known-heavy profile targets so the
|
|
252
257
|
profile carries its own hosted Riddle worker budget; an explicit CLI `--timeout`
|
|
@@ -32,6 +32,9 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
|
|
|
32
32
|
"click",
|
|
33
33
|
"fill",
|
|
34
34
|
"set_input_value",
|
|
35
|
+
"assert_text_visible",
|
|
36
|
+
"assert_text_absent",
|
|
37
|
+
"assert_selector_count",
|
|
35
38
|
"local_storage",
|
|
36
39
|
"session_storage",
|
|
37
40
|
"clear_storage",
|
|
@@ -205,12 +208,19 @@ function normalizeSetupAction(input, index) {
|
|
|
205
208
|
if (!isRecord(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
|
|
206
209
|
const type = normalizeSetupActionType(stringValue(input.type), index);
|
|
207
210
|
const selector = stringValue(input.selector);
|
|
208
|
-
if ((type === "click" || type === "fill" || type === "set_input_value" || type === "wait_for_selector" || type === "wait_for_text") && !selector) {
|
|
211
|
+
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) {
|
|
209
212
|
throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
|
|
210
213
|
}
|
|
211
214
|
if (type === "wait_for_text" && !stringValue(input.text) && !stringValue(input.pattern)) {
|
|
212
215
|
throw new Error(`target.setup_actions[${index}] wait_for_text requires text or pattern.`);
|
|
213
216
|
}
|
|
217
|
+
if ((type === "assert_text_visible" || type === "assert_text_absent") && !stringValue(input.text) && !stringValue(input.pattern)) {
|
|
218
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires text or pattern.`);
|
|
219
|
+
}
|
|
220
|
+
const expectedCount = numberValue(input.expected_count ?? input.expectedCount ?? input.count);
|
|
221
|
+
if (type === "assert_selector_count" && (expectedCount === void 0 || !Number.isInteger(expectedCount) || expectedCount < 0)) {
|
|
222
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires non-negative integer expected_count.`);
|
|
223
|
+
}
|
|
214
224
|
const value = stringFromOwn(input, "value", "input_value", "inputValue");
|
|
215
225
|
const hasJsonValue = hasOwn(input, "value_json") || hasOwn(input, "valueJson") || hasOwn(input, "json");
|
|
216
226
|
if ((type === "fill" || type === "set_input_value") && value === void 0 && !hasJsonValue) {
|
|
@@ -233,6 +243,7 @@ function normalizeSetupAction(input, index) {
|
|
|
233
243
|
pattern: stringValue(input.pattern),
|
|
234
244
|
flags: stringValue(input.flags),
|
|
235
245
|
index: numberValue(input.index),
|
|
246
|
+
expected_count: expectedCount,
|
|
236
247
|
ms: numberValue(input.ms) ?? numberValue(input.wait_ms) ?? numberValue(input.waitMs),
|
|
237
248
|
timeout_ms: numberValue(input.timeout_ms) ?? numberValue(input.timeoutMs),
|
|
238
249
|
after_ms: numberValue(input.after_ms) ?? numberValue(input.afterMs),
|
|
@@ -2150,6 +2161,19 @@ async function executeSetupAction(action, ordinal) {
|
|
|
2150
2161
|
await locator.nth(targetIndex).fill(value, { timeout });
|
|
2151
2162
|
return { ...base, ok: true, count, target_index: targetIndex, value_length: value.length };
|
|
2152
2163
|
}
|
|
2164
|
+
if (type === "assert_selector_count") {
|
|
2165
|
+
const locator = page.locator(action.selector);
|
|
2166
|
+
const expectedCount = setupNumber(action.expected_count, -1);
|
|
2167
|
+
if (!Number.isInteger(expectedCount) || expectedCount < 0) return { ...base, reason: "invalid_expected_count", expected_count: action.expected_count };
|
|
2168
|
+
const startedAt = Date.now();
|
|
2169
|
+
let count = 0;
|
|
2170
|
+
while (Date.now() - startedAt <= timeout) {
|
|
2171
|
+
count = await locator.count().catch(() => 0);
|
|
2172
|
+
if (count === expectedCount) return { ...base, ok: true, count, expected_count: expectedCount, timeout_ms: timeout };
|
|
2173
|
+
await page.waitForTimeout(100);
|
|
2174
|
+
}
|
|
2175
|
+
return { ...base, reason: "selector_count_mismatch", count, expected_count: expectedCount, timeout_ms: timeout };
|
|
2176
|
+
}
|
|
2153
2177
|
if (type === "wait_for_text") {
|
|
2154
2178
|
const locator = page.locator(action.selector);
|
|
2155
2179
|
const startedAt = Date.now();
|
|
@@ -2167,6 +2191,47 @@ async function executeSetupAction(action, ordinal) {
|
|
|
2167
2191
|
}
|
|
2168
2192
|
return { ...base, reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
|
|
2169
2193
|
}
|
|
2194
|
+
if (type === "assert_text_visible" || type === "assert_text_absent") {
|
|
2195
|
+
const locator = page.locator(action.selector);
|
|
2196
|
+
const startedAt = Date.now();
|
|
2197
|
+
let lastText = "";
|
|
2198
|
+
let matchedText = "";
|
|
2199
|
+
let hiddenMatch = false;
|
|
2200
|
+
while (Date.now() - startedAt <= timeout) {
|
|
2201
|
+
const count = await locator.count().catch(() => 0);
|
|
2202
|
+
let matched = false;
|
|
2203
|
+
matchedText = "";
|
|
2204
|
+
hiddenMatch = false;
|
|
2205
|
+
for (let index = 0; index < count; index += 1) {
|
|
2206
|
+
const text = await setupLocatorText(locator, index);
|
|
2207
|
+
lastText = text || lastText;
|
|
2208
|
+
if (setupTextMatches(text, action)) {
|
|
2209
|
+
matched = true;
|
|
2210
|
+
matchedText = text;
|
|
2211
|
+
if (type === "assert_text_visible") {
|
|
2212
|
+
const visible = await setupLocatorVisible(locator, index);
|
|
2213
|
+
if (visible) {
|
|
2214
|
+
return { ...base, ok: true, count, text: compactSetupResultText(text), target_index: index, timeout_ms: timeout };
|
|
2215
|
+
}
|
|
2216
|
+
hiddenMatch = true;
|
|
2217
|
+
break;
|
|
2218
|
+
}
|
|
2219
|
+
break;
|
|
2220
|
+
}
|
|
2221
|
+
}
|
|
2222
|
+
if (type === "assert_text_absent" && !matched) {
|
|
2223
|
+
return { ...base, ok: true, count, timeout_ms: timeout };
|
|
2224
|
+
}
|
|
2225
|
+
await page.waitForTimeout(100);
|
|
2226
|
+
}
|
|
2227
|
+
if (type === "assert_text_visible") {
|
|
2228
|
+
if (hiddenMatch) {
|
|
2229
|
+
return { ...base, reason: "matching_element_not_visible", text: compactSetupResultText(matchedText), timeout_ms: timeout };
|
|
2230
|
+
}
|
|
2231
|
+
return { ...base, reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
|
|
2232
|
+
}
|
|
2233
|
+
return { ...base, reason: "text_still_present", text: compactSetupResultText(matchedText || lastText), timeout_ms: timeout };
|
|
2234
|
+
}
|
|
2170
2235
|
return { ...base, reason: "unsupported_action" };
|
|
2171
2236
|
} catch (error) {
|
|
2172
2237
|
return { ...base, error: String(error && error.message ? error.message : error).slice(0, 1000) };
|
package/dist/cli.cjs
CHANGED
|
@@ -6905,6 +6905,9 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
|
|
|
6905
6905
|
"click",
|
|
6906
6906
|
"fill",
|
|
6907
6907
|
"set_input_value",
|
|
6908
|
+
"assert_text_visible",
|
|
6909
|
+
"assert_text_absent",
|
|
6910
|
+
"assert_selector_count",
|
|
6908
6911
|
"local_storage",
|
|
6909
6912
|
"session_storage",
|
|
6910
6913
|
"clear_storage",
|
|
@@ -7078,12 +7081,19 @@ function normalizeSetupAction(input, index) {
|
|
|
7078
7081
|
if (!isRecord(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
|
|
7079
7082
|
const type = normalizeSetupActionType(stringValue2(input.type), index);
|
|
7080
7083
|
const selector = stringValue2(input.selector);
|
|
7081
|
-
if ((type === "click" || type === "fill" || type === "set_input_value" || type === "wait_for_selector" || type === "wait_for_text") && !selector) {
|
|
7084
|
+
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) {
|
|
7082
7085
|
throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
|
|
7083
7086
|
}
|
|
7084
7087
|
if (type === "wait_for_text" && !stringValue2(input.text) && !stringValue2(input.pattern)) {
|
|
7085
7088
|
throw new Error(`target.setup_actions[${index}] wait_for_text requires text or pattern.`);
|
|
7086
7089
|
}
|
|
7090
|
+
if ((type === "assert_text_visible" || type === "assert_text_absent") && !stringValue2(input.text) && !stringValue2(input.pattern)) {
|
|
7091
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires text or pattern.`);
|
|
7092
|
+
}
|
|
7093
|
+
const expectedCount = numberValue(input.expected_count ?? input.expectedCount ?? input.count);
|
|
7094
|
+
if (type === "assert_selector_count" && (expectedCount === void 0 || !Number.isInteger(expectedCount) || expectedCount < 0)) {
|
|
7095
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires non-negative integer expected_count.`);
|
|
7096
|
+
}
|
|
7087
7097
|
const value = stringFromOwn(input, "value", "input_value", "inputValue");
|
|
7088
7098
|
const hasJsonValue = hasOwn(input, "value_json") || hasOwn(input, "valueJson") || hasOwn(input, "json");
|
|
7089
7099
|
if ((type === "fill" || type === "set_input_value") && value === void 0 && !hasJsonValue) {
|
|
@@ -7106,6 +7116,7 @@ function normalizeSetupAction(input, index) {
|
|
|
7106
7116
|
pattern: stringValue2(input.pattern),
|
|
7107
7117
|
flags: stringValue2(input.flags),
|
|
7108
7118
|
index: numberValue(input.index),
|
|
7119
|
+
expected_count: expectedCount,
|
|
7109
7120
|
ms: numberValue(input.ms) ?? numberValue(input.wait_ms) ?? numberValue(input.waitMs),
|
|
7110
7121
|
timeout_ms: numberValue(input.timeout_ms) ?? numberValue(input.timeoutMs),
|
|
7111
7122
|
after_ms: numberValue(input.after_ms) ?? numberValue(input.afterMs),
|
|
@@ -9007,6 +9018,19 @@ async function executeSetupAction(action, ordinal) {
|
|
|
9007
9018
|
await locator.nth(targetIndex).fill(value, { timeout });
|
|
9008
9019
|
return { ...base, ok: true, count, target_index: targetIndex, value_length: value.length };
|
|
9009
9020
|
}
|
|
9021
|
+
if (type === "assert_selector_count") {
|
|
9022
|
+
const locator = page.locator(action.selector);
|
|
9023
|
+
const expectedCount = setupNumber(action.expected_count, -1);
|
|
9024
|
+
if (!Number.isInteger(expectedCount) || expectedCount < 0) return { ...base, reason: "invalid_expected_count", expected_count: action.expected_count };
|
|
9025
|
+
const startedAt = Date.now();
|
|
9026
|
+
let count = 0;
|
|
9027
|
+
while (Date.now() - startedAt <= timeout) {
|
|
9028
|
+
count = await locator.count().catch(() => 0);
|
|
9029
|
+
if (count === expectedCount) return { ...base, ok: true, count, expected_count: expectedCount, timeout_ms: timeout };
|
|
9030
|
+
await page.waitForTimeout(100);
|
|
9031
|
+
}
|
|
9032
|
+
return { ...base, reason: "selector_count_mismatch", count, expected_count: expectedCount, timeout_ms: timeout };
|
|
9033
|
+
}
|
|
9010
9034
|
if (type === "wait_for_text") {
|
|
9011
9035
|
const locator = page.locator(action.selector);
|
|
9012
9036
|
const startedAt = Date.now();
|
|
@@ -9024,6 +9048,47 @@ async function executeSetupAction(action, ordinal) {
|
|
|
9024
9048
|
}
|
|
9025
9049
|
return { ...base, reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
|
|
9026
9050
|
}
|
|
9051
|
+
if (type === "assert_text_visible" || type === "assert_text_absent") {
|
|
9052
|
+
const locator = page.locator(action.selector);
|
|
9053
|
+
const startedAt = Date.now();
|
|
9054
|
+
let lastText = "";
|
|
9055
|
+
let matchedText = "";
|
|
9056
|
+
let hiddenMatch = false;
|
|
9057
|
+
while (Date.now() - startedAt <= timeout) {
|
|
9058
|
+
const count = await locator.count().catch(() => 0);
|
|
9059
|
+
let matched = false;
|
|
9060
|
+
matchedText = "";
|
|
9061
|
+
hiddenMatch = false;
|
|
9062
|
+
for (let index = 0; index < count; index += 1) {
|
|
9063
|
+
const text = await setupLocatorText(locator, index);
|
|
9064
|
+
lastText = text || lastText;
|
|
9065
|
+
if (setupTextMatches(text, action)) {
|
|
9066
|
+
matched = true;
|
|
9067
|
+
matchedText = text;
|
|
9068
|
+
if (type === "assert_text_visible") {
|
|
9069
|
+
const visible = await setupLocatorVisible(locator, index);
|
|
9070
|
+
if (visible) {
|
|
9071
|
+
return { ...base, ok: true, count, text: compactSetupResultText(text), target_index: index, timeout_ms: timeout };
|
|
9072
|
+
}
|
|
9073
|
+
hiddenMatch = true;
|
|
9074
|
+
break;
|
|
9075
|
+
}
|
|
9076
|
+
break;
|
|
9077
|
+
}
|
|
9078
|
+
}
|
|
9079
|
+
if (type === "assert_text_absent" && !matched) {
|
|
9080
|
+
return { ...base, ok: true, count, timeout_ms: timeout };
|
|
9081
|
+
}
|
|
9082
|
+
await page.waitForTimeout(100);
|
|
9083
|
+
}
|
|
9084
|
+
if (type === "assert_text_visible") {
|
|
9085
|
+
if (hiddenMatch) {
|
|
9086
|
+
return { ...base, reason: "matching_element_not_visible", text: compactSetupResultText(matchedText), timeout_ms: timeout };
|
|
9087
|
+
}
|
|
9088
|
+
return { ...base, reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
|
|
9089
|
+
}
|
|
9090
|
+
return { ...base, reason: "text_still_present", text: compactSetupResultText(matchedText || lastText), timeout_ms: timeout };
|
|
9091
|
+
}
|
|
9027
9092
|
return { ...base, reason: "unsupported_action" };
|
|
9028
9093
|
} catch (error) {
|
|
9029
9094
|
return { ...base, error: String(error && error.message ? error.message : error).slice(0, 1000) };
|
package/dist/cli.js
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -8746,6 +8746,9 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
|
|
|
8746
8746
|
"click",
|
|
8747
8747
|
"fill",
|
|
8748
8748
|
"set_input_value",
|
|
8749
|
+
"assert_text_visible",
|
|
8750
|
+
"assert_text_absent",
|
|
8751
|
+
"assert_selector_count",
|
|
8749
8752
|
"local_storage",
|
|
8750
8753
|
"session_storage",
|
|
8751
8754
|
"clear_storage",
|
|
@@ -8919,12 +8922,19 @@ function normalizeSetupAction(input, index) {
|
|
|
8919
8922
|
if (!isRecord2(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
|
|
8920
8923
|
const type = normalizeSetupActionType(stringValue5(input.type), index);
|
|
8921
8924
|
const selector = stringValue5(input.selector);
|
|
8922
|
-
if ((type === "click" || type === "fill" || type === "set_input_value" || type === "wait_for_selector" || type === "wait_for_text") && !selector) {
|
|
8925
|
+
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) {
|
|
8923
8926
|
throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
|
|
8924
8927
|
}
|
|
8925
8928
|
if (type === "wait_for_text" && !stringValue5(input.text) && !stringValue5(input.pattern)) {
|
|
8926
8929
|
throw new Error(`target.setup_actions[${index}] wait_for_text requires text or pattern.`);
|
|
8927
8930
|
}
|
|
8931
|
+
if ((type === "assert_text_visible" || type === "assert_text_absent") && !stringValue5(input.text) && !stringValue5(input.pattern)) {
|
|
8932
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires text or pattern.`);
|
|
8933
|
+
}
|
|
8934
|
+
const expectedCount = numberValue3(input.expected_count ?? input.expectedCount ?? input.count);
|
|
8935
|
+
if (type === "assert_selector_count" && (expectedCount === void 0 || !Number.isInteger(expectedCount) || expectedCount < 0)) {
|
|
8936
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires non-negative integer expected_count.`);
|
|
8937
|
+
}
|
|
8928
8938
|
const value = stringFromOwn(input, "value", "input_value", "inputValue");
|
|
8929
8939
|
const hasJsonValue = hasOwn(input, "value_json") || hasOwn(input, "valueJson") || hasOwn(input, "json");
|
|
8930
8940
|
if ((type === "fill" || type === "set_input_value") && value === void 0 && !hasJsonValue) {
|
|
@@ -8947,6 +8957,7 @@ function normalizeSetupAction(input, index) {
|
|
|
8947
8957
|
pattern: stringValue5(input.pattern),
|
|
8948
8958
|
flags: stringValue5(input.flags),
|
|
8949
8959
|
index: numberValue3(input.index),
|
|
8960
|
+
expected_count: expectedCount,
|
|
8950
8961
|
ms: numberValue3(input.ms) ?? numberValue3(input.wait_ms) ?? numberValue3(input.waitMs),
|
|
8951
8962
|
timeout_ms: numberValue3(input.timeout_ms) ?? numberValue3(input.timeoutMs),
|
|
8952
8963
|
after_ms: numberValue3(input.after_ms) ?? numberValue3(input.afterMs),
|
|
@@ -10864,6 +10875,19 @@ async function executeSetupAction(action, ordinal) {
|
|
|
10864
10875
|
await locator.nth(targetIndex).fill(value, { timeout });
|
|
10865
10876
|
return { ...base, ok: true, count, target_index: targetIndex, value_length: value.length };
|
|
10866
10877
|
}
|
|
10878
|
+
if (type === "assert_selector_count") {
|
|
10879
|
+
const locator = page.locator(action.selector);
|
|
10880
|
+
const expectedCount = setupNumber(action.expected_count, -1);
|
|
10881
|
+
if (!Number.isInteger(expectedCount) || expectedCount < 0) return { ...base, reason: "invalid_expected_count", expected_count: action.expected_count };
|
|
10882
|
+
const startedAt = Date.now();
|
|
10883
|
+
let count = 0;
|
|
10884
|
+
while (Date.now() - startedAt <= timeout) {
|
|
10885
|
+
count = await locator.count().catch(() => 0);
|
|
10886
|
+
if (count === expectedCount) return { ...base, ok: true, count, expected_count: expectedCount, timeout_ms: timeout };
|
|
10887
|
+
await page.waitForTimeout(100);
|
|
10888
|
+
}
|
|
10889
|
+
return { ...base, reason: "selector_count_mismatch", count, expected_count: expectedCount, timeout_ms: timeout };
|
|
10890
|
+
}
|
|
10867
10891
|
if (type === "wait_for_text") {
|
|
10868
10892
|
const locator = page.locator(action.selector);
|
|
10869
10893
|
const startedAt = Date.now();
|
|
@@ -10881,6 +10905,47 @@ async function executeSetupAction(action, ordinal) {
|
|
|
10881
10905
|
}
|
|
10882
10906
|
return { ...base, reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
|
|
10883
10907
|
}
|
|
10908
|
+
if (type === "assert_text_visible" || type === "assert_text_absent") {
|
|
10909
|
+
const locator = page.locator(action.selector);
|
|
10910
|
+
const startedAt = Date.now();
|
|
10911
|
+
let lastText = "";
|
|
10912
|
+
let matchedText = "";
|
|
10913
|
+
let hiddenMatch = false;
|
|
10914
|
+
while (Date.now() - startedAt <= timeout) {
|
|
10915
|
+
const count = await locator.count().catch(() => 0);
|
|
10916
|
+
let matched = false;
|
|
10917
|
+
matchedText = "";
|
|
10918
|
+
hiddenMatch = false;
|
|
10919
|
+
for (let index = 0; index < count; index += 1) {
|
|
10920
|
+
const text = await setupLocatorText(locator, index);
|
|
10921
|
+
lastText = text || lastText;
|
|
10922
|
+
if (setupTextMatches(text, action)) {
|
|
10923
|
+
matched = true;
|
|
10924
|
+
matchedText = text;
|
|
10925
|
+
if (type === "assert_text_visible") {
|
|
10926
|
+
const visible = await setupLocatorVisible(locator, index);
|
|
10927
|
+
if (visible) {
|
|
10928
|
+
return { ...base, ok: true, count, text: compactSetupResultText(text), target_index: index, timeout_ms: timeout };
|
|
10929
|
+
}
|
|
10930
|
+
hiddenMatch = true;
|
|
10931
|
+
break;
|
|
10932
|
+
}
|
|
10933
|
+
break;
|
|
10934
|
+
}
|
|
10935
|
+
}
|
|
10936
|
+
if (type === "assert_text_absent" && !matched) {
|
|
10937
|
+
return { ...base, ok: true, count, timeout_ms: timeout };
|
|
10938
|
+
}
|
|
10939
|
+
await page.waitForTimeout(100);
|
|
10940
|
+
}
|
|
10941
|
+
if (type === "assert_text_visible") {
|
|
10942
|
+
if (hiddenMatch) {
|
|
10943
|
+
return { ...base, reason: "matching_element_not_visible", text: compactSetupResultText(matchedText), timeout_ms: timeout };
|
|
10944
|
+
}
|
|
10945
|
+
return { ...base, reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
|
|
10946
|
+
}
|
|
10947
|
+
return { ...base, reason: "text_still_present", text: compactSetupResultText(matchedText || lastText), timeout_ms: timeout };
|
|
10948
|
+
}
|
|
10884
10949
|
return { ...base, reason: "unsupported_action" };
|
|
10885
10950
|
} catch (error) {
|
|
10886
10951
|
return { ...base, error: String(error && error.message ? error.message : error).slice(0, 1000) };
|
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-V2KNQTQD.js";
|
|
62
62
|
import {
|
|
63
63
|
DEFAULT_RIDDLE_API_BASE_URL,
|
|
64
64
|
DEFAULT_RIDDLE_API_KEY_FILE,
|
package/dist/profile.cjs
CHANGED
|
@@ -75,6 +75,9 @@ var RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES = [
|
|
|
75
75
|
"click",
|
|
76
76
|
"fill",
|
|
77
77
|
"set_input_value",
|
|
78
|
+
"assert_text_visible",
|
|
79
|
+
"assert_text_absent",
|
|
80
|
+
"assert_selector_count",
|
|
78
81
|
"local_storage",
|
|
79
82
|
"session_storage",
|
|
80
83
|
"clear_storage",
|
|
@@ -248,12 +251,19 @@ function normalizeSetupAction(input, index) {
|
|
|
248
251
|
if (!isRecord(input)) throw new Error(`target.setup_actions[${index}] must be an object.`);
|
|
249
252
|
const type = normalizeSetupActionType(stringValue(input.type), index);
|
|
250
253
|
const selector = stringValue(input.selector);
|
|
251
|
-
if ((type === "click" || type === "fill" || type === "set_input_value" || type === "wait_for_selector" || type === "wait_for_text") && !selector) {
|
|
254
|
+
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) {
|
|
252
255
|
throw new Error(`target.setup_actions[${index}] ${type} requires selector.`);
|
|
253
256
|
}
|
|
254
257
|
if (type === "wait_for_text" && !stringValue(input.text) && !stringValue(input.pattern)) {
|
|
255
258
|
throw new Error(`target.setup_actions[${index}] wait_for_text requires text or pattern.`);
|
|
256
259
|
}
|
|
260
|
+
if ((type === "assert_text_visible" || type === "assert_text_absent") && !stringValue(input.text) && !stringValue(input.pattern)) {
|
|
261
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires text or pattern.`);
|
|
262
|
+
}
|
|
263
|
+
const expectedCount = numberValue(input.expected_count ?? input.expectedCount ?? input.count);
|
|
264
|
+
if (type === "assert_selector_count" && (expectedCount === void 0 || !Number.isInteger(expectedCount) || expectedCount < 0)) {
|
|
265
|
+
throw new Error(`target.setup_actions[${index}] ${type} requires non-negative integer expected_count.`);
|
|
266
|
+
}
|
|
257
267
|
const value = stringFromOwn(input, "value", "input_value", "inputValue");
|
|
258
268
|
const hasJsonValue = hasOwn(input, "value_json") || hasOwn(input, "valueJson") || hasOwn(input, "json");
|
|
259
269
|
if ((type === "fill" || type === "set_input_value") && value === void 0 && !hasJsonValue) {
|
|
@@ -276,6 +286,7 @@ function normalizeSetupAction(input, index) {
|
|
|
276
286
|
pattern: stringValue(input.pattern),
|
|
277
287
|
flags: stringValue(input.flags),
|
|
278
288
|
index: numberValue(input.index),
|
|
289
|
+
expected_count: expectedCount,
|
|
279
290
|
ms: numberValue(input.ms) ?? numberValue(input.wait_ms) ?? numberValue(input.waitMs),
|
|
280
291
|
timeout_ms: numberValue(input.timeout_ms) ?? numberValue(input.timeoutMs),
|
|
281
292
|
after_ms: numberValue(input.after_ms) ?? numberValue(input.afterMs),
|
|
@@ -2193,6 +2204,19 @@ async function executeSetupAction(action, ordinal) {
|
|
|
2193
2204
|
await locator.nth(targetIndex).fill(value, { timeout });
|
|
2194
2205
|
return { ...base, ok: true, count, target_index: targetIndex, value_length: value.length };
|
|
2195
2206
|
}
|
|
2207
|
+
if (type === "assert_selector_count") {
|
|
2208
|
+
const locator = page.locator(action.selector);
|
|
2209
|
+
const expectedCount = setupNumber(action.expected_count, -1);
|
|
2210
|
+
if (!Number.isInteger(expectedCount) || expectedCount < 0) return { ...base, reason: "invalid_expected_count", expected_count: action.expected_count };
|
|
2211
|
+
const startedAt = Date.now();
|
|
2212
|
+
let count = 0;
|
|
2213
|
+
while (Date.now() - startedAt <= timeout) {
|
|
2214
|
+
count = await locator.count().catch(() => 0);
|
|
2215
|
+
if (count === expectedCount) return { ...base, ok: true, count, expected_count: expectedCount, timeout_ms: timeout };
|
|
2216
|
+
await page.waitForTimeout(100);
|
|
2217
|
+
}
|
|
2218
|
+
return { ...base, reason: "selector_count_mismatch", count, expected_count: expectedCount, timeout_ms: timeout };
|
|
2219
|
+
}
|
|
2196
2220
|
if (type === "wait_for_text") {
|
|
2197
2221
|
const locator = page.locator(action.selector);
|
|
2198
2222
|
const startedAt = Date.now();
|
|
@@ -2210,6 +2234,47 @@ async function executeSetupAction(action, ordinal) {
|
|
|
2210
2234
|
}
|
|
2211
2235
|
return { ...base, reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
|
|
2212
2236
|
}
|
|
2237
|
+
if (type === "assert_text_visible" || type === "assert_text_absent") {
|
|
2238
|
+
const locator = page.locator(action.selector);
|
|
2239
|
+
const startedAt = Date.now();
|
|
2240
|
+
let lastText = "";
|
|
2241
|
+
let matchedText = "";
|
|
2242
|
+
let hiddenMatch = false;
|
|
2243
|
+
while (Date.now() - startedAt <= timeout) {
|
|
2244
|
+
const count = await locator.count().catch(() => 0);
|
|
2245
|
+
let matched = false;
|
|
2246
|
+
matchedText = "";
|
|
2247
|
+
hiddenMatch = false;
|
|
2248
|
+
for (let index = 0; index < count; index += 1) {
|
|
2249
|
+
const text = await setupLocatorText(locator, index);
|
|
2250
|
+
lastText = text || lastText;
|
|
2251
|
+
if (setupTextMatches(text, action)) {
|
|
2252
|
+
matched = true;
|
|
2253
|
+
matchedText = text;
|
|
2254
|
+
if (type === "assert_text_visible") {
|
|
2255
|
+
const visible = await setupLocatorVisible(locator, index);
|
|
2256
|
+
if (visible) {
|
|
2257
|
+
return { ...base, ok: true, count, text: compactSetupResultText(text), target_index: index, timeout_ms: timeout };
|
|
2258
|
+
}
|
|
2259
|
+
hiddenMatch = true;
|
|
2260
|
+
break;
|
|
2261
|
+
}
|
|
2262
|
+
break;
|
|
2263
|
+
}
|
|
2264
|
+
}
|
|
2265
|
+
if (type === "assert_text_absent" && !matched) {
|
|
2266
|
+
return { ...base, ok: true, count, timeout_ms: timeout };
|
|
2267
|
+
}
|
|
2268
|
+
await page.waitForTimeout(100);
|
|
2269
|
+
}
|
|
2270
|
+
if (type === "assert_text_visible") {
|
|
2271
|
+
if (hiddenMatch) {
|
|
2272
|
+
return { ...base, reason: "matching_element_not_visible", text: compactSetupResultText(matchedText), timeout_ms: timeout };
|
|
2273
|
+
}
|
|
2274
|
+
return { ...base, reason: "text_not_found", text: compactSetupResultText(lastText), timeout_ms: timeout };
|
|
2275
|
+
}
|
|
2276
|
+
return { ...base, reason: "text_still_present", text: compactSetupResultText(matchedText || lastText), timeout_ms: timeout };
|
|
2277
|
+
}
|
|
2213
2278
|
return { ...base, reason: "unsupported_action" };
|
|
2214
2279
|
} catch (error) {
|
|
2215
2280
|
return { ...base, error: String(error && error.message ? error.message : error).slice(0, 1000) };
|
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_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "selector_text_order", "frame_text_visible", "frame_no_horizontal_overflow", "text_visible", "text_absent", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
|
|
8
|
-
declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "fill", "set_input_value", "local_storage", "session_storage", "clear_storage", "wait", "wait_for_selector", "wait_for_text"];
|
|
8
|
+
declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "local_storage", "session_storage", "clear_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];
|
|
@@ -27,6 +27,7 @@ interface RiddleProofProfileSetupAction {
|
|
|
27
27
|
pattern?: string;
|
|
28
28
|
flags?: string;
|
|
29
29
|
index?: number;
|
|
30
|
+
expected_count?: number;
|
|
30
31
|
ms?: number;
|
|
31
32
|
timeout_ms?: number;
|
|
32
33
|
after_ms?: number;
|
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_absent", "selector_count_at_least", "selector_count_equals", "selector_count_equal", "selector_count_eq", "selector_text_order", "frame_text_visible", "frame_no_horizontal_overflow", "text_visible", "text_absent", "route_inventory", "no_horizontal_overflow", "no_mobile_horizontal_overflow", "no_fatal_console_errors"];
|
|
8
|
-
declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "fill", "set_input_value", "local_storage", "session_storage", "clear_storage", "wait", "wait_for_selector", "wait_for_text"];
|
|
8
|
+
declare const RIDDLE_PROOF_PROFILE_SETUP_ACTION_TYPES: readonly ["click", "fill", "set_input_value", "assert_text_visible", "assert_text_absent", "assert_selector_count", "local_storage", "session_storage", "clear_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];
|
|
@@ -27,6 +27,7 @@ interface RiddleProofProfileSetupAction {
|
|
|
27
27
|
pattern?: string;
|
|
28
28
|
flags?: string;
|
|
29
29
|
index?: number;
|
|
30
|
+
expected_count?: number;
|
|
30
31
|
ms?: number;
|
|
31
32
|
timeout_ms?: number;
|
|
32
33
|
after_ms?: number;
|
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-V2KNQTQD.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: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "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: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "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: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "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: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "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: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "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: "author" | "recon" | "ship" | "implement" | "verify" | "setup" | "run";
|
|
663
663
|
state_path: string;
|
|
664
664
|
stage: any;
|
|
665
665
|
summary: string;
|