@validate.qa/runner 1.0.103 → 1.0.104
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 +7 -2
- package/dist/{chunk-YI3ZC2XI.mjs → chunk-6N4QCCEH.mjs} +2 -2
- package/dist/{chunk-CMM4DOXC.mjs → chunk-EBWZ7NGU.mjs} +11 -8
- package/dist/{chunk-OTKJZIOD.mjs → chunk-EKY6CN4Y.mjs} +659 -122
- package/dist/{chunk-CG75I3ZZ.mjs → chunk-MEE4DXRX.mjs} +13437 -1386
- package/dist/{chunk-WVLBQDFP.mjs → chunk-OXDU6ARE.mjs} +8 -2
- package/dist/{chunk-AAUHXGDS.mjs → chunk-PUMRAFJS.mjs} +37 -13
- package/dist/{chunk-BECCGMU4.mjs → chunk-TGVKABFN.mjs} +45 -3
- package/dist/{chunk-YIM746WO.mjs → chunk-TS4OUJVT.mjs} +1 -1
- package/dist/{chunk-NNJYKR3O.mjs → chunk-UR7KDOTP.mjs} +29 -6
- package/dist/{chunk-36AWDKPL.mjs → chunk-UZ67UBXH.mjs} +14 -3
- package/dist/{chunk-7SH3COMQ.mjs → chunk-VWE3SQ2Z.mjs} +1 -1
- package/dist/{chunk-TK5KEGNW.mjs → chunk-XXZZMG6Q.mjs} +15 -3
- package/dist/cli.js +20962 -7343
- package/dist/cli.mjs +1159 -245
- package/dist/credential-mcp-server.js +671 -127
- package/dist/credential-mcp-server.mjs +3 -3
- package/dist/discovery-mcp-server.js +710 -129
- package/dist/discovery-mcp-server.mjs +4 -4
- package/dist/dist-BXHLIG5H.mjs +17 -0
- package/dist/inbox-mcp-server.js +664 -123
- package/dist/inbox-mcp-server.mjs +3 -3
- package/dist/route-seed-worker.js +671 -124
- package/dist/route-seed-worker.mjs +3 -3
- package/dist/run-write-guard-preload.js +713 -125
- package/dist/run-write-guard-preload.mjs +4 -4
- package/dist/run-write-guard.js +713 -125
- package/dist/run-write-guard.mjs +3 -3
- package/dist/tar-extract-child.js +38 -14
- package/dist/tar-extract-child.mjs +2 -2
- package/package.json +3 -2
- package/dist/dist-2G7YTNH5.mjs +0 -17
|
@@ -391,7 +391,13 @@ function buildSandboxedEnv(processEnv, testVariables) {
|
|
|
391
391
|
return env;
|
|
392
392
|
}
|
|
393
393
|
function escapeEnvValue(value) {
|
|
394
|
-
|
|
394
|
+
if (!value.includes("\r")) {
|
|
395
|
+
for (const quote of ["'", "`"]) {
|
|
396
|
+
if (!value.includes(quote))
|
|
397
|
+
return `${quote}${value}${quote}`;
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
const escaped = value.replace(/"/g, '\\"').replace(/\n/g, "\\n").replace(/\r/g, "\\r");
|
|
395
401
|
return `"${escaped}"`;
|
|
396
402
|
}
|
|
397
403
|
var API_PREFIX, SUPPORT_EMAIL, PLATFORM_ADMIN_EMAIL, NOREPLY_EMAIL, EMAIL_FROM_IDENTITIES, ADMIN_EMAIL_LIMITS, AUDIO_CHUNK_DURATION_MS, ACTION_BATCH_INTERVAL_MS, ACTION_BATCH_MAX_SIZE, MOBILE_SCREENSHOT_INTERVAL_MS, MOBILE_ACTION_BATCH_MAX_SIZE, MOBILE_BRIDGE_PORT, MOBILE_SNAPSHOT_MAX_SIZE_BYTES, MOBILE_APP_ID_MAX_LENGTH, MOBILE_APP_ID_PATTERN, MOBILE_FOCUS_SETTLE_MS, MOBILE_POST_ACTION_SETTLE_MS, MOBILE_COLD_BOOT_SETTLE_MS, MOBILE_DEFAULT_SWIPE_DISTANCE, MOBILE_MAX_SWIPE_DISTANCE, SELECTOR_PRIORITIES, MOBILE_STEP_TYPES, BLOCKED_ENV_VARS, SPAWNED_ENV_ALLOWLIST, MAX_PLAYWRIGHT_CODE_LENGTH;
|
|
@@ -3313,6 +3319,65 @@ var init_discovery_har_decision = __esm({
|
|
|
3313
3319
|
}
|
|
3314
3320
|
});
|
|
3315
3321
|
|
|
3322
|
+
// ../shared/dist/regex-literal.js
|
|
3323
|
+
function opensRegexLiteral(code, i) {
|
|
3324
|
+
let j = i - 1;
|
|
3325
|
+
while (j >= 0 && (code[j] === " " || code[j] === " "))
|
|
3326
|
+
j--;
|
|
3327
|
+
if (j < 0 || code[j] === "\n" || code[j] === "\r")
|
|
3328
|
+
return true;
|
|
3329
|
+
return regexOpensAfter(code, j);
|
|
3330
|
+
}
|
|
3331
|
+
function regexOpensAfter(code, j) {
|
|
3332
|
+
const prev = code[j];
|
|
3333
|
+
if (REGEX_OPENERS.includes(prev))
|
|
3334
|
+
return !((prev === "+" || prev === "-") && code[j - 1] === prev);
|
|
3335
|
+
if (!/[a-z]/.test(prev))
|
|
3336
|
+
return false;
|
|
3337
|
+
let start = j;
|
|
3338
|
+
while (start > 0 && /[A-Za-z0-9_$]/.test(code[start - 1]))
|
|
3339
|
+
start--;
|
|
3340
|
+
if (start > 0 && code[start - 1] === ".")
|
|
3341
|
+
return false;
|
|
3342
|
+
return REGEX_KEYWORDS.has(code.slice(start, j + 1));
|
|
3343
|
+
}
|
|
3344
|
+
function regexLiteralEnd(code, i) {
|
|
3345
|
+
let k = i + 1;
|
|
3346
|
+
let inClass = false;
|
|
3347
|
+
while (k < code.length) {
|
|
3348
|
+
const ch = code[k];
|
|
3349
|
+
if (ch === "\n" || ch === "\r")
|
|
3350
|
+
return k;
|
|
3351
|
+
if (ch === "\\") {
|
|
3352
|
+
if (code[k + 1] === "\n" || code[k + 1] === "\r")
|
|
3353
|
+
return k + 1;
|
|
3354
|
+
k += 2;
|
|
3355
|
+
continue;
|
|
3356
|
+
}
|
|
3357
|
+
if (inClass) {
|
|
3358
|
+
if (ch === "]")
|
|
3359
|
+
inClass = false;
|
|
3360
|
+
} else if (ch === "[") {
|
|
3361
|
+
inClass = true;
|
|
3362
|
+
} else if (ch === "/") {
|
|
3363
|
+
k++;
|
|
3364
|
+
while (k < code.length && /[a-z]/i.test(code[k]))
|
|
3365
|
+
k++;
|
|
3366
|
+
return k;
|
|
3367
|
+
}
|
|
3368
|
+
k++;
|
|
3369
|
+
}
|
|
3370
|
+
return code.length;
|
|
3371
|
+
}
|
|
3372
|
+
var REGEX_OPENERS, REGEX_KEYWORDS;
|
|
3373
|
+
var init_regex_literal = __esm({
|
|
3374
|
+
"../shared/dist/regex-literal.js"() {
|
|
3375
|
+
"use strict";
|
|
3376
|
+
REGEX_OPENERS = "(,=:[!&|?{};+-*%~^<>";
|
|
3377
|
+
REGEX_KEYWORDS = /* @__PURE__ */ new Set(["return", "typeof", "case", "do", "else", "in", "of", "new", "delete", "void", "throw", "await", "yield", "instanceof"]);
|
|
3378
|
+
}
|
|
3379
|
+
});
|
|
3380
|
+
|
|
3316
3381
|
// ../shared/dist/assertion-classifier.js
|
|
3317
3382
|
function isButtonOrLinkLocator(line) {
|
|
3318
3383
|
return /getByRole\s*\(\s*['"`](?:button|link)['"`]/i.test(line);
|
|
@@ -3621,7 +3686,7 @@ function classifyMobileAssertValue(value, context = {}) {
|
|
|
3621
3686
|
return { tier: 2, reason: t2[1] };
|
|
3622
3687
|
return null;
|
|
3623
3688
|
}
|
|
3624
|
-
function
|
|
3689
|
+
function regexLiteralEnd2(text, start) {
|
|
3625
3690
|
let inClass = false;
|
|
3626
3691
|
for (let i = start + 1; i < text.length; i++) {
|
|
3627
3692
|
const ch = text[i];
|
|
@@ -3647,7 +3712,7 @@ function parenDepthDelta(text) {
|
|
|
3647
3712
|
let depth = 0;
|
|
3648
3713
|
let quote = null;
|
|
3649
3714
|
let escaped = false;
|
|
3650
|
-
let
|
|
3715
|
+
let prevAt = -1;
|
|
3651
3716
|
let noRegexUntil = -1;
|
|
3652
3717
|
for (let i = 0; i < text.length; i++) {
|
|
3653
3718
|
const ch = text[i];
|
|
@@ -3662,7 +3727,7 @@ function parenDepthDelta(text) {
|
|
|
3662
3727
|
if (quote) {
|
|
3663
3728
|
if (ch === quote) {
|
|
3664
3729
|
quote = null;
|
|
3665
|
-
|
|
3730
|
+
prevAt = i;
|
|
3666
3731
|
}
|
|
3667
3732
|
continue;
|
|
3668
3733
|
}
|
|
@@ -3681,11 +3746,11 @@ function parenDepthDelta(text) {
|
|
|
3681
3746
|
i = close + 1;
|
|
3682
3747
|
continue;
|
|
3683
3748
|
}
|
|
3684
|
-
if (i > noRegexUntil && (
|
|
3685
|
-
const end =
|
|
3749
|
+
if (i > noRegexUntil && (prevAt < 0 || regexOpensAfter(text, prevAt))) {
|
|
3750
|
+
const end = regexLiteralEnd2(text, i);
|
|
3686
3751
|
if (end > 0) {
|
|
3687
3752
|
i = end - 1;
|
|
3688
|
-
|
|
3753
|
+
prevAt = end - 1;
|
|
3689
3754
|
continue;
|
|
3690
3755
|
}
|
|
3691
3756
|
const nl = text.indexOf("\n", i);
|
|
@@ -3697,14 +3762,15 @@ function parenDepthDelta(text) {
|
|
|
3697
3762
|
else if (ch === ")")
|
|
3698
3763
|
depth--;
|
|
3699
3764
|
if (ch !== " " && ch !== " " && ch !== "\n")
|
|
3700
|
-
|
|
3765
|
+
prevAt = i;
|
|
3701
3766
|
}
|
|
3702
3767
|
return depth;
|
|
3703
3768
|
}
|
|
3704
|
-
var PENDING_STATE_TEXT_REASON, PENDING_STATE_TEXT, TIER1_PATTERNS, TIER2_PATTERNS, TIER4_PATTERNS, SINGLE_QUOTED, DOUBLE_QUOTED, BACKTICK_QUOTED, QUOTED_BODY, LOCATOR_ARG_VALUE, LOCATOR_TEXT_ARG_PATTERNS, EXPECT_TOKEN
|
|
3769
|
+
var PENDING_STATE_TEXT_REASON, PENDING_STATE_TEXT, TIER1_PATTERNS, TIER2_PATTERNS, TIER4_PATTERNS, SINGLE_QUOTED, DOUBLE_QUOTED, BACKTICK_QUOTED, QUOTED_BODY, LOCATOR_ARG_VALUE, LOCATOR_TEXT_ARG_PATTERNS, EXPECT_TOKEN;
|
|
3705
3770
|
var init_assertion_classifier = __esm({
|
|
3706
3771
|
"../shared/dist/assertion-classifier.js"() {
|
|
3707
3772
|
"use strict";
|
|
3773
|
+
init_regex_literal();
|
|
3708
3774
|
PENDING_STATE_TEXT_REASON = 'pending-state text ("Sending...") is transient';
|
|
3709
3775
|
PENDING_STATE_TEXT = /\b(?!(?:Billing|Shipping|Pricing|Listing|Meeting|Morning|Evening|Warning|Building|Training|Marketing|Parking|Housing|Reading|Rating|Heading|Ceiling|Wedding|Clothing|Painting|Setting)\b)[A-Z][a-z]{2,}ing(?:\.{3}|…)/;
|
|
3710
3776
|
TIER1_PATTERNS = [
|
|
@@ -3781,7 +3847,6 @@ var init_assertion_classifier = __esm({
|
|
|
3781
3847
|
new RegExp(`\\.filter\\s*\\(\\s*\\{[^}]{0,200}?\\bhasText\\s*:\\s*${LOCATOR_ARG_VALUE}`, "gi")
|
|
3782
3848
|
];
|
|
3783
3849
|
EXPECT_TOKEN = /\bexpect\s*[.(]/;
|
|
3784
|
-
REGEX_PRECEDER = /* @__PURE__ */ new Set(["(", ",", "=", ":", "[", "!", "&", "|", "?", "{", "}", ";", "+", "-", "*", "%", "<", ">", "~", "^"]);
|
|
3785
3850
|
}
|
|
3786
3851
|
});
|
|
3787
3852
|
|
|
@@ -3789,14 +3854,80 @@ var init_assertion_classifier = __esm({
|
|
|
3789
3854
|
function isExpectCall(code) {
|
|
3790
3855
|
return EXPECT_CALL_RE.test(code);
|
|
3791
3856
|
}
|
|
3857
|
+
function specCallsExpect(code) {
|
|
3858
|
+
if (EXPECT_CALL_RE.test(code) || SPACED_EXPECT_CALL_RE.test(code) || CONFIGURE_IN_PLACE_RE.test(code))
|
|
3859
|
+
return true;
|
|
3860
|
+
const names = /* @__PURE__ */ new Set();
|
|
3861
|
+
for (const clause of code.matchAll(IMPORT_CLAUSE_RE)) {
|
|
3862
|
+
for (const alias of clause[1].matchAll(EXPECT_ALIAS_RE))
|
|
3863
|
+
names.add(alias[1]);
|
|
3864
|
+
}
|
|
3865
|
+
for (const decl of code.matchAll(DERIVED_EXPECT_DECL_RE)) {
|
|
3866
|
+
if (names.size >= MAX_DERIVED_EXPECT_NAMES)
|
|
3867
|
+
break;
|
|
3868
|
+
const base2 = decl[2];
|
|
3869
|
+
if (base2 === void 0 || base2 === "expect" || names.has(base2))
|
|
3870
|
+
names.add(decl[1]);
|
|
3871
|
+
}
|
|
3872
|
+
names.delete("expect");
|
|
3873
|
+
if (names.size === 0)
|
|
3874
|
+
return false;
|
|
3875
|
+
const alts = [...names].map((n) => n.replace(/\$/g, "\\$")).join("|");
|
|
3876
|
+
return new RegExp(String.raw`(?<![\w$.])(?:${alts})${EXPECT_MODIFIERS}`).test(code);
|
|
3877
|
+
}
|
|
3792
3878
|
function asPlainExpect(code) {
|
|
3793
3879
|
return code.replace(/\bexpect\.soft(\s*\()/g, "expect$1");
|
|
3794
3880
|
}
|
|
3795
|
-
|
|
3881
|
+
function expectAliasNames(code) {
|
|
3882
|
+
if (!MAY_ALIAS.test(code))
|
|
3883
|
+
return [];
|
|
3884
|
+
const imported = [];
|
|
3885
|
+
for (const m of code.matchAll(PW_IMPORT)) {
|
|
3886
|
+
for (const a of m[1].matchAll(IMPORT_AS_EXPECT))
|
|
3887
|
+
imported.push(a[1]);
|
|
3888
|
+
}
|
|
3889
|
+
const known = /* @__PURE__ */ new Set(["expect", ...imported]);
|
|
3890
|
+
const derived = [];
|
|
3891
|
+
for (const m of code.matchAll(DECLARATION)) {
|
|
3892
|
+
const rhs = DERIVED.exec(code.slice(m.index + m[0].length, m.index + m[0].length + 200));
|
|
3893
|
+
if (!rhs)
|
|
3894
|
+
continue;
|
|
3895
|
+
const base2 = rhs[1];
|
|
3896
|
+
const fromKnown = base2 === void 0 || (rhs[2] ? base2 === "test" : known.has(base2));
|
|
3897
|
+
if (!fromKnown || m[1] === "expect")
|
|
3898
|
+
continue;
|
|
3899
|
+
known.add(m[1]);
|
|
3900
|
+
derived.push(m[1]);
|
|
3901
|
+
}
|
|
3902
|
+
const fromImports = LOCAL_EXPECT.test(code) ? [] : imported;
|
|
3903
|
+
return [.../* @__PURE__ */ new Set([...fromImports, ...derived])].filter((n) => n !== "expect");
|
|
3904
|
+
}
|
|
3905
|
+
function withExpectAliasesAsExpect(code) {
|
|
3906
|
+
let out = code;
|
|
3907
|
+
for (const name of expectAliasNames(code)) {
|
|
3908
|
+
const escaped = name.replace(/\$/g, "\\$");
|
|
3909
|
+
out = out.replace(new RegExp(`(?<![\\w$.])${escaped}(?=\\s{0,20}(?:\\.\\s{0,20}(?:soft|poll)\\s{0,20})?\\()`, "g"), "expect");
|
|
3910
|
+
}
|
|
3911
|
+
return out;
|
|
3912
|
+
}
|
|
3913
|
+
var EXPECT_CALL_RE, EXPECT_MODIFIERS, SPACED_EXPECT_CALL_RE, CONFIGURE_IN_PLACE_RE, IMPORT_CLAUSE_RE, EXPECT_ALIAS_RE, DERIVED_EXPECT_DECL_RE, MAX_DERIVED_EXPECT_NAMES, PW_IMPORT, IMPORT_AS_EXPECT, DECLARATION, DERIVED, LOCAL_EXPECT, MAY_ALIAS;
|
|
3796
3914
|
var init_expect_call = __esm({
|
|
3797
3915
|
"../shared/dist/expect-call.js"() {
|
|
3798
3916
|
"use strict";
|
|
3799
3917
|
EXPECT_CALL_RE = /\bexpect(?:\.(?:soft|poll))?\s*\(/;
|
|
3918
|
+
EXPECT_MODIFIERS = String.raw`\s*(?:\.\s*soft\s*)?(?:\.\s*poll\s*)?\(`;
|
|
3919
|
+
SPACED_EXPECT_CALL_RE = new RegExp(String.raw`\bexpect${EXPECT_MODIFIERS}`);
|
|
3920
|
+
CONFIGURE_IN_PLACE_RE = new RegExp(String.raw`\bexpect\s*\.\s*configure\s*\(\s*(?:\{[^{}()]{0,500}\}\s*)?\)${EXPECT_MODIFIERS}`);
|
|
3921
|
+
IMPORT_CLAUSE_RE = /\bimport\s+(?:type\s+)?\{([^{}]{0,2000})\}/g;
|
|
3922
|
+
EXPECT_ALIAS_RE = /\bexpect\s+as\s+([A-Za-z_$][\w$]*)/g;
|
|
3923
|
+
DERIVED_EXPECT_DECL_RE = /\b(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=\s*(?:([A-Za-z_$][\w$]*)\s*\.\s*(?:configure|extend)|mergeExpects)\s*\(/g;
|
|
3924
|
+
MAX_DERIVED_EXPECT_NAMES = 20;
|
|
3925
|
+
PW_IMPORT = /\bimport\s{0,20}\{([^}]{0,4000})\}\s{0,20}from\s{0,20}['"]@playwright\/test['"]/g;
|
|
3926
|
+
IMPORT_AS_EXPECT = /(?:^|,)\s{0,20}expect\s{1,20}as\s{1,20}([A-Za-z_$][\w$]{0,99})\s{0,20}(?=,|$)/g;
|
|
3927
|
+
DECLARATION = /\b(?:const|let|var)\s{1,20}([A-Za-z_$][\w$]{0,99})\s{0,20}(?::[^=;\n]{0,200})?=\s{0,20}/g;
|
|
3928
|
+
DERIVED = /^(?:mergeExpects\s{0,20}\(|([A-Za-z_$][\w$]{0,99})(\s{0,20}\.\s{0,20}expect)?\s{0,20}\.\s{0,20}(?:configure|extend)\s{0,20}\(|test\s{0,20}\.\s{0,20}expect\b(?!\s{0,20}[.(]))/;
|
|
3929
|
+
LOCAL_EXPECT = /\b(?:const|let|var)\s{1,20}expect\b/;
|
|
3930
|
+
MAY_ALIAS = /\bexpect\s{1,20}as\b|\.\s{0,20}(?:configure|extend)\s{0,20}\(|\bmergeExpects\b|\btest\s{0,20}\.\s{0,20}expect\b/;
|
|
3800
3931
|
}
|
|
3801
3932
|
});
|
|
3802
3933
|
|
|
@@ -3826,65 +3957,6 @@ var init_braced_clause = __esm({
|
|
|
3826
3957
|
}
|
|
3827
3958
|
});
|
|
3828
3959
|
|
|
3829
|
-
// ../shared/dist/regex-literal.js
|
|
3830
|
-
function opensRegexLiteral(code, i) {
|
|
3831
|
-
let j = i - 1;
|
|
3832
|
-
while (j >= 0 && (code[j] === " " || code[j] === " "))
|
|
3833
|
-
j--;
|
|
3834
|
-
if (j < 0 || code[j] === "\n" || code[j] === "\r")
|
|
3835
|
-
return true;
|
|
3836
|
-
return regexOpensAfter(code, j);
|
|
3837
|
-
}
|
|
3838
|
-
function regexOpensAfter(code, j) {
|
|
3839
|
-
const prev = code[j];
|
|
3840
|
-
if (REGEX_OPENERS.includes(prev))
|
|
3841
|
-
return !((prev === "+" || prev === "-") && code[j - 1] === prev);
|
|
3842
|
-
if (!/[a-z]/.test(prev))
|
|
3843
|
-
return false;
|
|
3844
|
-
let start = j;
|
|
3845
|
-
while (start > 0 && /[A-Za-z0-9_$]/.test(code[start - 1]))
|
|
3846
|
-
start--;
|
|
3847
|
-
if (start > 0 && code[start - 1] === ".")
|
|
3848
|
-
return false;
|
|
3849
|
-
return REGEX_KEYWORDS.has(code.slice(start, j + 1));
|
|
3850
|
-
}
|
|
3851
|
-
function regexLiteralEnd2(code, i) {
|
|
3852
|
-
let k = i + 1;
|
|
3853
|
-
let inClass = false;
|
|
3854
|
-
while (k < code.length) {
|
|
3855
|
-
const ch = code[k];
|
|
3856
|
-
if (ch === "\n" || ch === "\r")
|
|
3857
|
-
return k;
|
|
3858
|
-
if (ch === "\\") {
|
|
3859
|
-
if (code[k + 1] === "\n" || code[k + 1] === "\r")
|
|
3860
|
-
return k + 1;
|
|
3861
|
-
k += 2;
|
|
3862
|
-
continue;
|
|
3863
|
-
}
|
|
3864
|
-
if (inClass) {
|
|
3865
|
-
if (ch === "]")
|
|
3866
|
-
inClass = false;
|
|
3867
|
-
} else if (ch === "[") {
|
|
3868
|
-
inClass = true;
|
|
3869
|
-
} else if (ch === "/") {
|
|
3870
|
-
k++;
|
|
3871
|
-
while (k < code.length && /[a-z]/i.test(code[k]))
|
|
3872
|
-
k++;
|
|
3873
|
-
return k;
|
|
3874
|
-
}
|
|
3875
|
-
k++;
|
|
3876
|
-
}
|
|
3877
|
-
return code.length;
|
|
3878
|
-
}
|
|
3879
|
-
var REGEX_OPENERS, REGEX_KEYWORDS;
|
|
3880
|
-
var init_regex_literal = __esm({
|
|
3881
|
-
"../shared/dist/regex-literal.js"() {
|
|
3882
|
-
"use strict";
|
|
3883
|
-
REGEX_OPENERS = "(,=:[!&|?{};+-*%~^<>";
|
|
3884
|
-
REGEX_KEYWORDS = /* @__PURE__ */ new Set(["return", "typeof", "case", "do", "else", "in", "of", "new", "delete", "void", "throw", "await", "yield", "instanceof"]);
|
|
3885
|
-
}
|
|
3886
|
-
});
|
|
3887
|
-
|
|
3888
3960
|
// ../shared/dist/assertion-proof.js
|
|
3889
3961
|
function fragmentKindOf(literal, fromText) {
|
|
3890
3962
|
const text = literal.trim();
|
|
@@ -4043,7 +4115,7 @@ function stripCoverageComments(code) {
|
|
|
4043
4115
|
let copyFrom = 0;
|
|
4044
4116
|
let i = 0;
|
|
4045
4117
|
let quote = null;
|
|
4046
|
-
let
|
|
4118
|
+
let prevAt = -1;
|
|
4047
4119
|
let noRegexBefore = 0;
|
|
4048
4120
|
while (i < code.length) {
|
|
4049
4121
|
const ch = code[i];
|
|
@@ -4054,17 +4126,18 @@ function stripCoverageComments(code) {
|
|
|
4054
4126
|
}
|
|
4055
4127
|
if (ch === quote || ch === "\n" && quote !== "`") {
|
|
4056
4128
|
quote = null;
|
|
4057
|
-
|
|
4129
|
+
if (ch !== "\n")
|
|
4130
|
+
prevAt = i;
|
|
4058
4131
|
}
|
|
4059
4132
|
i++;
|
|
4060
4133
|
continue;
|
|
4061
4134
|
}
|
|
4062
4135
|
const next = code[i + 1];
|
|
4063
|
-
if (ch === "/" && next !== "*" && next !== "/" && i >= noRegexBefore && (
|
|
4136
|
+
if (ch === "/" && next !== "*" && next !== "/" && i >= noRegexBefore && (prevAt < 0 || regexOpensAfter(code, prevAt))) {
|
|
4064
4137
|
const end = regexLiteralEnd3(code, i);
|
|
4065
4138
|
if (end > 0) {
|
|
4066
4139
|
i = end;
|
|
4067
|
-
|
|
4140
|
+
prevAt = end - 1;
|
|
4068
4141
|
continue;
|
|
4069
4142
|
}
|
|
4070
4143
|
const eol = code.indexOf("\n", i);
|
|
@@ -4089,7 +4162,7 @@ function stripCoverageComments(code) {
|
|
|
4089
4162
|
if (ch === '"' || ch === "'" || ch === "`")
|
|
4090
4163
|
quote = ch;
|
|
4091
4164
|
if (ch !== " " && ch !== " " && ch !== "\n" && ch !== "\r")
|
|
4092
|
-
|
|
4165
|
+
prevAt = i;
|
|
4093
4166
|
i++;
|
|
4094
4167
|
}
|
|
4095
4168
|
out.push(code.slice(copyFrom));
|
|
@@ -4778,11 +4851,12 @@ function assessTitleCoverage(title, code) {
|
|
|
4778
4851
|
const repeatedHit = [...repeated].some((term) => hay.includes(term));
|
|
4779
4852
|
return { covered: hit >= needed || repeatedHit, missingTerms };
|
|
4780
4853
|
}
|
|
4781
|
-
var COVERAGE_STOP_WORDS, MAX_ASSERTION_JOIN_CHARS, MAX_COVERAGE_LINE_CHARS,
|
|
4854
|
+
var COVERAGE_STOP_WORDS, MAX_ASSERTION_JOIN_CHARS, MAX_COVERAGE_LINE_CHARS, BLOCK_SCAFFOLD, cachedAssertionInput, cachedAssertionSource, LOCAL_BINDING, ASSERTED_STATUS_RE, MAX_RESOLVED_NAMES_PER_LINE, WORD_CHAR_RE, NOT_CONTAIN_TEXT_RE, PLACE_PHRASE_RE, PLACE_WORD_MIN_CHARS, PLACE_FUNCTION_WORDS, HIDDEN_STATE_TERMS, HIDDEN_ELEMENT_LINE_RE, HIDDEN_LINE_RE, MAX_SHOWN_EARLIER_LINES, SHOWN_EARLIER_LITERAL_RE, SHARED_PREFIX_MIN_CHARS, MAX_SHOWN_EARLIER_LITERALS, VALUE_SHAPE_RE, VALUE_SHAPE_ALL_RE, TITLE_TERM_MIN;
|
|
4782
4855
|
var init_expected_outcome_coverage = __esm({
|
|
4783
4856
|
"../shared/dist/expected-outcome-coverage.js"() {
|
|
4784
4857
|
"use strict";
|
|
4785
4858
|
init_assertion_classifier();
|
|
4859
|
+
init_regex_literal();
|
|
4786
4860
|
COVERAGE_STOP_WORDS = /* @__PURE__ */ new Set([
|
|
4787
4861
|
"after",
|
|
4788
4862
|
"before",
|
|
@@ -4815,7 +4889,6 @@ var init_expected_outcome_coverage = __esm({
|
|
|
4815
4889
|
]);
|
|
4816
4890
|
MAX_ASSERTION_JOIN_CHARS = 8e3;
|
|
4817
4891
|
MAX_COVERAGE_LINE_CHARS = 2e3;
|
|
4818
|
-
REGEX_PRECEDER2 = "(,=:[!&|?{};+-*%<>~^";
|
|
4819
4892
|
BLOCK_SCAFFOLD = /=>|\b(?:test|describe|it|beforeEach|afterEach|beforeAll|afterAll|function)\b/;
|
|
4820
4893
|
cachedAssertionInput = null;
|
|
4821
4894
|
cachedAssertionSource = { raw: "", normalized: "", bindings: /* @__PURE__ */ new Map(), bindingRefs: /* @__PURE__ */ new Map() };
|
|
@@ -4911,7 +4984,7 @@ function replaceBlockComments(code, replacer) {
|
|
|
4911
4984
|
continue;
|
|
4912
4985
|
const next = code[i + 1];
|
|
4913
4986
|
if (next !== "/" && next !== "*" && opensRegexLiteral(code, i)) {
|
|
4914
|
-
i =
|
|
4987
|
+
i = regexLiteralEnd(code, i) - 1;
|
|
4915
4988
|
continue;
|
|
4916
4989
|
}
|
|
4917
4990
|
if (next === "/" && !(code[i - 1] === ":" && /[A-Za-z]/.test(code[i - 2] ?? ""))) {
|
|
@@ -5086,10 +5159,41 @@ var init_auth_handoff_coverage = __esm({
|
|
|
5086
5159
|
});
|
|
5087
5160
|
|
|
5088
5161
|
// ../shared/dist/auth-plan.js
|
|
5089
|
-
function
|
|
5162
|
+
function stripStampedHelperRegions(code) {
|
|
5163
|
+
let out = code;
|
|
5164
|
+
for (const [open, close] of STAMPED_HELPER_REGIONS) {
|
|
5165
|
+
if (out.indexOf(open) === -1)
|
|
5166
|
+
continue;
|
|
5167
|
+
let kept = "";
|
|
5168
|
+
let i = 0;
|
|
5169
|
+
while (i < out.length) {
|
|
5170
|
+
const start = out.indexOf(open, i);
|
|
5171
|
+
if (start === -1) {
|
|
5172
|
+
kept += out.slice(i);
|
|
5173
|
+
break;
|
|
5174
|
+
}
|
|
5175
|
+
const end = out.indexOf(close, start + open.length);
|
|
5176
|
+
if (end === -1) {
|
|
5177
|
+
kept += out.slice(i);
|
|
5178
|
+
break;
|
|
5179
|
+
}
|
|
5180
|
+
const lineEnd = out.indexOf("\n", end);
|
|
5181
|
+
kept += out.slice(i, start);
|
|
5182
|
+
i = lineEnd === -1 ? out.length : lineEnd + 1;
|
|
5183
|
+
}
|
|
5184
|
+
out = kept;
|
|
5185
|
+
}
|
|
5186
|
+
return out;
|
|
5187
|
+
}
|
|
5188
|
+
function signsInInline(playwrightCode) {
|
|
5090
5189
|
if (!playwrightCode)
|
|
5091
5190
|
return false;
|
|
5092
|
-
|
|
5191
|
+
if (!/process\.env\.TEST_USER_EMAIL!?/.test(playwrightCode))
|
|
5192
|
+
return false;
|
|
5193
|
+
if (/process\.env\.TEST_USER_PASSWORD!?/.test(playwrightCode))
|
|
5194
|
+
return true;
|
|
5195
|
+
const body = stripStampedHelperRegions(playwrightCode);
|
|
5196
|
+
return /process\.env\.TEST_USER_EMAIL/.test(body) && /__vqaWaitForEmail\s*\(/.test(body);
|
|
5093
5197
|
}
|
|
5094
5198
|
function hasGeneratedAuthGuard(playwrightCode) {
|
|
5095
5199
|
if (!playwrightCode)
|
|
@@ -5108,7 +5212,7 @@ function legacyNeedsCookieState(tags, code, sharedAuthInjectEnabled) {
|
|
|
5108
5212
|
if (sharedAuthInjectEnabled && tags.includes("@auth-guarded") && hasGeneratedAuthGuard(code))
|
|
5109
5213
|
return true;
|
|
5110
5214
|
const isGeneratedVariant = tags.includes("@edge") || tags.includes("@bug");
|
|
5111
|
-
const hasLegacyInlineLogin = tags.includes("@discovered") && !isGeneratedVariant &&
|
|
5215
|
+
const hasLegacyInlineLogin = tags.includes("@discovered") && !isGeneratedVariant && signsInInline(code);
|
|
5112
5216
|
return !tags.includes("@inline-login") && !hasLegacyInlineLogin;
|
|
5113
5217
|
}
|
|
5114
5218
|
function codeReadsStoredCredentials(code) {
|
|
@@ -5229,7 +5333,7 @@ function authTypeTag(tags) {
|
|
|
5229
5333
|
const explicit = explicitAuthTypeTags(t);
|
|
5230
5334
|
return explicit.length === 1 ? explicit[0] : void 0;
|
|
5231
5335
|
}
|
|
5232
|
-
var AUTH_TAG_COOKIE_STATE, AUTH_TAG_LOGIN_COOKIE, AUTH_TAG_LOGIN_BEARER, AUTH_TAG_STANDING, AUTH_TAG_NONE, AUTH_TAG_UNSUPPORTED, AUTH_TYPE_TAGS, AUTH_TAG_ALIASES, TEST_USER_ENV_KEYS, API_AUTH_HEADERS_ENV_KEY;
|
|
5336
|
+
var AUTH_TAG_COOKIE_STATE, AUTH_TAG_LOGIN_COOKIE, AUTH_TAG_LOGIN_BEARER, AUTH_TAG_STANDING, AUTH_TAG_NONE, AUTH_TAG_UNSUPPORTED, AUTH_TYPE_TAGS, AUTH_TAG_ALIASES, TEST_USER_ENV_KEYS, API_AUTH_HEADERS_ENV_KEY, STAMPED_HELPER_REGIONS;
|
|
5233
5337
|
var init_auth_plan = __esm({
|
|
5234
5338
|
"../shared/dist/auth-plan.js"() {
|
|
5235
5339
|
"use strict";
|
|
@@ -5256,6 +5360,10 @@ var init_auth_plan = __esm({
|
|
|
5256
5360
|
};
|
|
5257
5361
|
TEST_USER_ENV_KEYS = ["TEST_USER_EMAIL", "TEST_USER_PASSWORD"];
|
|
5258
5362
|
API_AUTH_HEADERS_ENV_KEY = "API_AUTH_HEADERS";
|
|
5363
|
+
STAMPED_HELPER_REGIONS = [
|
|
5364
|
+
["// >>> VALIDATE_QA_INBOX", "// <<< VALIDATE_QA_INBOX"],
|
|
5365
|
+
["// >>> VALIDATE_QA_SMS", "// <<< VALIDATE_QA_SMS"]
|
|
5366
|
+
];
|
|
5259
5367
|
}
|
|
5260
5368
|
});
|
|
5261
5369
|
|
|
@@ -5264,6 +5372,9 @@ function parseLastActionProofMode(raw) {
|
|
|
5264
5372
|
const v = (raw ?? "").trim().toLowerCase();
|
|
5265
5373
|
return v === "on" || v === "shadow" ? v : "off";
|
|
5266
5374
|
}
|
|
5375
|
+
function parseAbsenceProofMode(raw) {
|
|
5376
|
+
return parseLastActionProofMode(raw);
|
|
5377
|
+
}
|
|
5267
5378
|
function isUrlProof(stmt) {
|
|
5268
5379
|
if (URL_PROOF.test(stmt))
|
|
5269
5380
|
return true;
|
|
@@ -5651,6 +5762,65 @@ function isVacuousAccountAbsence(stmt, shown, account) {
|
|
|
5651
5762
|
}
|
|
5652
5763
|
return true;
|
|
5653
5764
|
}
|
|
5765
|
+
function isAbsenceCheck(stmt) {
|
|
5766
|
+
if (!claimsAbsence(stmt))
|
|
5767
|
+
return false;
|
|
5768
|
+
const bare = stmt.replace(NOT_BEFORE_MATCHER, ".");
|
|
5769
|
+
return ABSENCE_READ.test(bare) || VALUE_ABSENCE.test(bare) || OPTION_ABSENCE.test(bare);
|
|
5770
|
+
}
|
|
5771
|
+
function comparableSubject(subject) {
|
|
5772
|
+
let s = subject.replace(/^\s*await\s+/, "").replace(/\s+/g, "");
|
|
5773
|
+
for (let prev = ""; prev !== s; ) {
|
|
5774
|
+
prev = s;
|
|
5775
|
+
s = s.replace(/\.(?:count|isVisible|isHidden|first|last)\(\)$/, "").replace(/\.nth\(\d+\)$/, "");
|
|
5776
|
+
}
|
|
5777
|
+
return s;
|
|
5778
|
+
}
|
|
5779
|
+
function subjectsThatExisted(checks, interactionStmts) {
|
|
5780
|
+
const out = [];
|
|
5781
|
+
const bound = locatorBindings(interactionStmts);
|
|
5782
|
+
const resolve = (expr) => {
|
|
5783
|
+
for (let depth = 0; depth < 4; depth++) {
|
|
5784
|
+
const lead = expr.match(/^\s*(?:await\s+)?([A-Za-z_$][\w$]*)(?![\w$(])/);
|
|
5785
|
+
const to = lead ? bound.get(lead[1]) : void 0;
|
|
5786
|
+
if (!lead || to === void 0)
|
|
5787
|
+
break;
|
|
5788
|
+
expr = `${to.replace(/;\s*$/, "")}${expr.slice(lead[0].length)}`;
|
|
5789
|
+
}
|
|
5790
|
+
return expr;
|
|
5791
|
+
};
|
|
5792
|
+
for (const { stmt } of checks) {
|
|
5793
|
+
if (isAbsenceCheck(stmt))
|
|
5794
|
+
continue;
|
|
5795
|
+
const subject = extractExpectSubject(stmt);
|
|
5796
|
+
if (subject)
|
|
5797
|
+
out.push(comparableSubject(subject));
|
|
5798
|
+
}
|
|
5799
|
+
for (const stmt of interactionStmts) {
|
|
5800
|
+
if (EXPECT_CALL_RE.test(stmt))
|
|
5801
|
+
continue;
|
|
5802
|
+
for (const m of stmt.matchAll(LOCATOR_USE)) {
|
|
5803
|
+
if (m[0].includes("waitFor") && /state\s*:\s*['"`](?:hidden|detached)/.test(stmt.slice(m.index)))
|
|
5804
|
+
continue;
|
|
5805
|
+
const before = stmt.slice(0, m.index).replace(/^\s*(?:(?:const|let|var)\s+[\w$]+\s*=|return\b)\s*/, "");
|
|
5806
|
+
if (before.trim())
|
|
5807
|
+
out.push(comparableSubject(resolve(before)));
|
|
5808
|
+
}
|
|
5809
|
+
}
|
|
5810
|
+
return out;
|
|
5811
|
+
}
|
|
5812
|
+
function isUnshownAbsence(stmt, existed, entered) {
|
|
5813
|
+
if (!isAbsenceCheck(stmt))
|
|
5814
|
+
return false;
|
|
5815
|
+
const raw = extractExpectSubject(stmt);
|
|
5816
|
+
if (!raw || !/\b(?:locator|getBy[A-Z]\w*|frameLocator)\s*\(/.test(raw))
|
|
5817
|
+
return false;
|
|
5818
|
+
const subject = comparableSubject(raw);
|
|
5819
|
+
if (existed.some((e) => e === subject || e.startsWith(`${subject}.`)))
|
|
5820
|
+
return false;
|
|
5821
|
+
const named = raw.match(/['"`][^'"`]+['"`]/g) ?? [];
|
|
5822
|
+
return !named.some((q) => entered.values.has(q.slice(1, -1).toLowerCase()));
|
|
5823
|
+
}
|
|
5654
5824
|
function endOfEnclosingCall(stmt, from) {
|
|
5655
5825
|
let depth = 0;
|
|
5656
5826
|
for (let i = from; i < stmt.length; i++) {
|
|
@@ -6150,10 +6320,31 @@ function comparesWithItself(subject, tail) {
|
|
|
6150
6320
|
const expected = squash2(args);
|
|
6151
6321
|
return expected === squash2(m[1] === "toHaveCount" ? `${subject}.count()` : subject);
|
|
6152
6322
|
}
|
|
6323
|
+
function ariaSnapshotTexts(template) {
|
|
6324
|
+
const out = [];
|
|
6325
|
+
for (const raw of template.split(ARIA_ENTRY_SPLIT)) {
|
|
6326
|
+
const m = ARIA_ENTRY.exec(raw.trim());
|
|
6327
|
+
if (!m || !ARIA_CONTENT_ROLES.has(m[1]))
|
|
6328
|
+
continue;
|
|
6329
|
+
for (const text of [m[2], m[3]]) {
|
|
6330
|
+
const t = text?.replace(/\\(.)/g, "$1").replace(/^["']|["']$/g, "").trim();
|
|
6331
|
+
if (!t || t.startsWith("/") || !/[\p{L}\p{N}]/u.test(t) || /["'`\\]/.test(t))
|
|
6332
|
+
continue;
|
|
6333
|
+
out.push(t);
|
|
6334
|
+
}
|
|
6335
|
+
}
|
|
6336
|
+
return out;
|
|
6337
|
+
}
|
|
6338
|
+
function presenceTwin(stmt) {
|
|
6339
|
+
return stmt.replace(NOT_HIDDEN, ".toBeVisible(").replace(NOT_COUNT_ZERO, ".toBeVisible(");
|
|
6340
|
+
}
|
|
6153
6341
|
function asPlainAssertion(s) {
|
|
6154
6342
|
return plainAssertion(s, false);
|
|
6155
6343
|
}
|
|
6156
6344
|
function plainAssertion(s, keepSelfCompare) {
|
|
6345
|
+
const twin = presenceTwin(s.stmt);
|
|
6346
|
+
if (twin !== s.stmt)
|
|
6347
|
+
return plainAssertion({ ...s, stmt: twin }, keepSelfCompare);
|
|
6157
6348
|
const { stmt } = s;
|
|
6158
6349
|
if (COUNT_AT_LEAST_ZERO.test(stmt))
|
|
6159
6350
|
return [];
|
|
@@ -6164,6 +6355,12 @@ function plainAssertion(s, keepSelfCompare) {
|
|
|
6164
6355
|
const subjectAt = stmt.indexOf(subject, stmt.search(EXPECT_CALL_RE));
|
|
6165
6356
|
const tail = (stmt.startsWith("expect.poll", stmt.search(EXPECT_CALL_RE)) ? expectCallTail(stmt) : null) ?? stmt.slice(subjectAt + subject.length).trimStart();
|
|
6166
6357
|
const as = (rewritten) => [{ ...s, stmt: rewritten }];
|
|
6358
|
+
const aria = ARIA_TEMPLATE_CALL.exec(tail);
|
|
6359
|
+
if (aria && !NEGATED_ASSERT.test(stmt)) {
|
|
6360
|
+
const texts = ariaSnapshotTexts(aria[2]);
|
|
6361
|
+
if (texts.length > 0)
|
|
6362
|
+
return texts.map((t) => ({ ...s, stmt: `await expect(${plain}).toContainText(${JSON.stringify(t)});` }));
|
|
6363
|
+
}
|
|
6167
6364
|
if (LOCATOR_EXPR.test(plain) && !LOCATOR_VALUE_READ.test(plain) && ALWAYS_TRUE_ON_OBJECT.test(tail))
|
|
6168
6365
|
return [];
|
|
6169
6366
|
if (DEFINED_VALUE_READ.test(plain) && ALWAYS_DEFINED.test(tail))
|
|
@@ -6470,7 +6667,8 @@ function teardownLines(lines) {
|
|
|
6470
6667
|
}
|
|
6471
6668
|
return out;
|
|
6472
6669
|
}
|
|
6473
|
-
function validateAssertionStrength(
|
|
6670
|
+
function validateAssertionStrength(source, opts = {}) {
|
|
6671
|
+
const code = withExpectAliasesAsExpect(source);
|
|
6474
6672
|
const body = stripLoginScaffolding(code);
|
|
6475
6673
|
const lines = body.split("\n");
|
|
6476
6674
|
const stmts = liveExpectStatements(stripCoverageComments(body)).flatMap(asPlainAssertion);
|
|
@@ -6623,8 +6821,23 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
6623
6821
|
const orderedPersistence = firstMutLine !== void 0 ? persistence : void 0;
|
|
6624
6822
|
const signedIn = signInProofWindow(interactionStmts, interactionStmtsWithLines, lines, blockIds);
|
|
6625
6823
|
const proof = classifyOutcomeProof(checks, mutated, reloaded, clickedControlNames(interactionStmts), entered, firstMutLine, orderedPersistence, signedIn);
|
|
6824
|
+
const absenceProof = opts.absenceProof ?? "off";
|
|
6825
|
+
let absenceOnly = false;
|
|
6826
|
+
if (absenceProof !== "off" && proof.kind === "durable") {
|
|
6827
|
+
const existed = subjectsThatExisted(checks, interactionStmtsRaw);
|
|
6828
|
+
const kept = checks.filter(({ stmt }) => !isUnshownAbsence(stmt, existed, entered));
|
|
6829
|
+
absenceOnly = kept.length < checks.length && classifyOutcomeProof(kept, mutated, reloaded, clickedControlNames(interactionStmts), entered, firstMutLine, orderedPersistence, signedIn).kind !== "durable";
|
|
6830
|
+
if (absenceOnly && absenceProof === "on") {
|
|
6831
|
+
return {
|
|
6832
|
+
ok: false,
|
|
6833
|
+
severity: mutated ? "block" : "downgrade",
|
|
6834
|
+
reason: "the only outcome checks are absence checks (not visible / hidden / count 0) of something the test never showed, touched or typed: they pass whether or not the action worked \u2014 assert what the action produced (the new text, value, count or page), or assert the element present before it goes",
|
|
6835
|
+
signals: base2({ interacted, mutated, navOnly, hasOutcomeProof: false, terminal, absenceOnly: true })
|
|
6836
|
+
};
|
|
6837
|
+
}
|
|
6838
|
+
}
|
|
6626
6839
|
if (proof.kind === "durable") {
|
|
6627
|
-
const signals2 = base2({ interacted, mutated, navOnly, hasOutcomeProof: true, terminal });
|
|
6840
|
+
const signals2 = base2({ interacted, mutated, navOnly, hasOutcomeProof: true, terminal, ...absenceOnly ? { absenceOnly } : {} });
|
|
6628
6841
|
const { last, prev } = acts;
|
|
6629
6842
|
if (teardown !== null && last !== null && acts.count >= 2 && last.kind !== "fill" && (last.kind === "enter" || isCommitClick(interactionStmts[last.i]) && !(prev?.kind === "click" && isDestructiveClick(interactionStmts[prev.i])))) {
|
|
6630
6843
|
const lastLine = interactionStmtsWithLines[last.i].startLine;
|
|
@@ -6728,7 +6941,7 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
6728
6941
|
signals
|
|
6729
6942
|
};
|
|
6730
6943
|
}
|
|
6731
|
-
var ERROR_BANNER, OUTCOME_ALWAYS, FORM_INPUT, ANY_CLICK, NAV_LOCATOR, URL_PROOF, POLL_OPEN, POLL_PAGE_URL, POLL_PAGE_URL_ONLY, POLL_CALLS_MAX, RELOAD, EXPECT_STMT, BLOCK_SCAFFOLD2, TEST_BLOCK_OPEN, LOCATOR_BINDING, EXPECT_OPEN, STATE_MATCHER, CHROME_LOCATOR, CONTENT_ROLE, GET_BY_TEXT, BARE_CONTAINER_ROLE, HAS_TEXT_FILTER, OUTCOME_TEXT, SUCCESS_NOTICE_TEXT, NOT_A_SUCCESS_NOTICE, ANNOUNCE_ROLE, MESSAGE_SURFACE, TEXT_CONTENT_MATCHER, VISIBILITY_MATCHER, ADDITIVE_AFFORDANCE, EXCLUDE_AFFORDANCE, EMPTY_STATE_TEXT, AUTH_START, AUTH_END, LOGIN_CALL_LINE, INBOX_START, INBOX_END, NEGATED_ASSERT, NEGATED_ASSERT_NOT, CONST_CHAIN_MAX_DEPTH, TYPED_INPUT, TITLE_LINE, FAILURE_STATUS_ASSERT, FAILED_LIST_ASSERT, ENDPOINT_DOWN, NAVIGATION_RESPONSE_VAR, DIRECT_REQUEST_VAR, CATCH_ALL_PATTERN, GUARD_HANDLER, ABSENCE_MATCHER, VALUE_ABSENCE, OPTION_ABSENCE, NOT_BEFORE_MATCHER, ERROR_TEXT_WORDS, TEXT_REGEX_ARG, SCOPING_STEP, NEGATED_TEXT, ASYNC_DESTRUCTURE_OPEN, REQUEST_WORD, ROLE_NAME_RE, INTERACT_VERB, ROLE_SIG_RE, TRANSIENT_CONTROL_ROLES, POLL_CALLBACK, CONSTANT_WORD, CONSTANT_GLUE_CHARS, WORD_CHAR, MATCHER_ARGS_MAX, MATCHER_OPEN, ENTERED_VALUE, PAGE_NAV, ENV_READ, ENTERED_ENV, HAVE_VALUE_ENV, ACCOUNT_KEYS, ACCOUNT_ENV, ACCOUNT_CONST, IN_FLIGHT_TEXT, LOCATOR_VALUE_READ, LOCATOR_EXPR, ALWAYS_TRUE_ON_OBJECT, COUNT_AT_LEAST_ZERO, DEFINED_VALUE_READ, ALWAYS_DEFINED, SELF_COMPARE_MATCHER, IS_VISIBLE_TRUE, PAGE_VALUE_MATCHER, COUNT_ONE, URL_CHECK_ARG, PLAIN_PAGE_PATH, FORM_CONTROL_LOCATOR, CONTROL_VALUE_MATCHER, ACCOUNT_EMAIL_ENV, ENV_PASSWORD_ENTRY, ACCOUNT_CONTROL_ROLE, ASSERT_OR_WAIT, ACTS, actLinesOf, CLOSERS_ONLY, TEST_BODY_OPEN, COPY_CONTROL, COPIED_NOTICE, SEND_CONTROL, SEND_NOTICE, MARK_READ_CONTROL, APP_DATA_FIELD, COMMIT_CONTROL, NOT_COMMIT_CONTROL, DESTRUCTIVE_CONTROL, ENTER_PRESS, CONTROL_LABEL, isCommitClick, isDestructiveClick, TEARDOWN_OPEN;
|
|
6944
|
+
var ERROR_BANNER, OUTCOME_ALWAYS, FORM_INPUT, ANY_CLICK, NAV_LOCATOR, URL_PROOF, POLL_OPEN, POLL_PAGE_URL, POLL_PAGE_URL_ONLY, POLL_CALLS_MAX, RELOAD, EXPECT_STMT, BLOCK_SCAFFOLD2, TEST_BLOCK_OPEN, LOCATOR_BINDING, EXPECT_OPEN, STATE_MATCHER, CHROME_LOCATOR, CONTENT_ROLE, GET_BY_TEXT, BARE_CONTAINER_ROLE, HAS_TEXT_FILTER, OUTCOME_TEXT, SUCCESS_NOTICE_TEXT, NOT_A_SUCCESS_NOTICE, ANNOUNCE_ROLE, MESSAGE_SURFACE, TEXT_CONTENT_MATCHER, VISIBILITY_MATCHER, ADDITIVE_AFFORDANCE, EXCLUDE_AFFORDANCE, EMPTY_STATE_TEXT, AUTH_START, AUTH_END, LOGIN_CALL_LINE, INBOX_START, INBOX_END, NEGATED_ASSERT, NEGATED_ASSERT_NOT, CONST_CHAIN_MAX_DEPTH, TYPED_INPUT, TITLE_LINE, FAILURE_STATUS_ASSERT, FAILED_LIST_ASSERT, ENDPOINT_DOWN, NAVIGATION_RESPONSE_VAR, DIRECT_REQUEST_VAR, CATCH_ALL_PATTERN, GUARD_HANDLER, ABSENCE_MATCHER, VALUE_ABSENCE, OPTION_ABSENCE, NOT_BEFORE_MATCHER, ERROR_TEXT_WORDS, TEXT_REGEX_ARG, ABSENCE_READ, LOCATOR_USE, SCOPING_STEP, NEGATED_TEXT, ASYNC_DESTRUCTURE_OPEN, REQUEST_WORD, ROLE_NAME_RE, INTERACT_VERB, ROLE_SIG_RE, TRANSIENT_CONTROL_ROLES, POLL_CALLBACK, CONSTANT_WORD, CONSTANT_GLUE_CHARS, WORD_CHAR, MATCHER_ARGS_MAX, MATCHER_OPEN, ENTERED_VALUE, PAGE_NAV, ENV_READ, ENTERED_ENV, HAVE_VALUE_ENV, ACCOUNT_KEYS, ACCOUNT_ENV, ACCOUNT_CONST, IN_FLIGHT_TEXT, LOCATOR_VALUE_READ, LOCATOR_EXPR, ALWAYS_TRUE_ON_OBJECT, COUNT_AT_LEAST_ZERO, DEFINED_VALUE_READ, ALWAYS_DEFINED, SELF_COMPARE_MATCHER, IS_VISIBLE_TRUE, PAGE_VALUE_MATCHER, COUNT_ONE, ARIA_TEMPLATE_CALL, ARIA_ENTRY_SPLIT, ARIA_CONTENT_ROLES, ARIA_ENTRY, NOT_HIDDEN, NOT_COUNT_ZERO, URL_CHECK_ARG, PLAIN_PAGE_PATH, FORM_CONTROL_LOCATOR, CONTROL_VALUE_MATCHER, ACCOUNT_EMAIL_ENV, ENV_PASSWORD_ENTRY, ACCOUNT_CONTROL_ROLE, ASSERT_OR_WAIT, ACTS, actLinesOf, CLOSERS_ONLY, TEST_BODY_OPEN, COPY_CONTROL, COPIED_NOTICE, SEND_CONTROL, SEND_NOTICE, MARK_READ_CONTROL, APP_DATA_FIELD, COMMIT_CONTROL, NOT_COMMIT_CONTROL, DESTRUCTIVE_CONTROL, ENTER_PRESS, CONTROL_LABEL, isCommitClick, isDestructiveClick, TEARDOWN_OPEN;
|
|
6732
6945
|
var init_assertion_strength = __esm({
|
|
6733
6946
|
"../shared/dist/assertion-strength.js"() {
|
|
6734
6947
|
"use strict";
|
|
@@ -6817,6 +7030,8 @@ var init_assertion_strength = __esm({
|
|
|
6817
7030
|
NOT_BEFORE_MATCHER = /\.not\s*\.\s*(?=to[A-Z])/g;
|
|
6818
7031
|
ERROR_TEXT_WORDS = /error|fail|wrong|try again|unable|could ?n.?t|can.?t|problem|invalid|unavailable/i;
|
|
6819
7032
|
TEXT_REGEX_ARG = /(?:getByText|hasText|getByRole\([^)]{0,200}name)\s*[:(]\s*(\/(?:\\.|[^/\\\n])+\/[a-z]*)/;
|
|
7033
|
+
ABSENCE_READ = /\.toBeVisible\s*\(|\.toBeHidden\s*\(|\.toHaveCount\s*\(\s*0\s*\)|\.toBeAttached\s*\(|\.toHaveText\s*\(|\.toContainText\s*\(/;
|
|
7034
|
+
LOCATOR_USE = /\.\s*(?:click|dblclick|tap|hover|focus|fill|clear|press|pressSequentially|type|check|uncheck|setChecked|selectOption|setInputFiles|dragTo|selectText|waitFor)\s*\(/g;
|
|
6820
7035
|
SCOPING_STEP = /(?:\s*\.\s*(?:first|last|nth)\s*\([^()]*\))*\s*\.\s*(?:getBy[A-Z]\w*|locator|filter)\s*\(/y;
|
|
6821
7036
|
NEGATED_TEXT = /\.not\s*\.\s*(?:toHaveText|toContainText)\s*\(\s*(?:['"`]([^'"`]*)['"`]|\/((?:\\.|[^/\\\n])+)\/)?/;
|
|
6822
7037
|
ASYNC_DESTRUCTURE_OPEN = /async\s*\(\s*\{/g;
|
|
@@ -6858,6 +7073,29 @@ var init_assertion_strength = __esm({
|
|
|
6858
7073
|
IS_VISIBLE_TRUE = /^\)*\s*\.\s*(?:toBe\s*\(\s*true\s*\)|toBeTruthy\s*\(\s*\))/;
|
|
6859
7074
|
PAGE_VALUE_MATCHER = /^\)\s*\.\s*(?:toBe|toEqual|toStrictEqual|toMatch|toContain)\s*\(/;
|
|
6860
7075
|
COUNT_ONE = /\.\s*toHaveCount\s*\(\s*1\s*\)/;
|
|
7076
|
+
ARIA_TEMPLATE_CALL = /^\)\s*\.\s*toMatchAriaSnapshot\s*\(\s*(['"`])((?:\\[\s\S]|(?!\1)[^\\])*)\1/;
|
|
7077
|
+
ARIA_ENTRY_SPLIT = /(?:^|\s)-\s+(?=\/?[a-z][a-z-]*(?:\s|:|\[|$))/;
|
|
7078
|
+
ARIA_CONTENT_ROLES = /* @__PURE__ */ new Set([
|
|
7079
|
+
"listitem",
|
|
7080
|
+
"row",
|
|
7081
|
+
"cell",
|
|
7082
|
+
"gridcell",
|
|
7083
|
+
"article",
|
|
7084
|
+
"treeitem",
|
|
7085
|
+
"paragraph",
|
|
7086
|
+
"text",
|
|
7087
|
+
"strong",
|
|
7088
|
+
"emphasis",
|
|
7089
|
+
"code",
|
|
7090
|
+
"blockquote",
|
|
7091
|
+
"term",
|
|
7092
|
+
"definition",
|
|
7093
|
+
"alert",
|
|
7094
|
+
"status"
|
|
7095
|
+
]);
|
|
7096
|
+
ARIA_ENTRY = /^([a-z][a-z-]*)(?:\s+"((?:\\.|[^"\\])*)")?(?:\s*\[[^\]]*\])*\s*(?::\s*(\S.*)?)?$/s;
|
|
7097
|
+
NOT_HIDDEN = /\.not\s*\.\s*toBeHidden\s*\(/g;
|
|
7098
|
+
NOT_COUNT_ZERO = /\.not\s*\.\s*toHaveCount\s*\(\s*0\s*(?:,\s*|(?=\)))/g;
|
|
6861
7099
|
URL_CHECK_ARG = /\bpage\s*\.\s*waitForURL\s*\(\s*([^,)]+)|\bexpect(?:\s*\.\s*soft)?\s*\(\s*page\s*\)\s*\.\s*toHaveURL\s*\(\s*([^,)]+)/;
|
|
6862
7100
|
PLAIN_PAGE_PATH = /^\/[\w\-./~%]*(?:[?#][^\s]*)?$/;
|
|
6863
7101
|
FORM_CONTROL_LOCATOR = /getByRole\s*\(\s*['"`](?:combobox|switch|checkbox|radio|textbox|searchbox|spinbutton|slider)['"`]|getByLabel\s*\(|getByPlaceholder\s*\(/;
|
|
@@ -6903,6 +7141,12 @@ function isCancelledReason(error2) {
|
|
|
6903
7141
|
function isHeldHealRun(run) {
|
|
6904
7142
|
return run?.status === "PASSED" && typeof run.error === "string" && run.error.startsWith(HEAL_PATCH_HELD_RUN_ERROR_PREFIX);
|
|
6905
7143
|
}
|
|
7144
|
+
function mayBeUnverifiedHealPass(run, tags) {
|
|
7145
|
+
return !!run && run.status === "PASSED" && run.mode === "heal" && !isHeldHealRun(run) && (tags ?? []).includes(NEEDS_REVIEW_TAG);
|
|
7146
|
+
}
|
|
7147
|
+
function isUnverifiedHealPass(run, tags, healConfidence) {
|
|
7148
|
+
return mayBeUnverifiedHealPass(run, tags) && typeof healConfidence === "string" && UNVERIFIED_HEAL_CONFIDENCES.has(healConfidence);
|
|
7149
|
+
}
|
|
6906
7150
|
function isRunInterruptedError(error2) {
|
|
6907
7151
|
return typeof error2 === "string" && RUN_INTERRUPTED_ERROR_PREFIXES.some((prefix) => error2.startsWith(prefix));
|
|
6908
7152
|
}
|
|
@@ -6989,12 +7233,25 @@ function classifyErrorMessage(error2) {
|
|
|
6989
7233
|
return "config_issue";
|
|
6990
7234
|
if (EMAIL_NOT_RECEIVED_PREFIXES.some((prefix) => normalized.startsWith(prefix)))
|
|
6991
7235
|
return "email_not_received";
|
|
7236
|
+
if (SMS_NOT_RECEIVED_PREFIXES.some((prefix) => normalized.startsWith(prefix)))
|
|
7237
|
+
return "email_not_received";
|
|
6992
7238
|
if (isCancelledReason(error2))
|
|
6993
7239
|
return "cancelled";
|
|
6994
7240
|
if (isRetriedRunInterruption(error2))
|
|
6995
7241
|
return "interrupted";
|
|
6996
7242
|
return null;
|
|
6997
7243
|
}
|
|
7244
|
+
function isSmsNotReceivedError(error2) {
|
|
7245
|
+
if (typeof error2 !== "string")
|
|
7246
|
+
return false;
|
|
7247
|
+
const normalized = error2.replace(/^\s+/, "").replace(/^Error:\s*/i, "");
|
|
7248
|
+
return SMS_NOT_RECEIVED_PREFIXES.some((prefix) => normalized.startsWith(prefix));
|
|
7249
|
+
}
|
|
7250
|
+
function blockedRunLogLine(error2, durationMs) {
|
|
7251
|
+
const reason = classifyErrorMessage(error2);
|
|
7252
|
+
const tail = reason === "rate_limit" ? "rate-limit detected, not counted as failure" : reason === "config_issue" ? "config issue (needs setup or sign-in), not counted as failure" : reason === "email_not_received" ? "verification email not received, not counted as failure" : reason === "cancelled" ? "cancelled, not counted as failure" : reason === "interrupted" ? "run interrupted, not counted as failure" : "run error";
|
|
7253
|
+
return `BLOCKED (${durationMs}ms) \u2014 ${tail}`;
|
|
7254
|
+
}
|
|
6998
7255
|
function stripEnvironmentalPrefix(error2) {
|
|
6999
7256
|
for (const prefix of ENVIRONMENTAL_ERROR_PREFIXES) {
|
|
7000
7257
|
if (error2.startsWith(prefix)) {
|
|
@@ -7057,8 +7314,19 @@ function computePassRate(passed, tested) {
|
|
|
7057
7314
|
}
|
|
7058
7315
|
function summarizeHealth(items) {
|
|
7059
7316
|
const c = { passed: 0, failed: 0, errored: 0, environmental: 0, never_run: 0 };
|
|
7317
|
+
let rateLimited = 0;
|
|
7318
|
+
let configIssue = 0;
|
|
7060
7319
|
for (const item of items) {
|
|
7061
|
-
|
|
7320
|
+
const weight = item.weight ?? 1;
|
|
7321
|
+
const bucket = classifyTestHealth(item.run);
|
|
7322
|
+
c[bucket] += weight;
|
|
7323
|
+
if (bucket === "environmental") {
|
|
7324
|
+
const reason = classifyErrorMessage(item.run?.error);
|
|
7325
|
+
if (reason === "rate_limit")
|
|
7326
|
+
rateLimited += weight;
|
|
7327
|
+
else if (isConfigLikeReason(reason))
|
|
7328
|
+
configIssue += weight;
|
|
7329
|
+
}
|
|
7062
7330
|
}
|
|
7063
7331
|
const tested = c.passed + c.failed + c.errored;
|
|
7064
7332
|
return {
|
|
@@ -7066,6 +7334,8 @@ function summarizeHealth(items) {
|
|
|
7066
7334
|
failed: c.failed,
|
|
7067
7335
|
errored: c.errored,
|
|
7068
7336
|
environmental: c.environmental,
|
|
7337
|
+
rateLimited,
|
|
7338
|
+
configIssue,
|
|
7069
7339
|
neverRun: c.never_run,
|
|
7070
7340
|
tested,
|
|
7071
7341
|
total: tested + c.environmental + c.never_run,
|
|
@@ -7102,7 +7372,7 @@ function reportedBugWhere() {
|
|
|
7102
7372
|
function bugReviewStatus(status) {
|
|
7103
7373
|
return status === "QUARANTINED" ? "confirmed" : "needs-review";
|
|
7104
7374
|
}
|
|
7105
|
-
var USER_CANCELLED_RUN_ERROR, PLATFORM_SUPPORT_CANCELLED_RUN_ERROR, PLATFORM_ADMIN_CANCELLED_RUN_ERROR, ADMIN_FORCE_CANCELLED_RUN_ERROR, CHAIN_CANCELLED_RUN_ERROR, RETRY_HELD_RUN_ERROR, CANCELLED_REASON_PREFIXES, isUserCancelledError, HEAL_PATCH_HELD_RUN_ERROR_PREFIX, RUNNER_INTERRUPT_ERROR_PREFIX, SERVER_INTERRUPT_ERROR_PREFIX, RUN_LOST_ERROR_PREFIX, RUN_INTERRUPTED_ERROR_PREFIXES, RUN_INTERRUPTION_RETRIED_MARKER, RUN_INTERRUPTION_NOT_RETRIED_MARKERS, BUG_ASSERTION_TAG, UNEXPECTED_PASS_ERROR_PREFIX, BUG_TEST_BROKEN_ERROR_PREFIX, BUG_TEST_BROKEN_REASON, TEST_DID_NOT_RUN_ERROR, EMAIL_NOT_RECEIVED_PREFIXES, ENVIRONMENTAL_ERROR_PREFIXES, ENVIRONMENTAL_ERROR_STORED_PREFIXES, FEATURE_ROW_RUN_WINDOW, BUG_SURFACE_SUPPRESSING_TAGS, QUARANTINE_CLOSE_TAGS, BUG_CANDIDATE_TAG, BUG_TEST_BROKEN_TAG;
|
|
7375
|
+
var USER_CANCELLED_RUN_ERROR, PLATFORM_SUPPORT_CANCELLED_RUN_ERROR, PLATFORM_ADMIN_CANCELLED_RUN_ERROR, ADMIN_FORCE_CANCELLED_RUN_ERROR, CHAIN_CANCELLED_RUN_ERROR, RETRY_HELD_RUN_ERROR, CANCELLED_REASON_PREFIXES, isUserCancelledError, HEAL_PATCH_HELD_RUN_ERROR_PREFIX, UNVERIFIED_HEAL_CONFIDENCES, NEEDS_REVIEW_TAG, RUNNER_INTERRUPT_ERROR_PREFIX, SERVER_INTERRUPT_ERROR_PREFIX, RUN_LOST_ERROR_PREFIX, RUN_INTERRUPTED_ERROR_PREFIXES, RUN_INTERRUPTION_RETRIED_MARKER, RUN_INTERRUPTION_NOT_RETRIED_MARKERS, BUG_ASSERTION_TAG, UNEXPECTED_PASS_ERROR_PREFIX, BUG_TEST_BROKEN_ERROR_PREFIX, BUG_TEST_BROKEN_REASON, TEST_DID_NOT_RUN_ERROR, EMAIL_NOT_RECEIVED_PREFIXES, SMS_NOT_RECEIVED_PREFIXES, ENVIRONMENTAL_ERROR_PREFIXES, ENVIRONMENTAL_ERROR_STORED_PREFIXES, FEATURE_ROW_RUN_WINDOW, BUG_SURFACE_SUPPRESSING_TAGS, QUARANTINE_CLOSE_TAGS, BUG_CANDIDATE_TAG, BUG_TEST_BROKEN_TAG;
|
|
7106
7376
|
var init_run_classification = __esm({
|
|
7107
7377
|
"../shared/dist/run-classification.js"() {
|
|
7108
7378
|
"use strict";
|
|
@@ -7122,6 +7392,8 @@ var init_run_classification = __esm({
|
|
|
7122
7392
|
];
|
|
7123
7393
|
isUserCancelledError = isCancelledReason;
|
|
7124
7394
|
HEAL_PATCH_HELD_RUN_ERROR_PREFIX = "Heal patch held";
|
|
7395
|
+
UNVERIFIED_HEAL_CONFIDENCES = /* @__PURE__ */ new Set(["low", "medium"]);
|
|
7396
|
+
NEEDS_REVIEW_TAG = "@needs-review";
|
|
7125
7397
|
RUNNER_INTERRUPT_ERROR_PREFIX = "Runner shutting down";
|
|
7126
7398
|
SERVER_INTERRUPT_ERROR_PREFIX = "Run interrupted by server restart";
|
|
7127
7399
|
RUN_LOST_ERROR_PREFIX = "Runner lost this run";
|
|
@@ -7142,10 +7414,12 @@ var init_run_classification = __esm({
|
|
|
7142
7414
|
"VERIFICATION_EMAIL_HAS_NO_CODE:",
|
|
7143
7415
|
"VERIFICATION_EMAIL_HAS_NO_LINK:"
|
|
7144
7416
|
];
|
|
7417
|
+
SMS_NOT_RECEIVED_PREFIXES = ["VERIFICATION_SMS_NOT_RECEIVED:"];
|
|
7145
7418
|
ENVIRONMENTAL_ERROR_PREFIXES = [
|
|
7146
7419
|
"RATE_LIMIT_BLOCKED:",
|
|
7147
7420
|
"CONFIG_ISSUE:",
|
|
7148
|
-
...EMAIL_NOT_RECEIVED_PREFIXES
|
|
7421
|
+
...EMAIL_NOT_RECEIVED_PREFIXES,
|
|
7422
|
+
...SMS_NOT_RECEIVED_PREFIXES
|
|
7149
7423
|
];
|
|
7150
7424
|
ENVIRONMENTAL_ERROR_STORED_PREFIXES = [
|
|
7151
7425
|
...ENVIRONMENTAL_ERROR_PREFIXES.flatMap((prefix) => [prefix, `Error: ${prefix}`]),
|
|
@@ -9530,6 +9804,19 @@ function googleBrokerUnavailableLine(lines, testError) {
|
|
|
9530
9804
|
}
|
|
9531
9805
|
return last;
|
|
9532
9806
|
}
|
|
9807
|
+
function googleSignInRefusedLine(lines) {
|
|
9808
|
+
let last = null;
|
|
9809
|
+
for (const raw of lines ?? []) {
|
|
9810
|
+
for (const line of String(raw).split("\n")) {
|
|
9811
|
+
const text = line.trim();
|
|
9812
|
+
if (GOOGLE_SIGN_IN_REFUSED.test(text))
|
|
9813
|
+
last = text;
|
|
9814
|
+
else if (GOOGLE_SIGNED_IN.test(text))
|
|
9815
|
+
last = null;
|
|
9816
|
+
}
|
|
9817
|
+
}
|
|
9818
|
+
return last;
|
|
9819
|
+
}
|
|
9533
9820
|
function stepConsoleLines(result) {
|
|
9534
9821
|
const steps = Array.isArray(result) ? result : result && typeof result === "object" && Array.isArray(result.stepResults) ? result.stepResults : [];
|
|
9535
9822
|
return steps.flatMap((step) => {
|
|
@@ -9537,7 +9824,23 @@ function stepConsoleLines(result) {
|
|
|
9537
9824
|
return Array.isArray(logs) ? logs.filter((line) => typeof line === "string") : [];
|
|
9538
9825
|
});
|
|
9539
9826
|
}
|
|
9540
|
-
|
|
9827
|
+
function googleSignInRefusedReason(lines) {
|
|
9828
|
+
let reason = null;
|
|
9829
|
+
for (const raw of lines ?? []) {
|
|
9830
|
+
for (const line of String(raw).split("\n")) {
|
|
9831
|
+
const text = line.trim();
|
|
9832
|
+
if (GOOGLE_SIGNED_IN.test(text)) {
|
|
9833
|
+
reason = null;
|
|
9834
|
+
continue;
|
|
9835
|
+
}
|
|
9836
|
+
const m = GOOGLE_SIGN_IN_ANSWER.exec(text);
|
|
9837
|
+
if (m)
|
|
9838
|
+
reason = m[1];
|
|
9839
|
+
}
|
|
9840
|
+
}
|
|
9841
|
+
return reason;
|
|
9842
|
+
}
|
|
9843
|
+
var GOOGLE_BROKER_UNAVAILABLE, GOOGLE_BROKER_ASKED, GOOGLE_SIGNED_IN, TIMEOUT_ERROR, GOOGLE_SIGN_IN_REFUSED, GOOGLE_SIGN_IN_ANSWER;
|
|
9541
9844
|
var init_google_broker_lines = __esm({
|
|
9542
9845
|
"../shared/dist/google-broker-lines.js"() {
|
|
9543
9846
|
"use strict";
|
|
@@ -9545,6 +9848,8 @@ var init_google_broker_lines = __esm({
|
|
|
9545
9848
|
GOOGLE_BROKER_ASKED = /^\[google-sign-in\] the app started Google sign-in; asking the broker/;
|
|
9546
9849
|
GOOGLE_SIGNED_IN = /^\[google-sign-in\] returned to the app with Google sign-in/;
|
|
9547
9850
|
TIMEOUT_ERROR = /Test timeout of \d+ms exceeded|TimeoutError|Timeout:? \d+ ?ms/i;
|
|
9851
|
+
GOOGLE_SIGN_IN_REFUSED = /^\[google-sign-in\] (?:not_seeded|not_enabled|expired|needs_reseed|device_approval|needs_verification|policy_rejected|unsupported_flow|unsupported_one_tap): /;
|
|
9852
|
+
GOOGLE_SIGN_IN_ANSWER = /^\[google-sign-in\] ([a-z][a-z0-9_]*): /;
|
|
9548
9853
|
}
|
|
9549
9854
|
});
|
|
9550
9855
|
|
|
@@ -9596,22 +9901,87 @@ function isIntentionalNegativeAuthTest(input) {
|
|
|
9596
9901
|
const meta = [input.testName, input.description].filter(Boolean).join(" ");
|
|
9597
9902
|
return matchesAny(meta, INTENTIONAL_NEGATIVE_AUTH);
|
|
9598
9903
|
}
|
|
9904
|
+
function signInStepPassedBeforeFailure(steps) {
|
|
9905
|
+
const list = steps ?? [];
|
|
9906
|
+
const failedAt = list.findIndex((step) => typeof step.status === "string" && step.status !== "passed" && step.status !== "skipped");
|
|
9907
|
+
if (failedAt <= 0)
|
|
9908
|
+
return false;
|
|
9909
|
+
if (SIGN_IN_STEP_TITLE.test(list[failedAt].title ?? ""))
|
|
9910
|
+
return false;
|
|
9911
|
+
return list.slice(0, failedAt).some((step) => step.status === "passed" && SIGN_IN_STEP_TITLE.test(step.title ?? ""));
|
|
9912
|
+
}
|
|
9913
|
+
function loginFormAlertTexts(body) {
|
|
9914
|
+
const text = body.length > ERROR_CONTEXT_CAP ? body.slice(0, ERROR_CONTEXT_CAP) : body;
|
|
9915
|
+
const blocks = [];
|
|
9916
|
+
let open = null;
|
|
9917
|
+
for (const line of text.split("\n")) {
|
|
9918
|
+
const fence = /^```(\w*)$/.exec(line.trim());
|
|
9919
|
+
if (fence) {
|
|
9920
|
+
if (open) {
|
|
9921
|
+
blocks.push(open);
|
|
9922
|
+
open = null;
|
|
9923
|
+
} else if (fence[1].toLowerCase() === "yaml")
|
|
9924
|
+
open = [];
|
|
9925
|
+
continue;
|
|
9926
|
+
}
|
|
9927
|
+
if (open)
|
|
9928
|
+
open.push(line);
|
|
9929
|
+
}
|
|
9930
|
+
const alerts = [];
|
|
9931
|
+
for (const lines of blocks) {
|
|
9932
|
+
if (!lines.some((l) => SNAPSHOT_PASSWORD_FIELD.test(l)))
|
|
9933
|
+
continue;
|
|
9934
|
+
for (let i = 0; i < lines.length && alerts.length < MAX_ALERTS; i++) {
|
|
9935
|
+
const m = SNAPSHOT_ALERT.exec(lines[i]);
|
|
9936
|
+
if (!m)
|
|
9937
|
+
continue;
|
|
9938
|
+
const indent = m[1].length;
|
|
9939
|
+
const parts = [m[2]];
|
|
9940
|
+
let j = i + 1;
|
|
9941
|
+
for (; j < lines.length; j++) {
|
|
9942
|
+
const lead = /^\s*/.exec(lines[j])?.[0].length ?? 0;
|
|
9943
|
+
if (lines[j].trim() === "" || lead <= indent)
|
|
9944
|
+
break;
|
|
9945
|
+
parts.push(lines[j].trim());
|
|
9946
|
+
}
|
|
9947
|
+
alerts.push(parts.join(" ").slice(0, MAX_ALERT_CHARS));
|
|
9948
|
+
i = j - 1;
|
|
9949
|
+
}
|
|
9950
|
+
}
|
|
9951
|
+
return alerts;
|
|
9952
|
+
}
|
|
9953
|
+
function stepLoginFormAlerts(steps) {
|
|
9954
|
+
const out = [];
|
|
9955
|
+
for (const sr of steps ?? []) {
|
|
9956
|
+
for (const a of sr.attachments ?? []) {
|
|
9957
|
+
if (a?.name === "error-context" && typeof a.body === "string")
|
|
9958
|
+
out.push(...loginFormAlertTexts(a.body));
|
|
9959
|
+
}
|
|
9960
|
+
}
|
|
9961
|
+
return out;
|
|
9962
|
+
}
|
|
9599
9963
|
function detectAuthBlock(input) {
|
|
9600
9964
|
const tags = input.tags ?? [];
|
|
9601
9965
|
const isAuthed = tags.some((t) => AUTHED_TAGS.includes(t));
|
|
9602
|
-
|
|
9966
|
+
const signsInInline2 = !isAuthed && codeReadsStoredCredentials(input.code);
|
|
9967
|
+
if (!isAuthed && !signsInInline2)
|
|
9603
9968
|
return NO_DETECTION;
|
|
9604
9969
|
if (isIntentionalNegativeAuthTest(input))
|
|
9605
9970
|
return NO_DETECTION;
|
|
9971
|
+
if (signInStepPassedBeforeFailure(input.stepResults))
|
|
9972
|
+
return NO_DETECTION;
|
|
9606
9973
|
const sources = [];
|
|
9607
|
-
if (
|
|
9608
|
-
|
|
9609
|
-
|
|
9610
|
-
|
|
9611
|
-
|
|
9612
|
-
|
|
9613
|
-
|
|
9974
|
+
if (isAuthed) {
|
|
9975
|
+
if (input.error)
|
|
9976
|
+
sources.push(stripEchoLines(input.error));
|
|
9977
|
+
if (input.logs)
|
|
9978
|
+
sources.push(stripEchoLines(input.logs));
|
|
9979
|
+
for (const sr of input.stepResults ?? []) {
|
|
9980
|
+
if (sr.error)
|
|
9981
|
+
sources.push(stripEchoLines(sr.error));
|
|
9982
|
+
}
|
|
9614
9983
|
}
|
|
9984
|
+
sources.push(...stepLoginFormAlerts(input.stepResults));
|
|
9615
9985
|
for (const text of sources) {
|
|
9616
9986
|
if (!text)
|
|
9617
9987
|
continue;
|
|
@@ -9660,10 +10030,11 @@ function detectApiColdSessionBlock(input) {
|
|
|
9660
10030
|
function coldSessionConfigMessage(context, reason, evidence) {
|
|
9661
10031
|
return `CONFIG_ISSUE: ${context} without valid injected auth (${reason}) \u2014 no session cookie was injected this run. Ensure the project login (auth-setup recipe / prewarm) is configured so the shared session jar warms (a project with no login: set TEST_USER_EMAIL and TEST_USER_PASSWORD in Test Data \u2192 Test Variables so a session can be captured); for endpoints that authenticate with a standing API key or bearer header instead, set them in the project's API_AUTH_HEADERS variable (injected as request headers). Evidence: ${evidence.join("; ")}`;
|
|
9662
10032
|
}
|
|
9663
|
-
var NO_DETECTION, AUTHED_TAGS, LOGIN_CTX, AUTH_BLOCK_SIGNATURES, INTENTIONAL_NEGATIVE_AUTH, ECHO_LINE_RE, UNAUTHORIZED_TEXT_RE;
|
|
10033
|
+
var NO_DETECTION, AUTHED_TAGS, LOGIN_CTX, AUTH_BLOCK_SIGNATURES, INTENTIONAL_NEGATIVE_AUTH, ECHO_LINE_RE, SIGN_IN_STEP_TITLE, ERROR_CONTEXT_CAP, MAX_ALERTS, MAX_ALERT_CHARS, SNAPSHOT_PASSWORD_FIELD, SNAPSHOT_ALERT, UNAUTHORIZED_TEXT_RE;
|
|
9664
10034
|
var init_auth_block_detector = __esm({
|
|
9665
10035
|
"../shared/dist/auth-block-detector.js"() {
|
|
9666
10036
|
"use strict";
|
|
10037
|
+
init_auth_plan();
|
|
9667
10038
|
NO_DETECTION = { detected: false, reason: "", evidence: [] };
|
|
9668
10039
|
AUTHED_TAGS = ["@needs-auth", "@inline-login"];
|
|
9669
10040
|
LOGIN_CTX = "\\b(?:log\\s*in|login|logging\\s+in|sign[\\s-]?in|signing\\s+in|continue)\\b";
|
|
@@ -9673,6 +10044,10 @@ var init_auth_block_detector = __esm({
|
|
|
9673
10044
|
{ reason: "invalid credentials", re: /\b(invalid|incorrect|wrong|bad)\s+(login\s+)?credentials\b/i },
|
|
9674
10045
|
{ reason: "credentials do not match", re: /\bcredentials\b[^\n]{0,40}\b(do(?:es)?\s*n['’]?t|do\s+not)\s+match\b/i },
|
|
9675
10046
|
{ reason: "incorrect email or password", re: /\b(incorrect|invalid|wrong)\s+(email|username)\s+or\s+password\b/i },
|
|
10047
|
+
{ reason: "username and password do not match", re: /\b(?:user\s*name|e-?mail)\s+and\s+password\s+(?:do(?:es)?\s*n['’]?t|do(?:es)?\s+not)\s+match\b/i },
|
|
10048
|
+
// A locked account is a blocker of the same kind: the configured user can't sign in until it is unlocked. The
|
|
10049
|
+
// rate-limit detector keeps the timed lockouts ("temporarily locked", "too many attempts").
|
|
10050
|
+
{ reason: "account locked out", re: /\b(?:user|account)\b[^\n]{0,30}\b(?:has\s+been|is)\s+locked\s+out\b/i },
|
|
9676
10051
|
// Require an EXPLICIT negative (codex #21): the old `(not\s+)?(confirmed|verified)` made the negation
|
|
9677
10052
|
// optional, so a benign "Email verified" success message / feature assertion matched and hid a real
|
|
9678
10053
|
// feature failure as a CONFIG_ISSUE. Only "email not (yet) confirmed/verified" or "unconfirmed/unverified".
|
|
@@ -9704,6 +10079,12 @@ var init_auth_block_detector = __esm({
|
|
|
9704
10079
|
/\b(reject|deny|denied|block(ed)?)\b[^\n]{0,20}\b(login|sign[\s-]?in|auth|credential|password)\b/i
|
|
9705
10080
|
];
|
|
9706
10081
|
ECHO_LINE_RE = /^\s*(?:(?:📋|🎭|🌐|⚙️?)|(?:stderr:\s*|stdout:\s*)?Locator:)/u;
|
|
10082
|
+
SIGN_IN_STEP_TITLE = /\b(?:log(?:ging)?\s*in(?:to)?|sign(?:ing)?[\s-]?in(?:to)?|authenticat(?:e|es|ed|ing|ion))\b/i;
|
|
10083
|
+
ERROR_CONTEXT_CAP = 64 * 1024;
|
|
10084
|
+
MAX_ALERTS = 20;
|
|
10085
|
+
MAX_ALERT_CHARS = 1e3;
|
|
10086
|
+
SNAPSHOT_PASSWORD_FIELD = /^\s*- textbox "[^"\n]{0,80}\bpass(?:word|code)?\b/i;
|
|
10087
|
+
SNAPSHOT_ALERT = /^(\s*)- alert\b(.*)$/;
|
|
9707
10088
|
UNAUTHORIZED_TEXT_RE = /(?:return(?:s|ed|ing)?|respond(?:s|ed|ing)?|got|receiv(?:e|ed|ing)|gives?|sends?|yield(?:s|ed|ing)?|results?\s+in)\s+(?:a\s+|an\s+|the\s+)?(?:401|403)\b|\bstatus(?:\s+code)?\s*(?::\s*)?(?:401|403)\b|\bHTTP\/[\d.]+\s+(?:401|403)\b|(?:401|403)['’]d\b|(?:[→⇒]|->)\s*(?:401|403)\b|(?:return(?:s|ed|ing)?|respond(?:s|ed|ing)?|got|receiv(?:e|ed|ing)|threw|throws?)\s+(?:a\s+|an\s+)?(?:unauthorized|forbidden)\b|\bnot\s+authenticated\b/i;
|
|
9708
10089
|
}
|
|
9709
10090
|
});
|
|
@@ -10138,6 +10519,77 @@ var init_redact_needles = __esm({
|
|
|
10138
10519
|
}
|
|
10139
10520
|
});
|
|
10140
10521
|
|
|
10522
|
+
// ../shared/dist/credential-header-scrub.js
|
|
10523
|
+
function scrubCredentialHeaders(text) {
|
|
10524
|
+
if (text.length < 6)
|
|
10525
|
+
return text;
|
|
10526
|
+
let out = text.replace(HEADER_LINE, (match, keyQuote, name, sep, value) => {
|
|
10527
|
+
if (value === "" || ALREADY_REDACTED.test(value))
|
|
10528
|
+
return match;
|
|
10529
|
+
if (COOKIE_NAME.test(name) && !value.includes("="))
|
|
10530
|
+
return match;
|
|
10531
|
+
if (AUTHORIZATION_NAME.test(name) && WORDS_ONLY.test(value))
|
|
10532
|
+
return match;
|
|
10533
|
+
const q = value[0] === '"' || value[0] === "'" ? value[0] : "";
|
|
10534
|
+
return `${keyQuote}${name}${keyQuote}${sep}${q}${REDACTED2}${q}`;
|
|
10535
|
+
});
|
|
10536
|
+
out = out.replace(SET_COOKIE_PAIR, `$1${REDACTED2}`);
|
|
10537
|
+
return out;
|
|
10538
|
+
}
|
|
10539
|
+
function isCredentialHeaderName(name) {
|
|
10540
|
+
return name.length <= 100 && HEADER_NAME_ONLY.test(name);
|
|
10541
|
+
}
|
|
10542
|
+
function scrubCredentialHeaderValue(value) {
|
|
10543
|
+
if (typeof value === "string")
|
|
10544
|
+
return value === REDACTED2 || value === "" ? value : REDACTED2;
|
|
10545
|
+
if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
|
|
10546
|
+
const next = value.map((item) => item === REDACTED2 || item === "" ? item : REDACTED2);
|
|
10547
|
+
return next.every((item, i) => item === value[i]) ? value : next;
|
|
10548
|
+
}
|
|
10549
|
+
return value;
|
|
10550
|
+
}
|
|
10551
|
+
function scrubCredentialHeadersDeep(value) {
|
|
10552
|
+
if (typeof value === "string")
|
|
10553
|
+
return scrubCredentialHeaders(value);
|
|
10554
|
+
if (Array.isArray(value)) {
|
|
10555
|
+
let changed = false;
|
|
10556
|
+
const next = value.map((item) => {
|
|
10557
|
+
const scrubbed = scrubCredentialHeadersDeep(item);
|
|
10558
|
+
if (scrubbed !== item)
|
|
10559
|
+
changed = true;
|
|
10560
|
+
return scrubbed;
|
|
10561
|
+
});
|
|
10562
|
+
return changed ? next : value;
|
|
10563
|
+
}
|
|
10564
|
+
if (value !== null && typeof value === "object") {
|
|
10565
|
+
let changed = false;
|
|
10566
|
+
const next = {};
|
|
10567
|
+
for (const [k, v] of Object.entries(value)) {
|
|
10568
|
+
const scrubbed = isCredentialHeaderName(k) ? scrubCredentialHeaderValue(v) : scrubCredentialHeadersDeep(v);
|
|
10569
|
+
if (scrubbed !== v)
|
|
10570
|
+
changed = true;
|
|
10571
|
+
next[k] = scrubbed;
|
|
10572
|
+
}
|
|
10573
|
+
return changed ? next : value;
|
|
10574
|
+
}
|
|
10575
|
+
return value;
|
|
10576
|
+
}
|
|
10577
|
+
var REDACTED2, HEADER_NAMES, COOKIE_NAME, AUTHORIZATION_NAME, WORDS_ONLY, HEADER_NAME_ONLY, HEADER_LINE, ALREADY_REDACTED, SET_COOKIE_PAIR;
|
|
10578
|
+
var init_credential_header_scrub = __esm({
|
|
10579
|
+
"../shared/dist/credential-header-scrub.js"() {
|
|
10580
|
+
"use strict";
|
|
10581
|
+
REDACTED2 = "[REDACTED]";
|
|
10582
|
+
HEADER_NAMES = "cookie2?|set-cookie2?|proxy-authorization|authorization|api-?key|(?:x-)?(?:csrf|xsrf)[a-z0-9-]{0,30}|x-[a-z0-9-]{0,40}?(?:token|session|secret|key|auth)[a-z0-9-]{0,40}";
|
|
10583
|
+
COOKIE_NAME = /^(?:set-)?cookie2?$/i;
|
|
10584
|
+
AUTHORIZATION_NAME = /^(?:proxy-)?authorization$/i;
|
|
10585
|
+
WORDS_ONLY = /^[A-Za-z]+(?: [A-Za-z]+){0,3}$/;
|
|
10586
|
+
HEADER_NAME_ONLY = new RegExp(`^(?:${HEADER_NAMES})$`, "i");
|
|
10587
|
+
HEADER_LINE = new RegExp(`(?<![A-Za-z0-9_-])(["']?)(${HEADER_NAMES})\\1(\\s*:\\s*)("(?:[^"\\\\\\r\\n]|\\\\.)*"|'(?:[^'\\\\\\r\\n]|\\\\.)*'|[^\\r\\n\\x1b]*)`, "gi");
|
|
10588
|
+
ALREADY_REDACTED = /^["']?(?:[A-Za-z][\w-]*\s+)?\[REDACTED\]["']?[,;]?\s*$/;
|
|
10589
|
+
SET_COOKIE_PAIR = /(?<![A-Za-z0-9_-])([A-Za-z0-9_.%-]{1,64}=)(?!\[REDACTED\])([^\s;,"'<>]{6,2048})(?=;\s*(?:Path|Domain|Expires|Max-Age|HttpOnly|Secure|SameSite|Partitioned)\b)/gi;
|
|
10590
|
+
}
|
|
10591
|
+
});
|
|
10592
|
+
|
|
10141
10593
|
// ../shared/dist/deepgram-voices.js
|
|
10142
10594
|
function voice(family, name, gender, accent, description) {
|
|
10143
10595
|
const label = name.charAt(0).toUpperCase() + name.slice(1);
|
|
@@ -10714,13 +11166,13 @@ function isSensitiveQueryKey(key) {
|
|
|
10714
11166
|
return SENSITIVE_QUERY_KEY_RE.test(key);
|
|
10715
11167
|
}
|
|
10716
11168
|
function redactSecretValues(value) {
|
|
10717
|
-
return value.replace(MCP_SECRET_VALUE_RE,
|
|
11169
|
+
return value.replace(MCP_SECRET_VALUE_RE, REDACTED3);
|
|
10718
11170
|
}
|
|
10719
11171
|
function scrubReturnUrlValue(value, depth) {
|
|
10720
11172
|
if (!/[?%]/.test(value))
|
|
10721
11173
|
return value;
|
|
10722
11174
|
if (depth >= MAX_NESTED_URL_DEPTH)
|
|
10723
|
-
return
|
|
11175
|
+
return REDACTED3;
|
|
10724
11176
|
const q = value.indexOf("?");
|
|
10725
11177
|
if (q !== -1) {
|
|
10726
11178
|
const hashIdx = value.indexOf("#", q);
|
|
@@ -10742,7 +11194,7 @@ function scrubReturnUrlValue(value, depth) {
|
|
|
10742
11194
|
try {
|
|
10743
11195
|
return encodeURIComponent(scrubbed);
|
|
10744
11196
|
} catch {
|
|
10745
|
-
return
|
|
11197
|
+
return REDACTED3;
|
|
10746
11198
|
}
|
|
10747
11199
|
}
|
|
10748
11200
|
function scrubQuery(search, depth) {
|
|
@@ -10758,7 +11210,7 @@ function scrubQuery(search, depth) {
|
|
|
10758
11210
|
params.forEach((value, key) => {
|
|
10759
11211
|
let scrubbed = value;
|
|
10760
11212
|
if (isSensitiveQueryKey(key)) {
|
|
10761
|
-
scrubbed =
|
|
11213
|
+
scrubbed = REDACTED3;
|
|
10762
11214
|
} else {
|
|
10763
11215
|
if (RETURN_URL_QUERY_KEY_RE.test(key))
|
|
10764
11216
|
scrubbed = scrubReturnUrlValue(scrubbed, depth);
|
|
@@ -10870,12 +11322,12 @@ function scrubUrlPropertyBag(props) {
|
|
|
10870
11322
|
} catch {
|
|
10871
11323
|
}
|
|
10872
11324
|
}
|
|
10873
|
-
var SENSITIVE_QUERY_KEY_RE,
|
|
11325
|
+
var SENSITIVE_QUERY_KEY_RE, REDACTED3, MCP_SECRET_VALUE_RE, RETURN_URL_QUERY_KEY_RE, MAX_NESTED_URL_DEPTH, MAX_PROPERTY_SWEEP_DEPTH;
|
|
10874
11326
|
var init_analytics_url = __esm({
|
|
10875
11327
|
"../shared/dist/analytics-url.js"() {
|
|
10876
11328
|
"use strict";
|
|
10877
11329
|
SENSITIVE_QUERY_KEY_RE = /^(access_token|refresh_token|id_token|token|code|state|password|secret|api[_-]?key|auth|authorization|session|jwt|otp|email|phone|magic[_-]?link)$|token|secret|password|credential|email|phone|(^|[_-])(otp|verification|auth)[_-]?code($|[_-])|(^|[_-])(state|session|grant)$/i;
|
|
10878
|
-
|
|
11330
|
+
REDACTED3 = "[redacted]";
|
|
10879
11331
|
MCP_SECRET_VALUE_RE = /mcp_(consent|code|at|rt)_[A-Za-z0-9]+/g;
|
|
10880
11332
|
RETURN_URL_QUERY_KEY_RE = /^(next|redirect|return|continue)([_-]?(to|url|uri|path))?$/i;
|
|
10881
11333
|
MAX_NESTED_URL_DEPTH = 5;
|
|
@@ -13705,8 +14157,19 @@ function successContradicted(text) {
|
|
|
13705
14157
|
}
|
|
13706
14158
|
return SUCCESS_NO_STATUS_RE.test(text) || OFF_BY_RE.test(text);
|
|
13707
14159
|
}
|
|
14160
|
+
function negatedSafeguard(text) {
|
|
14161
|
+
for (const match of matches(NEGATED_SAFEGUARD_RE, text)) {
|
|
14162
|
+
if (!NOT_KEPT_RE.test(match[1]))
|
|
14163
|
+
return true;
|
|
14164
|
+
const head = text.slice(Math.max(0, match.index - SAFEGUARD_LOOKBEHIND), match.index);
|
|
14165
|
+
const sentence = head.slice(Math.max(head.lastIndexOf("."), head.lastIndexOf(";"), head.lastIndexOf("\n")) + 1);
|
|
14166
|
+
if (!REFUSED_INPUT_RE.test(sentence))
|
|
14167
|
+
return true;
|
|
14168
|
+
}
|
|
14169
|
+
return false;
|
|
14170
|
+
}
|
|
13708
14171
|
function claimsDefect(text) {
|
|
13709
|
-
if (BUG_LABEL_RE.test(text) || SILENT_RE.test(text) || CONCESSION_RE.test(text) || successContradicted(text) ||
|
|
14172
|
+
if (BUG_LABEL_RE.test(text) || SILENT_RE.test(text) || CONCESSION_RE.test(text) || successContradicted(text) || negatedSafeguard(text)) {
|
|
13710
14173
|
return true;
|
|
13711
14174
|
}
|
|
13712
14175
|
return BAD_VALUE_RE.test(text) && !REFUSAL_RE.test(text);
|
|
@@ -13714,7 +14177,7 @@ function claimsDefect(text) {
|
|
|
13714
14177
|
function hasTestFailContract(code) {
|
|
13715
14178
|
return TEST_FAIL_CONTRACT_RE.test(code);
|
|
13716
14179
|
}
|
|
13717
|
-
var BUG_LABEL_RE, SILENT_RE, CONCESSION_RE, SUCCESS_REPORT, SUCCESS_CONTRADICTED_RE, CONTRADICTION_VETO_RE, NOTHING_PROVIDED_RE, UNTOUCHED_SUBSETS, ACTION_LOOKBEHIND, TRAILING_ACTION_RE, ADJECTIVE_BEFORE_NOUN_RE, SUCCESS_SAME_STATE_RE, GENERIC_REPORT_RE, SAME_STATE, OTHER_ITEM_RE, SUCCESS_STATUS_RE, STATUS_ACTION_RE, SUCCESS_WITHOUT_EFFECT_RE, COUNT_UNCHANGED_RE, CLEARING_ACTION_RE, NOT_A_CLEARING_RE, SUCCESS_NO_STATUS_RE, OFF_BY_RE, NEGATED_SAFEGUARD_RE, BAD_VALUE_RE, REFUSAL_RE, TEST_FAIL_CONTRACT_RE;
|
|
14180
|
+
var BUG_LABEL_RE, SILENT_RE, CONCESSION_RE, SUCCESS_REPORT, SUCCESS_CONTRADICTED_RE, CONTRADICTION_VETO_RE, NOTHING_PROVIDED_RE, UNTOUCHED_SUBSETS, ACTION_LOOKBEHIND, TRAILING_ACTION_RE, ADJECTIVE_BEFORE_NOUN_RE, SUCCESS_SAME_STATE_RE, GENERIC_REPORT_RE, SAME_STATE, OTHER_ITEM_RE, SUCCESS_STATUS_RE, STATUS_ACTION_RE, SUCCESS_WITHOUT_EFFECT_RE, COUNT_UNCHANGED_RE, CLEARING_ACTION_RE, NOT_A_CLEARING_RE, SUCCESS_NO_STATUS_RE, OFF_BY_RE, NEGATED_SAFEGUARD_RE, NOT_KEPT_RE, REFUSED_INPUT_RE, SAFEGUARD_LOOKBEHIND, BAD_VALUE_RE, REFUSAL_RE, TEST_FAIL_CONTRACT_RE;
|
|
13718
14181
|
var init_claims_defect = __esm({
|
|
13719
14182
|
"../shared/dist/claims-defect.js"() {
|
|
13720
14183
|
"use strict";
|
|
@@ -13758,7 +14221,10 @@ var init_claims_defect = __esm({
|
|
|
13758
14221
|
NOT_A_CLEARING_RE = /\b(?:cancel|refresh|reload|preview|open|view|fail|hover|scroll|sort|filter|search)\w*/i;
|
|
13759
14222
|
SUCCESS_NO_STATUS_RE = /\bsuccess\w*\b[^.;\n]{0,30}?\b(?:(?:do|does|did) not|don't|doesn't|didn't) (?:change|update|move)\b[^.;\n]{0,20}?\bstatus\b/i;
|
|
13760
14223
|
OFF_BY_RE = /\boff[- ]by[- ](?:one|two|\d{1,3})\b/i;
|
|
13761
|
-
NEGATED_SAFEGUARD_RE = /\bnot (
|
|
14224
|
+
NEGATED_SAFEGUARD_RE = /\bnot (rejected|validated|enforced|applied|persisted|saved)\b/gi;
|
|
14225
|
+
NOT_KEPT_RE = /^(?:applied|persisted|saved)$/i;
|
|
14226
|
+
REFUSED_INPUT_RE = /\b(?:blank|empty|whitespace|invalid|malformed|expired|duplicate[sd]?|too (?:long|short)|cancel(?:s|led|ed|ling|ing)?|discard\w*|escape)\b/i;
|
|
14227
|
+
SAFEGUARD_LOOKBEHIND = 80;
|
|
13762
14228
|
BAD_VALUE_RE = /\b(?:incorrect|wrong|stale|negative|epoch|unix) (?:total|amount|value|date|count|price|label|plan|balance)\b/i;
|
|
13763
14229
|
REFUSAL_RE = /\b(?<!not )(?:rejected|refused|denied|blocked|disallowed|prevented)\b|\breturns? (?:4\d\d|an? (?:error|validation))\b|\bshows (?:an? )?(?:error|validation)\b/i;
|
|
13764
14230
|
TEST_FAIL_CONTRACT_RE = /\btest\.fail\s{0,20}\(/;
|
|
@@ -14617,7 +15083,7 @@ function findExpectCalls(code) {
|
|
|
14617
15083
|
return out;
|
|
14618
15084
|
}
|
|
14619
15085
|
function countExpectCalls(code) {
|
|
14620
|
-
return findExpectCalls(stripComments2(code)).length;
|
|
15086
|
+
return findExpectCalls(stripComments2(withExpectAliasesAsExpect(code))).length;
|
|
14621
15087
|
}
|
|
14622
15088
|
function countActionCalls(code) {
|
|
14623
15089
|
return [...stripComments2(code).matchAll(ACTION_CALL)].length;
|
|
@@ -16946,6 +17412,7 @@ var init_test_authoring_quality = __esm({
|
|
|
16946
17412
|
"../shared/dist/test-authoring-quality.js"() {
|
|
16947
17413
|
"use strict";
|
|
16948
17414
|
init_claims_defect();
|
|
17415
|
+
init_expect_call();
|
|
16949
17416
|
init_readiness_poll();
|
|
16950
17417
|
init_persistence_reread();
|
|
16951
17418
|
init_write_response_check();
|
|
@@ -17072,7 +17539,7 @@ var init_test_authoring_quality = __esm({
|
|
|
17072
17539
|
MAX_BALANCED_SCAN = 2048;
|
|
17073
17540
|
MAX_CALLS = 500;
|
|
17074
17541
|
MAX_SEEN_SCAN = 200;
|
|
17075
|
-
ACTION_CALL = /\.(?:click|dblclick|fill|press|pressSequentially|type|check|uncheck|selectOption|setInputFiles|hover|tap|dragTo|goto)\s*\(/g;
|
|
17542
|
+
ACTION_CALL = /\.(?:(?:click|dblclick|fill|clear|press|pressSequentially|type|check|uncheck|setChecked|selectOption|setInputFiles|hover|tap|dragTo|dragAndDrop|dispatchEvent|goto)|(?:keyboard|mouse)\s*\.\s*(?:down|up|insertText|move|wheel))\s*\(/g;
|
|
17076
17543
|
BY_NAME_LOCATOR = /\.getByRole\(\s{0,20}['"][^'"\n]{1,100}['"]\s{0,20},\s{0,20}\{[^}\n]{0,200}\bname\s{0,20}:|\.getByText\(|\.getByLabel\(|\.getByTitle\(|\.getByAltText\(|\.getByPlaceholder\(/;
|
|
17077
17544
|
ACTION_AFTER = /^\s{0,20}\.\s{0,20}(?:click|fill|check|uncheck|press|type|hover|focus|selectOption|setInputFiles|dblclick|tap)\s{0,20}\(/;
|
|
17078
17545
|
MAX_CONTACTS = 200;
|
|
@@ -18581,7 +19048,7 @@ function credentialEntries(maps) {
|
|
|
18581
19048
|
}
|
|
18582
19049
|
function replacePattern(value, form) {
|
|
18583
19050
|
const escaped = form.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
18584
|
-
return
|
|
19051
|
+
return value.length < WHOLE_WORD_BELOW ? `(?<![A-Za-z0-9_])${escaped}(?![A-Za-z0-9_])` : escaped;
|
|
18585
19052
|
}
|
|
18586
19053
|
function findCredentialTextLeftover(text, maps) {
|
|
18587
19054
|
const bare = text.split(WITHHELD_CREDENTIAL_TEXT).join(" ").replace(REFERENCE, " ").toLowerCase();
|
|
@@ -18595,11 +19062,17 @@ function scrubCredentialText(text, maps) {
|
|
|
18595
19062
|
const entries = credentialEntries(maps);
|
|
18596
19063
|
if (entries.length === 0)
|
|
18597
19064
|
return text;
|
|
18598
|
-
|
|
19065
|
+
const alternatives = [];
|
|
18599
19066
|
for (const [key, value] of entries) {
|
|
18600
19067
|
for (const form of credentialValueForms(value))
|
|
18601
|
-
|
|
19068
|
+
alternatives.push({ pattern: replacePattern(value, form), key, length: form.length });
|
|
18602
19069
|
}
|
|
19070
|
+
alternatives.sort((a, b) => b.length - a.length);
|
|
19071
|
+
const matcher = new RegExp([REFERENCE.source, ...alternatives.map((alt) => `(${alt.pattern})`)].join("|"), "gi");
|
|
19072
|
+
const out = text.replace(matcher, (...args) => {
|
|
19073
|
+
const index = args.slice(1, 1 + alternatives.length).findIndex((group) => group !== void 0);
|
|
19074
|
+
return index < 0 ? String(args[0]) : `{{secret:${alternatives[index].key}}}`;
|
|
19075
|
+
});
|
|
18603
19076
|
return findCredentialTextLeftover(out, maps) ? WITHHELD_CREDENTIAL_TEXT : out;
|
|
18604
19077
|
}
|
|
18605
19078
|
function scrubCredentialStringsIn(value, maps) {
|
|
@@ -19093,10 +19566,24 @@ function onlyUrlAfter(code, writeAt) {
|
|
|
19093
19566
|
i = at + 6;
|
|
19094
19567
|
}
|
|
19095
19568
|
}
|
|
19569
|
+
function readsOrderAfter(code, writeAt) {
|
|
19570
|
+
const rest = code.slice(writeAt + 1);
|
|
19571
|
+
if (ORDER_READ_MARKERS.some((m) => rest.includes(m)) && nextExpect(code, writeAt + 1) >= 0)
|
|
19572
|
+
return true;
|
|
19573
|
+
for (let i = writeAt + 1; ; ) {
|
|
19574
|
+
const at = nextExpect(code, i);
|
|
19575
|
+
if (at < 0)
|
|
19576
|
+
return false;
|
|
19577
|
+
if (ORDERED_ARRAY_EXPECT.test(expectStatement(code, at)))
|
|
19578
|
+
return true;
|
|
19579
|
+
i = at + 6;
|
|
19580
|
+
}
|
|
19581
|
+
}
|
|
19096
19582
|
function assessTitlePromiseShape(claimText, code) {
|
|
19097
19583
|
const persistence = PERSISTENCE_RE.test(claimText);
|
|
19098
19584
|
const refusal = REFUSAL_RE2.test(claimText);
|
|
19099
|
-
|
|
19585
|
+
const order = ORDER_RE.test(claimText) || ORDER_RE_CASED.test(claimText);
|
|
19586
|
+
if (!persistence && !refusal && !order)
|
|
19100
19587
|
return [];
|
|
19101
19588
|
const blank = blankCommentsAndStringLiterals(code);
|
|
19102
19589
|
const writeAt = proofAnchor(blank);
|
|
@@ -19109,9 +19596,12 @@ function assessTitlePromiseShape(claimText, code) {
|
|
|
19109
19596
|
if (refusal && onlyUrlAfter(blank, writeAt)) {
|
|
19110
19597
|
findings.push({ rule: "rejection-only-url", reason: REFUSAL_REASON });
|
|
19111
19598
|
}
|
|
19599
|
+
if (order && !readsOrderAfter(blank, writeAt)) {
|
|
19600
|
+
findings.push({ rule: "sort-without-order", reason: ORDER_REASON });
|
|
19601
|
+
}
|
|
19112
19602
|
return findings;
|
|
19113
19603
|
}
|
|
19114
|
-
var PERSIST_REASON, REFUSAL_REASON, PERSISTENCE_RE, REFUSAL_RE2, WRITE_MARKERS, VALUE_WRITE_MARKERS, REREAD_MARKERS;
|
|
19604
|
+
var PERSIST_REASON, REFUSAL_REASON, PERSISTENCE_RE, REFUSAL_RE2, ORDER_REASON, ORDER_RE, ORDER_RE_CASED, ORDER_READ_MARKERS, ORDERED_ARRAY_EXPECT, WRITE_MARKERS, VALUE_WRITE_MARKERS, REREAD_MARKERS;
|
|
19115
19605
|
var init_title_promise_shape = __esm({
|
|
19116
19606
|
"../shared/dist/title-promise-shape.js"() {
|
|
19117
19607
|
"use strict";
|
|
@@ -19120,6 +19610,21 @@ var init_title_promise_shape = __esm({
|
|
|
19120
19610
|
REFUSAL_REASON = "The title says the app refuses the input, but the only check after submitting is the URL: assert the error message, the field's invalid state or the response status.";
|
|
19121
19611
|
PERSISTENCE_RE = /\b(?:is|are|gets|stays)\s{1,20}saved\b|\b(?:is|are)\s{1,20}persisted\b|\bpersists\s{1,20}(?:after|across|through)\s{1,20}(?:a\s{1,20})?(?:reloads?|refresh(?:es)?|sessions?)\b|\bis\s{1,20}(?:stored|kept|remembered)\b|\bafter\s{1,20}(?:a\s{1,20})?reload\b|\bafter\s{1,20}refresh\b|\bsurvives\s{1,20}(?:a\s{1,20})?reload\b/i;
|
|
19122
19612
|
REFUSAL_RE2 = /\b(?:rejects|rejected|refuses|refused|prevents|prevented|disallows)\b|\b(?:is|are|gets)\s{1,20}blocked\b|\bis\s{1,20}denied\b|\bshows\s{1,20}an\s{1,20}error\b|\bshows\s{1,20}a\s{1,20}validation\b|\bshows\s{1,20}validation\b|\breturns\s{1,20}4\d\d\b/i;
|
|
19613
|
+
ORDER_REASON = "The title says the list is sorted, but no check after the sort reads the order: assert the items in order (toHaveText([...]) on the list, the first and last item, or allTextContents() compared with a sorted copy).";
|
|
19614
|
+
ORDER_RE = /\bsort(?:s|ed|ing)?\b[^\n.]{0,60}?\bby\b|\b(?:ascending|descending)\b|\b(?:low|lowest)\s{1,20}to\s{1,20}(?:high|highest)\b|\b(?:high|highest)\s{1,20}to\s{1,20}(?:low|lowest)\b|\balphabetical(?:ly)?\b|\b(?:newest|oldest)\s{1,20}first\b/i;
|
|
19615
|
+
ORDER_RE_CASED = /\b[AZ]\s{0,3}(?:to|-|→)\s{0,3}[AZ]\b/;
|
|
19616
|
+
ORDER_READ_MARKERS = [
|
|
19617
|
+
".allTextContents(",
|
|
19618
|
+
".allInnerTexts(",
|
|
19619
|
+
".evaluateAll(",
|
|
19620
|
+
".toMatchAriaSnapshot(",
|
|
19621
|
+
".sort(",
|
|
19622
|
+
".toSorted(",
|
|
19623
|
+
".first()",
|
|
19624
|
+
".last()",
|
|
19625
|
+
".nth("
|
|
19626
|
+
];
|
|
19627
|
+
ORDERED_ARRAY_EXPECT = /\.(?:toHaveText|toContainText|toEqual|toStrictEqual)\s*\(\s*\[/;
|
|
19123
19628
|
WRITE_MARKERS = [
|
|
19124
19629
|
".fill(",
|
|
19125
19630
|
".click(",
|
|
@@ -19451,7 +19956,7 @@ function assertionsReadVisibleContent(code) {
|
|
|
19451
19956
|
});
|
|
19452
19957
|
}
|
|
19453
19958
|
function isLegacyReviewFlag(tags, activity) {
|
|
19454
|
-
const flagged = tags.includes(
|
|
19959
|
+
const flagged = tags.includes(NEEDS_REVIEW_TAG2) || activity?.needsReview === true;
|
|
19455
19960
|
const source = activity?.needsReviewSource;
|
|
19456
19961
|
return flagged && !(typeof source === "string" && source in SOURCE_RANK);
|
|
19457
19962
|
}
|
|
@@ -19513,7 +20018,7 @@ function recheckGeneratorNotes(notes, input) {
|
|
|
19513
20018
|
}
|
|
19514
20019
|
function reviewHolds(tags, activity, cleared = /* @__PURE__ */ new Set()) {
|
|
19515
20020
|
const out = [];
|
|
19516
|
-
const tagged = tags.includes(
|
|
20021
|
+
const tagged = tags.includes(NEEDS_REVIEW_TAG2);
|
|
19517
20022
|
const generatorAsked = activity?.needsReview === true;
|
|
19518
20023
|
if (tagged) {
|
|
19519
20024
|
if (activity?.needsReviewSource === "human")
|
|
@@ -19573,7 +20078,7 @@ function evaluatePromotionGate(input, checks = PROMOTION_QUALITY_CHECKS) {
|
|
|
19573
20078
|
...suspiciousTagged ? { suspiciousPass: { mode: suspicious, covered: suspiciousCovered, wouldHold: suspiciousHold } } : {}
|
|
19574
20079
|
};
|
|
19575
20080
|
}
|
|
19576
|
-
var SOURCE_RANK, strengthCheck, STRING_CONST, TYPED_VALUE, TYPED_CONSTANT, MAX_STATEMENTS, MAX_STATEMENT_CHARS, LITERAL_OR_IDENTIFIER, MUTATING_ACTION, FEEDBACK_REGION, ONE_SHOT_MESSAGE_REASON, FEEDBACK_REGION_ALL, dynamicAssertionCheck, OUTCOME_KIND_MATCHER, ROUTE_TERM, ROUTE_TRAILING_PUNCTUATION, QUOTED_LITERAL, GENERIC_LITERAL, MAX_OUTCOME_STATEMENTS, MAX_OUTCOMES, MAX_OUTCOME_TEXT_CHARS, expectedOutcomeCheck, testDataCheck, sharedAccountCheck, clockLiteralCheck, readinessPollCheck, knownBugTestCheck, bugClaimContractCheck, suspiciousExpectationCheck, bugCandidateCheck, conventionOutcomesCheck, pendingHook, locatorFragmentCheck, FILTER_STEP, NEXT_ACTION, REDUCTION_PROOF, MAX_FILTER_LINES, MAX_FILTER_LINE_CHARS, filterPositiveOnlyCheck, PROMOTION_QUALITY_CHECKS, PROMOTION_GATE_MAX_CODE_CHARS, NOT_EVALUATED, SUSPICIOUS_PASS_TAG, NOT_CONTENT_MATCHER, CONTENT_PROOF, NAMED_ELEMENT,
|
|
20081
|
+
var SOURCE_RANK, strengthCheck, STRING_CONST, TYPED_VALUE, TYPED_CONSTANT, MAX_STATEMENTS, MAX_STATEMENT_CHARS, LITERAL_OR_IDENTIFIER, MUTATING_ACTION, FEEDBACK_REGION, ONE_SHOT_MESSAGE_REASON, FEEDBACK_REGION_ALL, dynamicAssertionCheck, OUTCOME_KIND_MATCHER, ROUTE_TERM, ROUTE_TRAILING_PUNCTUATION, QUOTED_LITERAL, GENERIC_LITERAL, MAX_OUTCOME_STATEMENTS, MAX_OUTCOMES, MAX_OUTCOME_TEXT_CHARS, expectedOutcomeCheck, testDataCheck, sharedAccountCheck, clockLiteralCheck, readinessPollCheck, knownBugTestCheck, bugClaimContractCheck, suspiciousExpectationCheck, bugCandidateCheck, conventionOutcomesCheck, pendingHook, locatorFragmentCheck, FILTER_STEP, NEXT_ACTION, REDUCTION_PROOF, MAX_FILTER_LINES, MAX_FILTER_LINE_CHARS, filterPositiveOnlyCheck, PROMOTION_QUALITY_CHECKS, PROMOTION_GATE_MAX_CODE_CHARS, NOT_EVALUATED, SUSPICIOUS_PASS_TAG, NOT_CONTENT_MATCHER, CONTENT_PROOF, NAMED_ELEMENT, NEEDS_REVIEW_TAG2, count2, RECHECKED_NOTES, EVIDENCE_NOTE_PREFIXES, PENDING_RECHECK_NOTE_PREFIXES, STRENGTH_RANK;
|
|
19577
20082
|
var init_promotion_quality_gate = __esm({
|
|
19578
20083
|
"../shared/dist/promotion-quality-gate.js"() {
|
|
19579
20084
|
"use strict";
|
|
@@ -19592,8 +20097,8 @@ var init_promotion_quality_gate = __esm({
|
|
|
19592
20097
|
SOURCE_RANK = { generator: 0, classifier: 0, healer: 1, human: 2 };
|
|
19593
20098
|
strengthCheck = {
|
|
19594
20099
|
id: "assertion-strength",
|
|
19595
|
-
run({ code, tags, strengthGate, flagContradictedAdditions, lastActionProof }) {
|
|
19596
|
-
const verdict = validateAssertionStrength(code, { flagContradictedAdditions: flagContradictedAdditions === true, lastActionProof });
|
|
20100
|
+
run({ code, tags, strengthGate, flagContradictedAdditions, lastActionProof, absenceProof }) {
|
|
20101
|
+
const verdict = validateAssertionStrength(code, { flagContradictedAdditions: flagContradictedAdditions === true, lastActionProof, absenceProof });
|
|
19597
20102
|
if (verdict.severity === "route-bug")
|
|
19598
20103
|
return [{ check: "route-bug" }];
|
|
19599
20104
|
const authDowngrade = verdict.severity === "downgrade" && tags.some((t) => t.toLowerCase() === "@auth");
|
|
@@ -19851,7 +20356,7 @@ ${goalText}`);
|
|
|
19851
20356
|
NOT_CONTENT_MATCHER = /\.(?:toHaveURL|toHaveTitle|toBeOK)\s*\(|\bwaitForURL\s*\(|\.(?:status|ok)\s*\(\s*\)/;
|
|
19852
20357
|
CONTENT_PROOF = /* @__PURE__ */ new Set(["controlled", "revealed", "value"]);
|
|
19853
20358
|
NAMED_ELEMENT = /\bgetByRole\s*\(\s*['"`](?!(?:navigation|banner|main|contentinfo|complementary|region|search)['"`])\w{1,30}['"`]\s*,\s*\{[^}]{0,200}?\bname\s*:\s*(['"`])[^'"`$\n]{1,200}\1|\bgetByLabel\s*\(\s*(['"`])[^'"`$\n]{1,200}\2/;
|
|
19854
|
-
|
|
20359
|
+
NEEDS_REVIEW_TAG2 = "@needs-review";
|
|
19855
20360
|
count2 = (v) => typeof v === "number" && Number.isFinite(v) ? v : 0;
|
|
19856
20361
|
RECHECKED_NOTES = [
|
|
19857
20362
|
{
|
|
@@ -19972,11 +20477,18 @@ var init_regex_alternation = __esm({
|
|
|
19972
20477
|
function isPageEvidenceEntry(entry) {
|
|
19973
20478
|
return typeof entry === "object" && entry !== null && entry.outcomeType === PAGE_LOADING_OUTCOME_TYPE;
|
|
19974
20479
|
}
|
|
19975
|
-
|
|
20480
|
+
function pageScreenshotKey(projectId, safeName, stillLoading = false) {
|
|
20481
|
+
return `discovery/${projectId}/screenshots/${stillLoading ? `${STILL_LOADING_SCREENSHOT_DIR}/` : ""}${safeName}.png`;
|
|
20482
|
+
}
|
|
20483
|
+
function isStillLoadingScreenshotKey(key) {
|
|
20484
|
+
return typeof key === "string" && key.includes(`/screenshots/${STILL_LOADING_SCREENSHOT_DIR}/`);
|
|
20485
|
+
}
|
|
20486
|
+
var PAGE_LOADING_OUTCOME_TYPE, STILL_LOADING_SCREENSHOT_DIR;
|
|
19976
20487
|
var init_page_evidence = __esm({
|
|
19977
20488
|
"../shared/dist/page-evidence.js"() {
|
|
19978
20489
|
"use strict";
|
|
19979
20490
|
PAGE_LOADING_OUTCOME_TYPE = "LOADING";
|
|
20491
|
+
STILL_LOADING_SCREENSHOT_DIR = "still-loading";
|
|
19980
20492
|
}
|
|
19981
20493
|
});
|
|
19982
20494
|
|
|
@@ -20381,11 +20893,13 @@ __export(dist_exports, {
|
|
|
20381
20893
|
SERVER_INTERRUPT_ERROR_PREFIX: () => SERVER_INTERRUPT_ERROR_PREFIX,
|
|
20382
20894
|
SHARED_PRICING_PLAN_MAP: () => SHARED_PRICING_PLAN_MAP,
|
|
20383
20895
|
SHARED_SERVER_APPLICATION_NAME: () => SHARED_SERVER_APPLICATION_NAME,
|
|
20896
|
+
SMS_NOT_RECEIVED_PREFIXES: () => SMS_NOT_RECEIVED_PREFIXES,
|
|
20384
20897
|
SPEND_SOURCE_KEY: () => SPEND_SOURCE_KEY,
|
|
20385
20898
|
SPEND_SOURCE_SERVER: () => SPEND_SOURCE_SERVER,
|
|
20386
20899
|
STATED_LIMITS_VERSION: () => STATED_LIMITS_VERSION,
|
|
20387
20900
|
STATED_PATTERN_MAX: () => STATED_PATTERN_MAX,
|
|
20388
20901
|
STATIC_STANDARD_MIN_INTERACTIVE: () => STATIC_STANDARD_MIN_INTERACTIVE,
|
|
20902
|
+
STILL_LOADING_SCREENSHOT_DIR: () => STILL_LOADING_SCREENSHOT_DIR,
|
|
20389
20903
|
STT_MODEL_OPTIONS: () => STT_MODEL_OPTIONS,
|
|
20390
20904
|
SUCCESS_NOTICE_TEXT: () => SUCCESS_NOTICE_TEXT,
|
|
20391
20905
|
SUPPORT_EMAIL: () => SUPPORT_EMAIL,
|
|
@@ -20413,6 +20927,7 @@ __export(dist_exports, {
|
|
|
20413
20927
|
TTS_VOICE_OPTIONS: () => TTS_VOICE_OPTIONS,
|
|
20414
20928
|
UI_VARIANTS: () => UI_VARIANTS,
|
|
20415
20929
|
UNEXPECTED_PASS_ERROR_PREFIX: () => UNEXPECTED_PASS_ERROR_PREFIX,
|
|
20930
|
+
UNVERIFIED_HEAL_CONFIDENCES: () => UNVERIFIED_HEAL_CONFIDENCES,
|
|
20416
20931
|
USER_CANCELLED_RUN_ERROR: () => USER_CANCELLED_RUN_ERROR,
|
|
20417
20932
|
VISUAL_MASK_SELECTORS_MAX: () => VISUAL_MASK_SELECTORS_MAX,
|
|
20418
20933
|
VISUAL_MASK_SELECTOR_FORBIDDEN: () => VISUAL_MASK_SELECTOR_FORBIDDEN,
|
|
@@ -20466,6 +20981,7 @@ __export(dist_exports, {
|
|
|
20466
20981
|
blankBlockComments: () => blankBlockComments3,
|
|
20467
20982
|
blankCommentsAndStringLiterals: () => blankCommentsAndStringLiterals,
|
|
20468
20983
|
blankKeepingLines: () => blankKeepingLines,
|
|
20984
|
+
blockedRunLogLine: () => blockedRunLogLine,
|
|
20469
20985
|
boundedCallCostUsd: () => boundedCallCostUsd,
|
|
20470
20986
|
brokerResponseBody: () => brokerResponseBody,
|
|
20471
20987
|
bugFoundQuarantineWhere: () => bugFoundQuarantineWhere,
|
|
@@ -20571,6 +21087,7 @@ __export(dist_exports, {
|
|
|
20571
21087
|
evaluatePromotionGate: () => evaluatePromotionGate,
|
|
20572
21088
|
excludeCancelledRunsAnd: () => excludeCancelledRunsAnd,
|
|
20573
21089
|
excludeCancelledRunsWhere: () => excludeCancelledRunsWhere,
|
|
21090
|
+
expectAliasNames: () => expectAliasNames,
|
|
20574
21091
|
explicitAgenticCliOverrideError: () => explicitAgenticCliOverrideError,
|
|
20575
21092
|
extractAssertedControlSignatures: () => extractAssertedControlSignatures,
|
|
20576
21093
|
extractMuseAssistantJson: () => extractMuseAssistantJson,
|
|
@@ -20637,6 +21154,8 @@ __export(dist_exports, {
|
|
|
20637
21154
|
googleGisRequestUrl: () => googleGisRequestUrl,
|
|
20638
21155
|
googleSignInLimitLines: () => googleSignInLimitLines,
|
|
20639
21156
|
googleSignInPolicyProblems: () => googleSignInPolicyProblems,
|
|
21157
|
+
googleSignInRefusedLine: () => googleSignInRefusedLine,
|
|
21158
|
+
googleSignInRefusedReason: () => googleSignInRefusedReason,
|
|
20640
21159
|
hasCrossPlatformIdentity: () => hasCrossPlatformIdentity,
|
|
20641
21160
|
hasEncodedRequestBody: () => hasEncodedRequestBody,
|
|
20642
21161
|
hasEngineSpecParts: () => hasEngineSpecParts,
|
|
@@ -20680,6 +21199,7 @@ __export(dist_exports, {
|
|
|
20680
21199
|
isCodeFactNote: () => isCodeFactNote,
|
|
20681
21200
|
isConfigLikeReason: () => isConfigLikeReason,
|
|
20682
21201
|
isCountedFailure: () => isCountedFailure,
|
|
21202
|
+
isCredentialHeaderName: () => isCredentialHeaderName,
|
|
20683
21203
|
isCreditPackAmountCents: () => isCreditPackAmountCents,
|
|
20684
21204
|
isDbPricingPlan: () => isDbPricingPlan,
|
|
20685
21205
|
isDeniedGoogleBrokerRedirectHost: () => isDeniedGoogleBrokerRedirectHost,
|
|
@@ -20735,8 +21255,10 @@ __export(dist_exports, {
|
|
|
20735
21255
|
isSharedAuthTenantHost: () => isSharedAuthTenantHost,
|
|
20736
21256
|
isSharedSuffix: () => isSharedSuffix,
|
|
20737
21257
|
isSingleEmailAddress: () => isSingleEmailAddress,
|
|
21258
|
+
isSmsNotReceivedError: () => isSmsNotReceivedError,
|
|
20738
21259
|
isSoftOutcome: () => isSoftOutcome,
|
|
20739
21260
|
isStateValueMobileClassName: () => isStateValueMobileClassName,
|
|
21261
|
+
isStillLoadingScreenshotKey: () => isStillLoadingScreenshotKey,
|
|
20740
21262
|
isSttModelForProvider: () => isSttModelForProvider,
|
|
20741
21263
|
isTestReadyForPlatform: () => isTestReadyForPlatform,
|
|
20742
21264
|
isTestVariableSecretKey: () => isTestVariableSecretKey,
|
|
@@ -20744,6 +21266,7 @@ __export(dist_exports, {
|
|
|
20744
21266
|
isUIVariant: () => isUIVariant,
|
|
20745
21267
|
isUnexpectedPassError: () => isUnexpectedPassError,
|
|
20746
21268
|
isUnsafePrecondition: () => isUnsafePrecondition,
|
|
21269
|
+
isUnverifiedHealPass: () => isUnverifiedHealPass,
|
|
20747
21270
|
isUsableDeepgramKey: () => isUsableDeepgramKey,
|
|
20748
21271
|
isUserCancelledError: () => isUserCancelledError,
|
|
20749
21272
|
isValidAgenticCliModel: () => isValidAgenticCliModel,
|
|
@@ -20768,8 +21291,10 @@ __export(dist_exports, {
|
|
|
20768
21291
|
lintTestData: () => lintTestData,
|
|
20769
21292
|
lintTestQuality: () => lintTestQuality,
|
|
20770
21293
|
literalUrlRegex: () => literalUrlRegex,
|
|
21294
|
+
loginFormAlertTexts: () => loginFormAlertTexts,
|
|
20771
21295
|
longCredentialValues: () => longCredentialValues,
|
|
20772
21296
|
maskedOutsideStrings: () => maskedOutsideStrings,
|
|
21297
|
+
mayBeUnverifiedHealPass: () => mayBeUnverifiedHealPass,
|
|
20773
21298
|
mediumForMobilePlatform: () => mediumForMobilePlatform,
|
|
20774
21299
|
mergePageType: () => mergePageType,
|
|
20775
21300
|
mergeSuspectedBugsAcrossSurveys: () => mergeSuspectedBugsAcrossSurveys,
|
|
@@ -20803,7 +21328,9 @@ __export(dist_exports, {
|
|
|
20803
21328
|
opensRegexLiteral: () => opensRegexLiteral,
|
|
20804
21329
|
otherMobilePlatform: () => otherMobilePlatform,
|
|
20805
21330
|
outcomeNamedByAssertion: () => outcomeNamedByAssertion,
|
|
21331
|
+
pageScreenshotKey: () => pageScreenshotKey,
|
|
20806
21332
|
parenDepthDelta: () => parenDepthDelta,
|
|
21333
|
+
parseAbsenceProofMode: () => parseAbsenceProofMode,
|
|
20807
21334
|
parseApiCardModelUpdate: () => parseApiCardModelUpdate,
|
|
20808
21335
|
parseAppTimezone: () => parseAppTimezone,
|
|
20809
21336
|
parseAuditGroupScopeId: () => parseAuditGroupScopeId,
|
|
@@ -20879,7 +21406,7 @@ __export(dist_exports, {
|
|
|
20879
21406
|
redactNeedlesText: () => redactNeedlesText,
|
|
20880
21407
|
redirectOnAppSite: () => redirectOnAppSite,
|
|
20881
21408
|
refuseEncodedRequestBodies: () => refuseEncodedRequestBodies,
|
|
20882
|
-
regexLiteralEnd: () =>
|
|
21409
|
+
regexLiteralEnd: () => regexLiteralEnd,
|
|
20883
21410
|
regexOpensAfter: () => regexOpensAfter,
|
|
20884
21411
|
registrableDomain: () => registrableDomain,
|
|
20885
21412
|
renderIdentity: () => renderIdentity,
|
|
@@ -20921,6 +21448,9 @@ __export(dist_exports, {
|
|
|
20921
21448
|
saveOpensConfirm: () => saveOpensConfirm,
|
|
20922
21449
|
scanClockDependentLiterals: () => scanClockDependentLiterals,
|
|
20923
21450
|
scanHtmlTags: () => scanHtmlTags,
|
|
21451
|
+
scrubCredentialHeaderValue: () => scrubCredentialHeaderValue,
|
|
21452
|
+
scrubCredentialHeaders: () => scrubCredentialHeaders,
|
|
21453
|
+
scrubCredentialHeadersDeep: () => scrubCredentialHeadersDeep,
|
|
20924
21454
|
scrubCredentialStringsIn: () => scrubCredentialStringsIn,
|
|
20925
21455
|
scrubCredentialText: () => scrubCredentialText,
|
|
20926
21456
|
scrubSearchParams: () => scrubSearchParams,
|
|
@@ -20931,9 +21461,12 @@ __export(dist_exports, {
|
|
|
20931
21461
|
selectorForValue: () => selectorForValue,
|
|
20932
21462
|
setAgenticCliRuntime: () => setAgenticCliRuntime,
|
|
20933
21463
|
setProviderChainOverrides: () => setProviderChainOverrides,
|
|
21464
|
+
signInStepPassedBeforeFailure: () => signInStepPassedBeforeFailure,
|
|
21465
|
+
signsInInline: () => signsInInline,
|
|
20934
21466
|
signupPlanFor: () => signupPlanFor,
|
|
20935
21467
|
simplifyMobileWanderingInPlace: () => simplifyMobileWanderingInPlace,
|
|
20936
21468
|
siteOf: () => siteOf,
|
|
21469
|
+
specCallsExpect: () => specCallsExpect,
|
|
20937
21470
|
specItemsFromTestPlans: () => specItemsFromTestPlans,
|
|
20938
21471
|
splitAnswerLines: () => splitAnswerLines,
|
|
20939
21472
|
statedLimitsFromAttrs: () => statedLimitsFromAttrs,
|
|
@@ -20981,6 +21514,7 @@ __export(dist_exports, {
|
|
|
20981
21514
|
visualProDailyBudget: () => visualProDailyBudget,
|
|
20982
21515
|
voiceMatchesTtsModel: () => voiceMatchesTtsModel,
|
|
20983
21516
|
voicesForTtsModel: () => voicesForTtsModel,
|
|
21517
|
+
withExpectAliasesAsExpect: () => withExpectAliasesAsExpect,
|
|
20984
21518
|
withGeneratorReviewSource: () => withGeneratorReviewSource,
|
|
20985
21519
|
withReviewSource: () => withReviewSource,
|
|
20986
21520
|
withoutNotChargedClaim: () => withoutNotChargedClaim,
|
|
@@ -21035,6 +21569,7 @@ var init_dist = __esm({
|
|
|
21035
21569
|
init_encoded_forms();
|
|
21036
21570
|
init_block_comments();
|
|
21037
21571
|
init_redact_needles();
|
|
21572
|
+
init_credential_header_scrub();
|
|
21038
21573
|
init_voice_config();
|
|
21039
21574
|
init_deepgram_speech();
|
|
21040
21575
|
init_deepgram_voices();
|
|
@@ -23402,7 +23937,13 @@ await expect(page).not.toHaveURL(/accounts\\.google\\.com/, { timeout: 60_000 })
|
|
|
23402
23937
|
\`\`\`
|
|
23403
23938
|
Never emit code that clicks, fills or asserts anything on accounts.google.com.`;
|
|
23404
23939
|
}
|
|
23405
|
-
function buildGoogleSignInTestGenSection(_opts) {
|
|
23940
|
+
function buildGoogleSignInTestGenSection(_opts, ctx = {}) {
|
|
23941
|
+
if (ctx.appLoginGiven) {
|
|
23942
|
+
return `
|
|
23943
|
+
## SIGN-IN: USE THE TEST ACCOUNT
|
|
23944
|
+
This project gave a test account (the Browser Credentials / \`process.env.TEST_USER_*\` values). Sign in with it on the app's own email (or username) and password form, even when the app also offers Continue with Google. Do not click Continue with Google / Sign in with Google / Sign up with Google to sign in.
|
|
23945
|
+
Use Continue with Google only when this scenario's goal is the Google sign-in itself, or the app has no email/username and password sign-in at all. Then click that control on the app and wait until the browser is back on the app: \`await expect(page).not.toHaveURL(/accounts\\.google\\.com/, { timeout: 60_000 })\` (the runner completes Google's step). Never click, fill or assert anything on accounts.google.com, never type a password or code there.`;
|
|
23946
|
+
}
|
|
23406
23947
|
return `
|
|
23407
23948
|
## GOOGLE SIGN-IN (the runner completes Google's step)
|
|
23408
23949
|
When this scenario uses Continue with Google / Sign in with Google / Sign up with Google:
|
|
@@ -23988,7 +24529,6 @@ var require_browser_config = __commonJS({
|
|
|
23988
24529
|
exports2.NO_ERROR_PAGE_RELOAD_ARG,
|
|
23989
24530
|
"--disable-dev-shm-usage",
|
|
23990
24531
|
"--disable-gpu",
|
|
23991
|
-
"--disable-software-rasterizer",
|
|
23992
24532
|
"--no-zygote",
|
|
23993
24533
|
"--disable-accelerated-2d-canvas",
|
|
23994
24534
|
"--js-flags=--max-old-space-size=512"
|
|
@@ -94798,6 +95338,7 @@ var require_cli_browser_socket = __commonJS({
|
|
|
94798
95338
|
exports2.assertSlotLease = assertSlotLease;
|
|
94799
95339
|
exports2.prepareSessionSocket = prepareSessionSocket;
|
|
94800
95340
|
exports2.assertLaunchOpensNoPort = assertLaunchOpensNoPort;
|
|
95341
|
+
exports2.devtoolsSwitchInCmdline = devtoolsSwitchInCmdline;
|
|
94801
95342
|
exports2.assertBrowserProcessOpensNoPort = assertBrowserProcessOpensNoPort;
|
|
94802
95343
|
exports2.confineOutputDirPaths = confineOutputDirPaths;
|
|
94803
95344
|
exports2.openCliBrowserSocket = openCliBrowserSocket;
|
|
@@ -95110,6 +95651,9 @@ var require_cli_browser_socket = __commonJS({
|
|
|
95110
95651
|
}
|
|
95111
95652
|
return children;
|
|
95112
95653
|
}
|
|
95654
|
+
function devtoolsSwitchInCmdline(cmdline) {
|
|
95655
|
+
return cmdline.split(/[\0\s]+/).find((arg) => DEVTOOLS_ENDPOINT_SWITCH.test(arg));
|
|
95656
|
+
}
|
|
95113
95657
|
async function assertBrowserProcessOpensNoPort(rootPid) {
|
|
95114
95658
|
if (process.platform !== "linux")
|
|
95115
95659
|
return;
|
|
@@ -95122,15 +95666,15 @@ var require_cli_browser_socket = __commonJS({
|
|
|
95122
95666
|
if (pids.length === 0)
|
|
95123
95667
|
throw new CliBrowserSocketUnsafeError("could not find the browser process to check");
|
|
95124
95668
|
for (const pid of pids) {
|
|
95125
|
-
let
|
|
95669
|
+
let cmdline;
|
|
95126
95670
|
try {
|
|
95127
|
-
|
|
95671
|
+
cmdline = await (0, promises_1.readFile)(`/proc/${pid}/cmdline`, "utf8");
|
|
95128
95672
|
} catch (error2) {
|
|
95129
95673
|
if (!rootPid && error2.code === "ENOENT")
|
|
95130
95674
|
continue;
|
|
95131
95675
|
throw new CliBrowserSocketUnsafeError(`could not read the command line of the browser (pid ${pid})`);
|
|
95132
95676
|
}
|
|
95133
|
-
const flag =
|
|
95677
|
+
const flag = devtoolsSwitchInCmdline(cmdline);
|
|
95134
95678
|
if (flag)
|
|
95135
95679
|
throw new CliBrowserSocketUnsafeError(`the browser (pid ${pid}) was started with ${flag}`);
|
|
95136
95680
|
}
|