@validate.qa/runner 1.0.100 → 1.0.102
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 +3 -0
- package/dist/{chunk-MBKGTELT.mjs → chunk-3JM6XTSZ.mjs} +1862 -530
- package/dist/{chunk-2XD63NU5.mjs → chunk-4WLP3RWN.mjs} +941 -86
- package/dist/{chunk-MHFP3QXU.mjs → chunk-5DFBEL72.mjs} +1 -1
- package/dist/{chunk-II7QW7MZ.mjs → chunk-BXLEPT4M.mjs} +31 -18
- package/dist/{chunk-MAO6ADAO.mjs → chunk-CBVHPYVJ.mjs} +62 -2
- package/dist/{chunk-5P4ANVDY.mjs → chunk-DN3O6EYT.mjs} +43073 -23357
- package/dist/{chunk-GIIIVO2W.mjs → chunk-E2RRAE27.mjs} +155 -11
- package/dist/chunk-E2VEMBQQ.mjs +291 -0
- package/dist/{chunk-HMUC3DKS.mjs → chunk-HJ6FKHMM.mjs} +2281 -2
- package/dist/{chunk-WDXLAZ2J.mjs → chunk-PWFWMVZU.mjs} +3 -2
- package/dist/{chunk-6NIT2CCH.mjs → chunk-ZZYBRIBT.mjs} +18 -12
- package/dist/cli.js +139723 -114754
- package/dist/cli.mjs +536 -247
- package/dist/credential-mcp-server.js +1761 -358
- package/dist/credential-mcp-server.mjs +3 -3
- package/dist/discovery-mcp-server.js +1874 -379
- package/dist/discovery-mcp-server.mjs +4 -4
- package/dist/dist-52M5RDZ6.mjs +17 -0
- package/dist/inbox-mcp-server.js +1902 -505
- package/dist/inbox-mcp-server.mjs +3 -3
- package/dist/route-seed-worker.js +3976 -356
- package/dist/route-seed-worker.mjs +14 -7
- package/dist/run-write-guard-preload.js +2908 -572
- package/dist/run-write-guard-preload.mjs +5 -285
- package/dist/run-write-guard.js +2908 -572
- package/dist/run-write-guard.mjs +3 -3
- package/dist/spec-driver.js +1 -1
- package/dist/spec-driver.mjs +1 -1
- package/package.json +4 -3
- package/dist/dist-DFNLMH6L.mjs +0 -16
package/dist/inbox-mcp-server.js
CHANGED
|
@@ -52692,7 +52692,7 @@ var require_he = __commonJS({
|
|
|
52692
52692
|
var stringFromCharCode2 = String.fromCharCode;
|
|
52693
52693
|
var object = {};
|
|
52694
52694
|
var hasOwnProperty = object.hasOwnProperty;
|
|
52695
|
-
var
|
|
52695
|
+
var has2 = function(object2, propertyName) {
|
|
52696
52696
|
return hasOwnProperty.call(object2, propertyName);
|
|
52697
52697
|
};
|
|
52698
52698
|
var contains = function(array, value) {
|
|
@@ -52712,7 +52712,7 @@ var require_he = __commonJS({
|
|
|
52712
52712
|
var result = {};
|
|
52713
52713
|
var key2;
|
|
52714
52714
|
for (key2 in defaults) {
|
|
52715
|
-
result[key2] =
|
|
52715
|
+
result[key2] = has2(options, key2) ? options[key2] : defaults[key2];
|
|
52716
52716
|
}
|
|
52717
52717
|
return result;
|
|
52718
52718
|
};
|
|
@@ -52724,7 +52724,7 @@ var require_he = __commonJS({
|
|
|
52724
52724
|
}
|
|
52725
52725
|
return "\uFFFD";
|
|
52726
52726
|
}
|
|
52727
|
-
if (
|
|
52727
|
+
if (has2(decodeMapNumeric, codePoint)) {
|
|
52728
52728
|
if (strict) {
|
|
52729
52729
|
parseError("disallowed character reference");
|
|
52730
52730
|
}
|
|
@@ -52765,7 +52765,7 @@ var require_he = __commonJS({
|
|
|
52765
52765
|
};
|
|
52766
52766
|
if (encodeEverything) {
|
|
52767
52767
|
string = string.replace(regexAsciiWhitelist, function(symbol) {
|
|
52768
|
-
if (useNamedReferences &&
|
|
52768
|
+
if (useNamedReferences && has2(encodeMap, symbol)) {
|
|
52769
52769
|
return "&" + encodeMap[symbol] + ";";
|
|
52770
52770
|
}
|
|
52771
52771
|
return escapeBmpSymbol(symbol);
|
|
@@ -52890,7 +52890,7 @@ var require_he = __commonJS({
|
|
|
52890
52890
|
freeModule.exports = he;
|
|
52891
52891
|
} else {
|
|
52892
52892
|
for (var key in he) {
|
|
52893
|
-
|
|
52893
|
+
has2(he, key) && (freeExports[key] = he[key]);
|
|
52894
52894
|
}
|
|
52895
52895
|
}
|
|
52896
52896
|
} else {
|
|
@@ -67537,163 +67537,6 @@ var require_verification_inbox = __commonJS({
|
|
|
67537
67537
|
}
|
|
67538
67538
|
});
|
|
67539
67539
|
|
|
67540
|
-
// ../runner-core/dist/services/harness-init-script.js
|
|
67541
|
-
var require_harness_init_script = __commonJS({
|
|
67542
|
-
"../runner-core/dist/services/harness-init-script.js"(exports2) {
|
|
67543
|
-
"use strict";
|
|
67544
|
-
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
67545
|
-
exports2.HARNESS_INIT_SOURCE_URL = void 0;
|
|
67546
|
-
exports2.withHarnessSourceUrl = withHarnessSourceUrl;
|
|
67547
|
-
exports2.buildAnimationDisablingSource = buildAnimationDisablingSource;
|
|
67548
|
-
exports2.isHarnessInitLocation = isHarnessInitLocation;
|
|
67549
|
-
exports2.isHarnessInitErrorStack = isHarnessInitErrorStack;
|
|
67550
|
-
exports2.isHarnessInitConsoleLine = isHarnessInitConsoleLine;
|
|
67551
|
-
exports2.stripHarnessConsoleEntries = stripHarnessConsoleEntries;
|
|
67552
|
-
var node_crypto_1 = require("crypto");
|
|
67553
|
-
exports2.HARNESS_INIT_SOURCE_URL = `vqa-harness-init-${(0, node_crypto_1.randomBytes)(4).toString("hex")}.js`;
|
|
67554
|
-
function withHarnessSourceUrl(content) {
|
|
67555
|
-
return `${content}
|
|
67556
|
-
//# sourceURL=${exports2.HARNESS_INIT_SOURCE_URL}`;
|
|
67557
|
-
}
|
|
67558
|
-
function buildAnimationDisablingSource(opts) {
|
|
67559
|
-
return withHarnessSourceUrl(`(() => {
|
|
67560
|
-
// Layer 1: CSS transitions and animations - instant, not removed
|
|
67561
|
-
// (duration 0s preserves final state; 'none' would prevent keyframes from completing)
|
|
67562
|
-
try {
|
|
67563
|
-
let applied = false;
|
|
67564
|
-
const apply = () => {
|
|
67565
|
-
if (applied) return true;
|
|
67566
|
-
const root = document.head || document.documentElement;
|
|
67567
|
-
if (!root) return false;
|
|
67568
|
-
const style = document.createElement('style');
|
|
67569
|
-
style.textContent = '*, *::before, *::after { transition-duration: 0s !important; animation-duration: 0s !important; transition-delay: 0s !important; animation-delay: 0s !important; }';
|
|
67570
|
-
root.appendChild(style);
|
|
67571
|
-
applied = true;
|
|
67572
|
-
return true;
|
|
67573
|
-
};
|
|
67574
|
-
if (!apply()) {
|
|
67575
|
-
// The document has no root element yet (iframe, about:blank, empty document): wait for it.
|
|
67576
|
-
let observer = null;
|
|
67577
|
-
const stop = () => { try { if (observer) observer.disconnect(); } catch (e) {} };
|
|
67578
|
-
const retry = () => { try { if (apply()) stop(); } catch (e) { stop(); } };
|
|
67579
|
-
try {
|
|
67580
|
-
observer = new MutationObserver(retry);
|
|
67581
|
-
observer.observe(document, { childList: true });
|
|
67582
|
-
} catch (e) {}
|
|
67583
|
-
document.addEventListener('readystatechange', retry);
|
|
67584
|
-
document.addEventListener('DOMContentLoaded', () => { retry(); stop(); }, { once: true });
|
|
67585
|
-
}
|
|
67586
|
-
} catch (e) {}
|
|
67587
|
-
${opts.hideWebdriver ? `
|
|
67588
|
-
try {
|
|
67589
|
-
Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
|
|
67590
|
-
} catch (e) {}
|
|
67591
|
-
` : ""}
|
|
67592
|
-
// Layer 2: Web Animations API - make instant instead of no-op
|
|
67593
|
-
// (preserves animation completion callbacks that app code may depend on)
|
|
67594
|
-
try {
|
|
67595
|
-
const origAnimate = Element.prototype.animate;
|
|
67596
|
-
if (typeof origAnimate === 'function') {
|
|
67597
|
-
Element.prototype.animate = function (keyframes, options) {
|
|
67598
|
-
if (typeof options === 'object' && options !== null) {
|
|
67599
|
-
options = Object.assign({}, options, { duration: 0, delay: 0 });
|
|
67600
|
-
} else {
|
|
67601
|
-
options = 0; // covers number, undefined, and any other type
|
|
67602
|
-
}
|
|
67603
|
-
return origAnimate.call(this, keyframes, options);
|
|
67604
|
-
};
|
|
67605
|
-
}
|
|
67606
|
-
} catch (e) {}
|
|
67607
|
-
})();`);
|
|
67608
|
-
}
|
|
67609
|
-
function isHarnessInitLocation(url) {
|
|
67610
|
-
return url === exports2.HARNESS_INIT_SOURCE_URL;
|
|
67611
|
-
}
|
|
67612
|
-
var MAX_MATCHED_LINE_CHARS = 2048;
|
|
67613
|
-
var MAX_SCANNED_LINES = 200;
|
|
67614
|
-
var STACK_FRAME_RE = /^\s*at\s+(?:[^()\s][^()]*\()?([^()\s]+):\d+:\d+\)?\s*$/;
|
|
67615
|
-
function isHarnessInitErrorStack(stack) {
|
|
67616
|
-
if (!stack)
|
|
67617
|
-
return false;
|
|
67618
|
-
const lines = stack.split("\n", MAX_SCANNED_LINES);
|
|
67619
|
-
for (const line of lines) {
|
|
67620
|
-
if (line.length > MAX_MATCHED_LINE_CHARS)
|
|
67621
|
-
continue;
|
|
67622
|
-
const match = STACK_FRAME_RE.exec(line);
|
|
67623
|
-
if (match)
|
|
67624
|
-
return match[1] === exports2.HARNESS_INIT_SOURCE_URL;
|
|
67625
|
-
}
|
|
67626
|
-
return false;
|
|
67627
|
-
}
|
|
67628
|
-
var MCP_CONSOLE_LINE_LOCATION_RE = / @ ([^\s@]+):\d+$/;
|
|
67629
|
-
function isHarnessInitConsoleLine(line) {
|
|
67630
|
-
const trimmed = line.trim();
|
|
67631
|
-
if (trimmed.length > MAX_MATCHED_LINE_CHARS)
|
|
67632
|
-
return false;
|
|
67633
|
-
const match = MCP_CONSOLE_LINE_LOCATION_RE.exec(trimmed);
|
|
67634
|
-
return match !== null && match[1] === exports2.HARNESS_INIT_SOURCE_URL;
|
|
67635
|
-
}
|
|
67636
|
-
var MCP_LEVEL_LINE_RE = /^\s*(?:-\s+)?\[([A-Za-z]+)\]/;
|
|
67637
|
-
var MCP_FRAME_LINE_RE = /^\s+at\s/;
|
|
67638
|
-
var MCP_TOTALS_RE = /^(\s*Total messages:\s*)(\d+)(\s*\(Errors:\s*)(\d+)(,\s*Warnings:\s*)(\d+)(\).*)$/;
|
|
67639
|
-
var MCP_RETURNING_RE = /^(\s*Returning\s+)(\d+)(\s+messages\b.*)$/;
|
|
67640
|
-
function stripHarnessConsoleEntries(text) {
|
|
67641
|
-
if (!text.includes(exports2.HARNESS_INIT_SOURCE_URL))
|
|
67642
|
-
return text;
|
|
67643
|
-
const lines = text.split("\n");
|
|
67644
|
-
const out = [];
|
|
67645
|
-
let removed = 0;
|
|
67646
|
-
let removedErrors = 0;
|
|
67647
|
-
let removedWarnings = 0;
|
|
67648
|
-
let i = 0;
|
|
67649
|
-
while (i < lines.length) {
|
|
67650
|
-
const line = lines[i];
|
|
67651
|
-
const level = MCP_LEVEL_LINE_RE.exec(line);
|
|
67652
|
-
if (level && isHarnessInitConsoleLine(line.replace(/^\s*-\s+/, ""))) {
|
|
67653
|
-
removed++;
|
|
67654
|
-
const kind = level[1].toLowerCase();
|
|
67655
|
-
if (kind === "error")
|
|
67656
|
-
removedErrors++;
|
|
67657
|
-
else if (kind === "warning" || kind === "warn")
|
|
67658
|
-
removedWarnings++;
|
|
67659
|
-
i++;
|
|
67660
|
-
continue;
|
|
67661
|
-
}
|
|
67662
|
-
if (MCP_FRAME_LINE_RE.test(line)) {
|
|
67663
|
-
let end = i;
|
|
67664
|
-
while (end < lines.length && MCP_FRAME_LINE_RE.test(lines[end]))
|
|
67665
|
-
end++;
|
|
67666
|
-
const frames = lines.slice(i, end);
|
|
67667
|
-
if (isHarnessInitErrorStack(frames.join("\n"))) {
|
|
67668
|
-
const previous = out[out.length - 1];
|
|
67669
|
-
if (previous !== void 0 && previous.trim() !== "" && !/^\s*(?:#|Total messages|Returning)/.test(previous) && !MCP_LEVEL_LINE_RE.test(previous))
|
|
67670
|
-
out.pop();
|
|
67671
|
-
removed++;
|
|
67672
|
-
removedErrors++;
|
|
67673
|
-
} else {
|
|
67674
|
-
out.push(...frames);
|
|
67675
|
-
}
|
|
67676
|
-
i = end;
|
|
67677
|
-
continue;
|
|
67678
|
-
}
|
|
67679
|
-
out.push(line);
|
|
67680
|
-
i++;
|
|
67681
|
-
}
|
|
67682
|
-
if (removed === 0)
|
|
67683
|
-
return text;
|
|
67684
|
-
return out.map((line) => {
|
|
67685
|
-
const totals = MCP_TOTALS_RE.exec(line);
|
|
67686
|
-
if (totals) {
|
|
67687
|
-
const [, a, total, b, errors2, c, warnings, d] = totals;
|
|
67688
|
-
return `${a}${Math.max(0, +total - removed)}${b}${Math.max(0, +errors2 - removedErrors)}${c}${Math.max(0, +warnings - removedWarnings)}${d}`;
|
|
67689
|
-
}
|
|
67690
|
-
const returning = MCP_RETURNING_RE.exec(line);
|
|
67691
|
-
return returning ? `${returning[1]}${Math.max(0, +returning[2] - removed)}${returning[3]}` : line;
|
|
67692
|
-
}).join("\n");
|
|
67693
|
-
}
|
|
67694
|
-
}
|
|
67695
|
-
});
|
|
67696
|
-
|
|
67697
67540
|
// ../shared/dist/types.js
|
|
67698
67541
|
function isUIVariant(value) {
|
|
67699
67542
|
return typeof value === "string" && UI_VARIANTS.includes(value);
|
|
@@ -67743,13 +67586,13 @@ function isBlockedEnvVar(key) {
|
|
|
67743
67586
|
function sanitizeTestVariables(vars) {
|
|
67744
67587
|
if (!vars)
|
|
67745
67588
|
return {};
|
|
67746
|
-
const
|
|
67589
|
+
const clean3 = {};
|
|
67747
67590
|
for (const [key, value] of Object.entries(vars)) {
|
|
67748
67591
|
if (!isBlockedEnvVar(key)) {
|
|
67749
|
-
|
|
67592
|
+
clean3[key] = value;
|
|
67750
67593
|
}
|
|
67751
67594
|
}
|
|
67752
|
-
return
|
|
67595
|
+
return clean3;
|
|
67753
67596
|
}
|
|
67754
67597
|
function buildSandboxedEnv(processEnv, testVariables) {
|
|
67755
67598
|
const env = {};
|
|
@@ -69206,9 +69049,40 @@ function semanticTarget(label, platform, base2) {
|
|
|
69206
69049
|
}
|
|
69207
69050
|
};
|
|
69208
69051
|
}
|
|
69052
|
+
function androidResourceOwners(value) {
|
|
69053
|
+
const owners = [];
|
|
69054
|
+
for (const match of value.matchAll(ANDROID_RESOURCE_ID_SUFFIX_RE)) {
|
|
69055
|
+
let runStart = match.index;
|
|
69056
|
+
while (runStart > 0 && /[a-z0-9_.]/i.test(value[runStart - 1]))
|
|
69057
|
+
runStart--;
|
|
69058
|
+
const owner = ownerAtEndOfRun(value.slice(runStart, match.index));
|
|
69059
|
+
if (owner !== null)
|
|
69060
|
+
owners.push(owner);
|
|
69061
|
+
}
|
|
69062
|
+
return owners;
|
|
69063
|
+
}
|
|
69064
|
+
function ownerAtEndOfRun(run) {
|
|
69065
|
+
const segments = run.split(".");
|
|
69066
|
+
const last = segments.length - 1;
|
|
69067
|
+
const startsWithLetter = (segment) => /^[a-z]/i.test(segment);
|
|
69068
|
+
if (last < 1 || !startsWithLetter(segments[last]))
|
|
69069
|
+
return null;
|
|
69070
|
+
let first = last;
|
|
69071
|
+
while (first > 0 && startsWithLetter(segments[first - 1]))
|
|
69072
|
+
first--;
|
|
69073
|
+
let offset = 0;
|
|
69074
|
+
for (let i = 0; i < first - 1; i++)
|
|
69075
|
+
offset += segments[i].length + 1;
|
|
69076
|
+
if (first > 0) {
|
|
69077
|
+
const letterAt = segments[first - 1].search(/[a-z]/i);
|
|
69078
|
+
if (letterAt >= 0)
|
|
69079
|
+
return run.slice(offset + letterAt);
|
|
69080
|
+
offset += segments[first - 1].length + 1;
|
|
69081
|
+
}
|
|
69082
|
+
return first < last ? run.slice(offset) : null;
|
|
69083
|
+
}
|
|
69209
69084
|
function containsForeignAppPackage(value, targetAppId) {
|
|
69210
|
-
for (const
|
|
69211
|
-
const owner = match[1];
|
|
69085
|
+
for (const owner of androidResourceOwners(value)) {
|
|
69212
69086
|
if (targetAppId && owner !== targetAppId && !owner.startsWith(`${targetAppId}.`))
|
|
69213
69087
|
return true;
|
|
69214
69088
|
}
|
|
@@ -69345,7 +69219,7 @@ function healMobileTestSteps(input) {
|
|
|
69345
69219
|
summary: changed ? uniq(summary).slice(0, 12) : []
|
|
69346
69220
|
};
|
|
69347
69221
|
}
|
|
69348
|
-
var MOBILE_STEP_ACTIONS, FOREIGN_PACKAGE_RE,
|
|
69222
|
+
var MOBILE_STEP_ACTIONS, FOREIGN_PACKAGE_RE, ANDROID_RESOURCE_ID_SUFFIX_RE, COMMON_EXTERNAL_PREFIXES;
|
|
69349
69223
|
var init_mobile_step_healer = __esm({
|
|
69350
69224
|
"../shared/dist/mobile-step-healer.js"() {
|
|
69351
69225
|
"use strict";
|
|
@@ -69366,7 +69240,7 @@ var init_mobile_step_healer = __esm({
|
|
|
69366
69240
|
"assertStateDelta"
|
|
69367
69241
|
]);
|
|
69368
69242
|
FOREIGN_PACKAGE_RE = /\b[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*){2,}\b/gi;
|
|
69369
|
-
|
|
69243
|
+
ANDROID_RESOURCE_ID_SUFFIX_RE = /:id\//gi;
|
|
69370
69244
|
COMMON_EXTERNAL_PREFIXES = [
|
|
69371
69245
|
"com.android.",
|
|
69372
69246
|
"com.google.",
|
|
@@ -70679,7 +70553,7 @@ function unescapeQuotedBody(raw) {
|
|
|
70679
70553
|
return raw.replace(/\\(['"`\\])/g, "$1");
|
|
70680
70554
|
}
|
|
70681
70555
|
function extractRoleNameValue(line) {
|
|
70682
|
-
const m = line.match(new RegExp(`getByRole\\s*\\([^,]
|
|
70556
|
+
const m = line.match(new RegExp(`getByRole\\s*\\([^,]{1,200},\\s*\\{[^}]{0,200}?name\\s*:\\s*(?:${QUOTED_BODY}|\\/([^/]*?)\\/)`, "i"));
|
|
70683
70557
|
if (!m)
|
|
70684
70558
|
return null;
|
|
70685
70559
|
const raw = m[1] ?? m[2] ?? m[3];
|
|
@@ -71076,7 +70950,7 @@ var init_assertion_classifier = __esm({
|
|
|
71076
70950
|
// toHaveCount(0) stays tier 4 (absence proof) via TIER4_PATTERNS.
|
|
71077
70951
|
[/\.toHaveCount\s*\(\s*[1-9]\d*\s*\)/, "non-zero toHaveCount asserts a record count that changes between runs"],
|
|
71078
70952
|
// parenthesised counts like "(3)" or "[12]" in text - but not Playwright method args
|
|
71079
|
-
[
|
|
70953
|
+
[/\((?<!\.\w{3,20}\s*\()\s*\d+\s*\)(?!\s*(?:[,;]\s*)?\))/i, "parenthesised count is session-specific"],
|
|
71080
70954
|
// bare email addresses in assertion content
|
|
71081
70955
|
[/\b[a-z0-9._%+-]+@[a-z0-9.-]+\.[a-z]{2,}\b/i, "email address is user-specific"],
|
|
71082
70956
|
// currency/balance amounts (dynamic account data)
|
|
@@ -71322,7 +71196,7 @@ var init_assertion_proof = __esm({
|
|
|
71322
71196
|
PRESENCE_MATCHER = /\.(?:toBeVisible|toBeAttached|toBeEnabled|toBeInViewport|toBeEditable|toBeFocused)\s*\(|\.toHaveCount\s*\(\s*1\s*\)/;
|
|
71323
71197
|
TEXT_MATCHER = /\.(?:toHaveText|toContainText)\s*\(/;
|
|
71324
71198
|
ANY_VALUE_SOURCE = /^(?:\.|\\S|\\w|\\d|\[\^\\s\]|\[0-9\]|\[\\d\]|\[\\w\]|\[\\s\\S\])[+*]?\??$/;
|
|
71325
|
-
ANY_VALUE_MATCHER = /\.(?:toHaveValue|toHaveText|toContainText)\s*\(\s*\/((?:\\.|[^/\\]){1,300})\/[a-z]*\s
|
|
71199
|
+
ANY_VALUE_MATCHER = /\.(?:toHaveValue|toHaveText|toContainText)\s*\(\s*\/((?:\\.|[^/\\]){1,300})\/[a-z]*\s*[,)]/;
|
|
71326
71200
|
EMPTY_NOT_VALUE = /\.not\s*\.\s*toHaveValue\s*\(\s*(?:['"`]{2}|\/\^?\$?\/)/;
|
|
71327
71201
|
TEXT_MATCHER_LITERAL = /\.(?:toHaveText|toContainText)\s*\(\s*(['"`])((?:(?!\1).){1,300})\1/;
|
|
71328
71202
|
GET_BY_TEXT_LITERAL = /getByText\s*\(\s*(['"`])((?:(?!\1).){1,300})\1/;
|
|
@@ -71339,7 +71213,7 @@ var init_assertion_proof = __esm({
|
|
|
71339
71213
|
DATA_ROLE = /getByRole\s*\(\s*['"`](?:dialog|alertdialog|alert|cell|gridcell|row|rowheader|columnheader|listitem|article|option|status|note|tooltip|paragraph|term|definition|log|marquee|timer|meter)['"`]/gi;
|
|
71340
71214
|
TEXT_LOCATOR = /\.getByText\s*\(|\.filter\s*\(\s*\{\s*hasText\s*:/g;
|
|
71341
71215
|
CSS_LOCATOR = /\.locator\s*\(\s*(['"`])((?:(?!\1).){1,300})\1/g;
|
|
71342
|
-
SPECIFIC_CSS = /\[[^\]]*=|#[\w-]|has-text|:text/;
|
|
71216
|
+
SPECIFIC_CSS = /\[[^\][=]*=|#[\w-]|has-text|:text/;
|
|
71343
71217
|
}
|
|
71344
71218
|
});
|
|
71345
71219
|
|
|
@@ -71387,6 +71261,8 @@ function stripCoverageComments(code) {
|
|
|
71387
71261
|
let copyFrom = 0;
|
|
71388
71262
|
let i = 0;
|
|
71389
71263
|
let quote = null;
|
|
71264
|
+
let prev = "";
|
|
71265
|
+
let noRegexBefore = 0;
|
|
71390
71266
|
while (i < code.length) {
|
|
71391
71267
|
const ch = code[i];
|
|
71392
71268
|
if (quote) {
|
|
@@ -71394,12 +71270,24 @@ function stripCoverageComments(code) {
|
|
|
71394
71270
|
i += 2;
|
|
71395
71271
|
continue;
|
|
71396
71272
|
}
|
|
71397
|
-
if (ch === quote || ch === "\n" && quote !== "`")
|
|
71273
|
+
if (ch === quote || ch === "\n" && quote !== "`") {
|
|
71398
71274
|
quote = null;
|
|
71275
|
+
prev = ch === "\n" ? prev : ch;
|
|
71276
|
+
}
|
|
71399
71277
|
i++;
|
|
71400
71278
|
continue;
|
|
71401
71279
|
}
|
|
71402
71280
|
const next = code[i + 1];
|
|
71281
|
+
if (ch === "/" && next !== "*" && next !== "/" && i >= noRegexBefore && (prev === "" || REGEX_PRECEDER2.includes(prev))) {
|
|
71282
|
+
const end = regexLiteralEnd3(code, i);
|
|
71283
|
+
if (end > 0) {
|
|
71284
|
+
i = end;
|
|
71285
|
+
prev = "a";
|
|
71286
|
+
continue;
|
|
71287
|
+
}
|
|
71288
|
+
const eol = code.indexOf("\n", i);
|
|
71289
|
+
noRegexBefore = eol === -1 ? code.length : eol;
|
|
71290
|
+
}
|
|
71403
71291
|
if (ch === "/" && next === "*") {
|
|
71404
71292
|
const end = code.indexOf("*/", i + 2);
|
|
71405
71293
|
const stop = end === -1 ? code.length : end + 2;
|
|
@@ -71418,11 +71306,39 @@ function stripCoverageComments(code) {
|
|
|
71418
71306
|
}
|
|
71419
71307
|
if (ch === '"' || ch === "'" || ch === "`")
|
|
71420
71308
|
quote = ch;
|
|
71309
|
+
if (ch !== " " && ch !== " " && ch !== "\n" && ch !== "\r")
|
|
71310
|
+
prev = ch;
|
|
71421
71311
|
i++;
|
|
71422
71312
|
}
|
|
71423
71313
|
out.push(code.slice(copyFrom));
|
|
71424
71314
|
return out.join("");
|
|
71425
71315
|
}
|
|
71316
|
+
function regexLiteralEnd3(code, start) {
|
|
71317
|
+
let inClass = false;
|
|
71318
|
+
for (let j = start + 1; j < code.length; j++) {
|
|
71319
|
+
const c = code[j];
|
|
71320
|
+
if (c === "\n")
|
|
71321
|
+
return -1;
|
|
71322
|
+
if (c === "\\") {
|
|
71323
|
+
j++;
|
|
71324
|
+
continue;
|
|
71325
|
+
}
|
|
71326
|
+
if (inClass) {
|
|
71327
|
+
if (c === "]")
|
|
71328
|
+
inClass = false;
|
|
71329
|
+
continue;
|
|
71330
|
+
}
|
|
71331
|
+
if (c === "[")
|
|
71332
|
+
inClass = true;
|
|
71333
|
+
else if (c === "/") {
|
|
71334
|
+
let k = j + 1;
|
|
71335
|
+
while (k < code.length && isIdentChar(code[k]))
|
|
71336
|
+
k++;
|
|
71337
|
+
return k;
|
|
71338
|
+
}
|
|
71339
|
+
}
|
|
71340
|
+
return -1;
|
|
71341
|
+
}
|
|
71426
71342
|
function isIdentChar(ch) {
|
|
71427
71343
|
if (!ch)
|
|
71428
71344
|
return false;
|
|
@@ -72080,7 +71996,7 @@ function assessTitleCoverage(title, code) {
|
|
|
72080
71996
|
const repeatedHit = [...repeated].some((term) => hay.includes(term));
|
|
72081
71997
|
return { covered: hit >= needed || repeatedHit, missingTerms };
|
|
72082
71998
|
}
|
|
72083
|
-
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;
|
|
71999
|
+
var COVERAGE_STOP_WORDS, MAX_ASSERTION_JOIN_CHARS, MAX_COVERAGE_LINE_CHARS, REGEX_PRECEDER2, 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;
|
|
72084
72000
|
var init_expected_outcome_coverage = __esm({
|
|
72085
72001
|
"../shared/dist/expected-outcome-coverage.js"() {
|
|
72086
72002
|
"use strict";
|
|
@@ -72117,6 +72033,7 @@ var init_expected_outcome_coverage = __esm({
|
|
|
72117
72033
|
]);
|
|
72118
72034
|
MAX_ASSERTION_JOIN_CHARS = 8e3;
|
|
72119
72035
|
MAX_COVERAGE_LINE_CHARS = 2e3;
|
|
72036
|
+
REGEX_PRECEDER2 = "(,=:[!&|?{};+-*%<>~^";
|
|
72120
72037
|
BLOCK_SCAFFOLD = /=>|\b(?:test|describe|it|beforeEach|afterEach|beforeAll|afterAll|function)\b/;
|
|
72121
72038
|
cachedAssertionInput = null;
|
|
72122
72039
|
cachedAssertionSource = { raw: "", normalized: "", bindings: /* @__PURE__ */ new Map(), bindingRefs: /* @__PURE__ */ new Map() };
|
|
@@ -72260,22 +72177,37 @@ function classifyAuthHandoffIntent(text) {
|
|
|
72260
72177
|
function withoutIdpUrlAsserts(code) {
|
|
72261
72178
|
return code.replace(/\.(?:toHaveURL|waitForURL)\s*\((?:[^)(]|\([^)]*\))*\)/g, (match) => /accountchooser|accounts\.google|appleid\.apple|login\.microsoftonline|\/v\d+\/signin|oauth/i.test(match) ? "" : match);
|
|
72262
72179
|
}
|
|
72180
|
+
function stripLineComment(line) {
|
|
72181
|
+
let from = line.length;
|
|
72182
|
+
while (from > 0) {
|
|
72183
|
+
const c = line.charCodeAt(from - 1);
|
|
72184
|
+
if (c === 10 || c === 13 || c === 8232 || c === 8233)
|
|
72185
|
+
break;
|
|
72186
|
+
from--;
|
|
72187
|
+
}
|
|
72188
|
+
const at = line.indexOf("//", from);
|
|
72189
|
+
return at < 0 ? line : line.slice(0, at);
|
|
72190
|
+
}
|
|
72263
72191
|
function stripComments(code) {
|
|
72264
|
-
return replaceBlockComments(code, () => "").split("\n").map(
|
|
72192
|
+
return replaceBlockComments(code, () => "").split("\n").map(stripLineComment).join("\n");
|
|
72265
72193
|
}
|
|
72266
|
-
function
|
|
72267
|
-
const
|
|
72268
|
-
|
|
72269
|
-
|
|
72270
|
-
let depth = 0;
|
|
72271
|
-
for (let i = open; i < code.length; i++) {
|
|
72194
|
+
function closingParens(code) {
|
|
72195
|
+
const close = new Int32Array(code.length).fill(-1);
|
|
72196
|
+
const open = [];
|
|
72197
|
+
for (let i = 0; i < code.length; i++) {
|
|
72272
72198
|
const c = code[i];
|
|
72273
72199
|
if (c === "(")
|
|
72274
|
-
|
|
72275
|
-
else if (c === ")" &&
|
|
72276
|
-
|
|
72200
|
+
open.push(i);
|
|
72201
|
+
else if (c === ")" && open.length > 0)
|
|
72202
|
+
close[open.pop()] = i;
|
|
72277
72203
|
}
|
|
72278
|
-
return
|
|
72204
|
+
return close;
|
|
72205
|
+
}
|
|
72206
|
+
function balancedCall(code, close, start) {
|
|
72207
|
+
const open = code.indexOf("(", start);
|
|
72208
|
+
if (open < 0 || close[open] < 0)
|
|
72209
|
+
return null;
|
|
72210
|
+
return { inner: code.slice(open + 1, close[open]), end: close[open] };
|
|
72279
72211
|
}
|
|
72280
72212
|
function resolveLocator(code, subject) {
|
|
72281
72213
|
const id = subject.trim().match(/^([A-Za-z_$][\w$]*)$/);
|
|
@@ -72323,8 +72255,10 @@ function isAuthHandoffDismissCode(code) {
|
|
|
72323
72255
|
const expects = [];
|
|
72324
72256
|
const re = new RegExp(EXPECT_CALL_RE.source, "g");
|
|
72325
72257
|
let match;
|
|
72258
|
+
let close = null;
|
|
72326
72259
|
while (match = re.exec(body)) {
|
|
72327
|
-
|
|
72260
|
+
close ??= closingParens(body);
|
|
72261
|
+
const found = balancedCall(body, close, match.index);
|
|
72328
72262
|
if (found)
|
|
72329
72263
|
expects.push({ inner: found.inner, tail: body.slice(found.end, found.end + 48) });
|
|
72330
72264
|
}
|
|
@@ -72369,12 +72303,209 @@ var init_auth_handoff_coverage = __esm({
|
|
|
72369
72303
|
}
|
|
72370
72304
|
});
|
|
72371
72305
|
|
|
72306
|
+
// ../shared/dist/auth-plan.js
|
|
72307
|
+
function hasInlineLoginSteps(playwrightCode) {
|
|
72308
|
+
if (!playwrightCode)
|
|
72309
|
+
return false;
|
|
72310
|
+
return /process\.env\.TEST_USER_EMAIL!?/.test(playwrightCode) && /process\.env\.TEST_USER_PASSWORD!?/.test(playwrightCode);
|
|
72311
|
+
}
|
|
72312
|
+
function hasGeneratedAuthGuard(playwrightCode) {
|
|
72313
|
+
if (!playwrightCode)
|
|
72314
|
+
return false;
|
|
72315
|
+
return /\/\/ >>> VALIDATE_QA_AUTH v(\d+)\b[\s\S]*?process\.env\.AUTH_FILE[\s\S]*?\/\/ <<< VALIDATE_QA_AUTH v\1\b/.test(playwrightCode);
|
|
72316
|
+
}
|
|
72317
|
+
function legacyNeedsCookieState(tags, code, sharedAuthInjectEnabled) {
|
|
72318
|
+
if (!sharedAuthInjectEnabled)
|
|
72319
|
+
return false;
|
|
72320
|
+
if (tags.includes("@auth"))
|
|
72321
|
+
return false;
|
|
72322
|
+
if (tags.includes("@api"))
|
|
72323
|
+
return true;
|
|
72324
|
+
if (!tags.includes("@needs-auth"))
|
|
72325
|
+
return false;
|
|
72326
|
+
if (sharedAuthInjectEnabled && tags.includes("@auth-guarded") && hasGeneratedAuthGuard(code))
|
|
72327
|
+
return true;
|
|
72328
|
+
const isGeneratedVariant = tags.includes("@edge") || tags.includes("@bug");
|
|
72329
|
+
const hasLegacyInlineLogin = tags.includes("@discovered") && !isGeneratedVariant && hasInlineLoginSteps(code);
|
|
72330
|
+
return !tags.includes("@inline-login") && !hasLegacyInlineLogin;
|
|
72331
|
+
}
|
|
72332
|
+
function codeReadsStoredCredentials(code) {
|
|
72333
|
+
if (!code)
|
|
72334
|
+
return false;
|
|
72335
|
+
if (/__vqaLogin\b/.test(code))
|
|
72336
|
+
return true;
|
|
72337
|
+
for (const m of code.matchAll(/TEST_[A-Z0-9_]+/g)) {
|
|
72338
|
+
if (/_(?:EMAIL|PASSWORD)/.test(m[0]))
|
|
72339
|
+
return true;
|
|
72340
|
+
}
|
|
72341
|
+
for (const m of code.matchAll(/process\.env\s*\[([^\]]*)\]?/g)) {
|
|
72342
|
+
if (!/^\s*(['"])[^'"`]*\1\s*$/.test(m[1]))
|
|
72343
|
+
return true;
|
|
72344
|
+
}
|
|
72345
|
+
return false;
|
|
72346
|
+
}
|
|
72347
|
+
function explicitAuthTypeTags(t) {
|
|
72348
|
+
const found = /* @__PURE__ */ new Set();
|
|
72349
|
+
for (const tag of t) {
|
|
72350
|
+
if (AUTH_TYPE_TAGS.includes(tag))
|
|
72351
|
+
found.add(tag);
|
|
72352
|
+
else if (Object.hasOwn(AUTH_TAG_ALIASES, tag))
|
|
72353
|
+
found.add(AUTH_TAG_ALIASES[tag]);
|
|
72354
|
+
}
|
|
72355
|
+
return [...found];
|
|
72356
|
+
}
|
|
72357
|
+
function invalidPlan(configurationError) {
|
|
72358
|
+
return {
|
|
72359
|
+
version: 1,
|
|
72360
|
+
source: "invalid",
|
|
72361
|
+
acquisition: "unsupported",
|
|
72362
|
+
presentation: "none",
|
|
72363
|
+
needsCookieState: false,
|
|
72364
|
+
needsStandingHeaders: false,
|
|
72365
|
+
standingHeadersMode: "none",
|
|
72366
|
+
needsLoginCreds: false,
|
|
72367
|
+
requiredEnvKeys: [],
|
|
72368
|
+
configurationError
|
|
72369
|
+
};
|
|
72370
|
+
}
|
|
72371
|
+
function explicitPlan(authTypeTag2, acquisition, presentation, opts) {
|
|
72372
|
+
return {
|
|
72373
|
+
version: 1,
|
|
72374
|
+
source: "explicit",
|
|
72375
|
+
authTypeTag: authTypeTag2,
|
|
72376
|
+
acquisition,
|
|
72377
|
+
presentation,
|
|
72378
|
+
needsCookieState: opts.cookie,
|
|
72379
|
+
needsStandingHeaders: opts.standingMode === "required",
|
|
72380
|
+
standingHeadersMode: opts.standingMode,
|
|
72381
|
+
needsLoginCreds: TEST_USER_ENV_KEYS.every((k) => opts.requiredEnvKeys.includes(k)),
|
|
72382
|
+
requiredEnvKeys: opts.requiredEnvKeys
|
|
72383
|
+
};
|
|
72384
|
+
}
|
|
72385
|
+
function deriveAuthPlan(tags, code, opts) {
|
|
72386
|
+
const t = Array.isArray(tags) ? tags : [];
|
|
72387
|
+
const sharedFlag = opts?.sharedAuthInjectEnabled ?? false;
|
|
72388
|
+
const isApi = t.includes("@api");
|
|
72389
|
+
const explicit = isApi ? explicitAuthTypeTags(t) : [];
|
|
72390
|
+
if (explicit.length > 0) {
|
|
72391
|
+
if (t.includes("@auth")) {
|
|
72392
|
+
return invalidPlan("@auth (self-login UI) cannot be combined with an explicit @api auth-type tag");
|
|
72393
|
+
}
|
|
72394
|
+
const loginCompose = explicit.filter((e) => e === AUTH_TAG_COOKIE_STATE || e === AUTH_TAG_LOGIN_COOKIE || e === AUTH_TAG_LOGIN_BEARER);
|
|
72395
|
+
if (explicit.length === 2 && explicit.includes(AUTH_TAG_STANDING) && loginCompose.length === 1) {
|
|
72396
|
+
const composedKeys = [...TEST_USER_ENV_KEYS, API_AUTH_HEADERS_ENV_KEY];
|
|
72397
|
+
switch (loginCompose[0]) {
|
|
72398
|
+
case AUTH_TAG_COOKIE_STATE:
|
|
72399
|
+
return explicitPlan(AUTH_TAG_COOKIE_STATE, "browser-bootstrap", "cookie", { cookie: sharedFlag, standingMode: "required", requiredEnvKeys: composedKeys });
|
|
72400
|
+
case AUTH_TAG_LOGIN_COOKIE:
|
|
72401
|
+
return explicitPlan(AUTH_TAG_LOGIN_COOKIE, "request-login", "cookie", { cookie: false, standingMode: "required", requiredEnvKeys: composedKeys });
|
|
72402
|
+
case AUTH_TAG_LOGIN_BEARER:
|
|
72403
|
+
return explicitPlan(AUTH_TAG_LOGIN_BEARER, "request-login", "bearer", { cookie: false, standingMode: "required", requiredEnvKeys: composedKeys });
|
|
72404
|
+
}
|
|
72405
|
+
}
|
|
72406
|
+
if (explicit.length > 1) {
|
|
72407
|
+
return invalidPlan(`conflicting auth-type tags: ${explicit.join(", ")}`);
|
|
72408
|
+
}
|
|
72409
|
+
switch (explicit[0]) {
|
|
72410
|
+
case AUTH_TAG_UNSUPPORTED:
|
|
72411
|
+
return {
|
|
72412
|
+
...invalidPlan("auth scheme not yet drivable (e.g. HMAC / mTLS / provider-replay) \u2014 needs manual configuration")
|
|
72413
|
+
};
|
|
72414
|
+
case AUTH_TAG_NONE:
|
|
72415
|
+
return explicitPlan(AUTH_TAG_NONE, "none", "none", { cookie: false, standingMode: "none", requiredEnvKeys: [] });
|
|
72416
|
+
case AUTH_TAG_STANDING:
|
|
72417
|
+
return explicitPlan(AUTH_TAG_STANDING, "standing-secret", "standing-header", { cookie: false, standingMode: "required", requiredEnvKeys: [API_AUTH_HEADERS_ENV_KEY] });
|
|
72418
|
+
case AUTH_TAG_LOGIN_BEARER:
|
|
72419
|
+
return explicitPlan(AUTH_TAG_LOGIN_BEARER, "request-login", "bearer", { cookie: false, standingMode: "none", requiredEnvKeys: [...TEST_USER_ENV_KEYS] });
|
|
72420
|
+
case AUTH_TAG_LOGIN_COOKIE:
|
|
72421
|
+
return explicitPlan(AUTH_TAG_LOGIN_COOKIE, "request-login", "cookie", { cookie: false, standingMode: "legacy-if-configured", requiredEnvKeys: [...TEST_USER_ENV_KEYS] });
|
|
72422
|
+
case AUTH_TAG_COOKIE_STATE:
|
|
72423
|
+
return explicitPlan(AUTH_TAG_COOKIE_STATE, "browser-bootstrap", "cookie", { cookie: sharedFlag, standingMode: "legacy-if-configured", requiredEnvKeys: [...TEST_USER_ENV_KEYS] });
|
|
72424
|
+
}
|
|
72425
|
+
}
|
|
72426
|
+
const cookie = legacyNeedsCookieState(t, code, sharedFlag);
|
|
72427
|
+
const authedLegacy = t.includes("@auth") || t.includes("@needs-auth") || isApi;
|
|
72428
|
+
const selfLoginWithoutStoredCreds = t.includes("@auth") && !t.includes("@needs-auth") && !isApi && !!code?.trim() && !/TEST_USER_EMAIL|TEST_USER_PASSWORD|__vqaLogin\b/.test(code);
|
|
72429
|
+
const apiWithoutStoredCreds = isApi && !t.includes("@auth") && !t.includes("@needs-auth") && !!code?.trim() && !codeReadsStoredCredentials(code);
|
|
72430
|
+
const needsLoginCreds = authedLegacy && !selfLoginWithoutStoredCreds && !apiWithoutStoredCreds;
|
|
72431
|
+
return {
|
|
72432
|
+
version: 1,
|
|
72433
|
+
source: "legacy",
|
|
72434
|
+
acquisition: cookie ? "browser-bootstrap" : authedLegacy ? "request-login" : "none",
|
|
72435
|
+
presentation: authedLegacy ? "cookie" : "none",
|
|
72436
|
+
needsCookieState: cookie,
|
|
72437
|
+
needsStandingHeaders: false,
|
|
72438
|
+
// A legacy bare-@api test keeps injecting standing headers IF the project configured them
|
|
72439
|
+
// (preserving today's behavior) — but does not require them. Non-@api legacy tests never inject.
|
|
72440
|
+
standingHeadersMode: isApi ? "legacy-if-configured" : "none",
|
|
72441
|
+
needsLoginCreds,
|
|
72442
|
+
requiredEnvKeys: needsLoginCreds ? [...TEST_USER_ENV_KEYS] : []
|
|
72443
|
+
};
|
|
72444
|
+
}
|
|
72445
|
+
function authTypeTag(tags) {
|
|
72446
|
+
const t = Array.isArray(tags) ? tags : [];
|
|
72447
|
+
const explicit = explicitAuthTypeTags(t);
|
|
72448
|
+
return explicit.length === 1 ? explicit[0] : void 0;
|
|
72449
|
+
}
|
|
72450
|
+
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;
|
|
72451
|
+
var init_auth_plan = __esm({
|
|
72452
|
+
"../shared/dist/auth-plan.js"() {
|
|
72453
|
+
"use strict";
|
|
72454
|
+
AUTH_TAG_COOKIE_STATE = "@auth-cookie-state";
|
|
72455
|
+
AUTH_TAG_LOGIN_COOKIE = "@auth-login-cookie";
|
|
72456
|
+
AUTH_TAG_LOGIN_BEARER = "@auth-login-bearer";
|
|
72457
|
+
AUTH_TAG_STANDING = "@auth-standing";
|
|
72458
|
+
AUTH_TAG_NONE = "@auth-none";
|
|
72459
|
+
AUTH_TAG_UNSUPPORTED = "@auth-unsupported";
|
|
72460
|
+
AUTH_TYPE_TAGS = [
|
|
72461
|
+
AUTH_TAG_COOKIE_STATE,
|
|
72462
|
+
AUTH_TAG_LOGIN_COOKIE,
|
|
72463
|
+
AUTH_TAG_LOGIN_BEARER,
|
|
72464
|
+
AUTH_TAG_STANDING,
|
|
72465
|
+
AUTH_TAG_NONE,
|
|
72466
|
+
AUTH_TAG_UNSUPPORTED
|
|
72467
|
+
];
|
|
72468
|
+
AUTH_TAG_ALIASES = {
|
|
72469
|
+
"@auth-cookie": AUTH_TAG_COOKIE_STATE,
|
|
72470
|
+
"@auth-bearer": AUTH_TAG_LOGIN_BEARER,
|
|
72471
|
+
"@auth-token": AUTH_TAG_LOGIN_BEARER,
|
|
72472
|
+
"@auth-api-key": AUTH_TAG_STANDING,
|
|
72473
|
+
"@auth-standing-header": AUTH_TAG_STANDING
|
|
72474
|
+
};
|
|
72475
|
+
TEST_USER_ENV_KEYS = ["TEST_USER_EMAIL", "TEST_USER_PASSWORD"];
|
|
72476
|
+
API_AUTH_HEADERS_ENV_KEY = "API_AUTH_HEADERS";
|
|
72477
|
+
}
|
|
72478
|
+
});
|
|
72479
|
+
|
|
72372
72480
|
// ../shared/dist/assertion-strength.js
|
|
72481
|
+
function parseLastActionProofMode(raw) {
|
|
72482
|
+
const v = (raw ?? "").trim().toLowerCase();
|
|
72483
|
+
return v === "on" || v === "shadow" ? v : "off";
|
|
72484
|
+
}
|
|
72485
|
+
function isUrlProof(stmt) {
|
|
72486
|
+
if (URL_PROOF.test(stmt))
|
|
72487
|
+
return true;
|
|
72488
|
+
let calls = 0;
|
|
72489
|
+
for (const open of stmt.matchAll(POLL_OPEN)) {
|
|
72490
|
+
if (++calls > POLL_CALLS_MAX)
|
|
72491
|
+
break;
|
|
72492
|
+
const from = open.index + open[0].length;
|
|
72493
|
+
const args = balancedArguments(stmt, from, MATCHER_ARGS_MAX);
|
|
72494
|
+
if (args === null)
|
|
72495
|
+
continue;
|
|
72496
|
+
const subject = pollSubject(args);
|
|
72497
|
+
if (!POLL_PAGE_URL.test(subject))
|
|
72498
|
+
continue;
|
|
72499
|
+
if (!POLL_PAGE_URL_ONLY.test(subject) || PAGE_VALUE_MATCHER.test(stmt.slice(from + args.length)))
|
|
72500
|
+
return true;
|
|
72501
|
+
}
|
|
72502
|
+
return false;
|
|
72503
|
+
}
|
|
72373
72504
|
function liveExpectStatements(uncommented) {
|
|
72374
72505
|
const masked = maskedOutsideStrings(uncommented).split("\n");
|
|
72375
72506
|
return accumulateStatements(uncommented.split("\n")).filter((s) => EXPECT_STMT.test(s.stmt) && EXPECT_STMT.test(masked[s.startLine - 1] ?? ""));
|
|
72376
72507
|
}
|
|
72377
|
-
function
|
|
72508
|
+
function stripLineComment2(ln) {
|
|
72378
72509
|
let quote = null;
|
|
72379
72510
|
for (let i = 0; i < ln.length; i++) {
|
|
72380
72511
|
const c = ln[i];
|
|
@@ -72397,7 +72528,7 @@ function splitInteractionStatementsWithLines(lines) {
|
|
|
72397
72528
|
let depth = 0;
|
|
72398
72529
|
let scaffold = false;
|
|
72399
72530
|
for (let i = 0; i < lines.length; i++) {
|
|
72400
|
-
const ln =
|
|
72531
|
+
const ln = stripLineComment2(lines[i]).trim();
|
|
72401
72532
|
if (!ln)
|
|
72402
72533
|
continue;
|
|
72403
72534
|
const isContinuation = out.length > 0 && (ln.startsWith(".") || depth > 0 && !scaffold);
|
|
@@ -72421,7 +72552,7 @@ function testBlockIds(lines) {
|
|
|
72421
72552
|
let any = false;
|
|
72422
72553
|
let block = 0;
|
|
72423
72554
|
for (let i = 0; i < lines.length; i++) {
|
|
72424
|
-
const ln =
|
|
72555
|
+
const ln = stripLineComment2(lines[i]).trim();
|
|
72425
72556
|
if (!open) {
|
|
72426
72557
|
if (!TEST_BLOCK_OPEN.test(ln))
|
|
72427
72558
|
continue;
|
|
@@ -72505,7 +72636,7 @@ function expectSubjectSpan(stmt) {
|
|
|
72505
72636
|
}
|
|
72506
72637
|
return null;
|
|
72507
72638
|
}
|
|
72508
|
-
function resolveSubjectBindings(stmts, bindings, blockOfLine) {
|
|
72639
|
+
function resolveSubjectBindings(stmts, bindings, blockOfLine, boundAt) {
|
|
72509
72640
|
if (bindings.length === 0)
|
|
72510
72641
|
return [...stmts];
|
|
72511
72642
|
return stmts.map((item) => {
|
|
@@ -72528,14 +72659,22 @@ function resolveSubjectBindings(stmts, bindings, blockOfLine) {
|
|
|
72528
72659
|
subject = `${lead[1]}${found.expr.replace(/;\s*$/, "")}${subject.slice(lead[0].length)}`;
|
|
72529
72660
|
line = found.line;
|
|
72530
72661
|
}
|
|
72531
|
-
|
|
72662
|
+
const out = { ...item, stmt: `${item.stmt.slice(0, span.from)}${subject}${item.stmt.slice(span.to)}` };
|
|
72663
|
+
if (boundAt !== void 0 && line !== item.startLine)
|
|
72664
|
+
boundAt.set(out, line);
|
|
72665
|
+
return out;
|
|
72532
72666
|
});
|
|
72533
72667
|
}
|
|
72534
72668
|
function stripLoginScaffolding(code) {
|
|
72535
|
-
const
|
|
72669
|
+
const lines = code.split("\n");
|
|
72670
|
+
return keptScaffoldingLines(lines).map((i) => lines[i]).join("\n");
|
|
72671
|
+
}
|
|
72672
|
+
function keptScaffoldingLines(lines) {
|
|
72673
|
+
const kept = [];
|
|
72536
72674
|
let inAuth = false;
|
|
72537
72675
|
let inInbox = false;
|
|
72538
|
-
for (
|
|
72676
|
+
for (let i = 0; i < lines.length; i++) {
|
|
72677
|
+
const ln = lines[i];
|
|
72539
72678
|
if (!inAuth && !inInbox && AUTH_START.test(ln)) {
|
|
72540
72679
|
inAuth = true;
|
|
72541
72680
|
continue;
|
|
@@ -72556,9 +72695,9 @@ function stripLoginScaffolding(code) {
|
|
|
72556
72695
|
}
|
|
72557
72696
|
if (LOGIN_CALL_LINE.test(ln))
|
|
72558
72697
|
continue;
|
|
72559
|
-
|
|
72698
|
+
kept.push(i);
|
|
72560
72699
|
}
|
|
72561
|
-
return
|
|
72700
|
+
return kept;
|
|
72562
72701
|
}
|
|
72563
72702
|
function stripCommentsAndLogs(code) {
|
|
72564
72703
|
return stripCoverageComments(code).split("\n").filter((ln) => !/^\s*console\./.test(ln)).join("\n");
|
|
@@ -72567,7 +72706,7 @@ function detectsErrorBannerAssertion(code) {
|
|
|
72567
72706
|
const cleaned = stripCommentsAndLogs(stripLoginScaffolding(code));
|
|
72568
72707
|
const lines = cleaned.split("\n");
|
|
72569
72708
|
const candidates = [];
|
|
72570
|
-
const positive = (stmt) => !
|
|
72709
|
+
const positive = (stmt) => !claimsAbsence(stmt);
|
|
72571
72710
|
const statements = liveExpectStatements(cleaned).map((s) => s.stmt);
|
|
72572
72711
|
for (const stmt of statements) {
|
|
72573
72712
|
if (positive(stmt))
|
|
@@ -72696,6 +72835,12 @@ function detectsObservedFailureAsExpected(code) {
|
|
|
72696
72835
|
return FAILURE_STATUS_ASSERT.some((re) => re.test(stmt)) || hasFailedListener && FAILED_LIST_ASSERT.test(stmt);
|
|
72697
72836
|
});
|
|
72698
72837
|
}
|
|
72838
|
+
function claimsAbsence(stmt) {
|
|
72839
|
+
const negated = NEGATED_ASSERT_NOT.test(stmt);
|
|
72840
|
+
const bare = negated ? stmt.replace(NOT_BEFORE_MATCHER, ".") : stmt;
|
|
72841
|
+
const absenceMatcher = /\.toBeHidden\s*\(|\.toHaveCount\s*\(\s*0\s*\)/.test(bare) || VALUE_ABSENCE.test(bare) || OPTION_ABSENCE.test(bare);
|
|
72842
|
+
return negated !== absenceMatcher;
|
|
72843
|
+
}
|
|
72699
72844
|
function isVacuousErrorAbsence(stmt, presence) {
|
|
72700
72845
|
if (!ABSENCE_MATCHER.test(stmt))
|
|
72701
72846
|
return false;
|
|
@@ -72704,6 +72849,41 @@ function isVacuousErrorAbsence(stmt, presence) {
|
|
|
72704
72849
|
return false;
|
|
72705
72850
|
return !presence().includes(m[1]);
|
|
72706
72851
|
}
|
|
72852
|
+
function isVacuousAccountAbsence(stmt, shown, account) {
|
|
72853
|
+
if (!claimsAbsence(stmt))
|
|
72854
|
+
return false;
|
|
72855
|
+
if (!ABSENCE_MATCHER.test(stmt)) {
|
|
72856
|
+
const negated = NEGATED_TEXT.exec(stmt);
|
|
72857
|
+
if (!negated)
|
|
72858
|
+
return false;
|
|
72859
|
+
const read = account.exec(stmt.slice(negated.index));
|
|
72860
|
+
return read !== null && !shown().has(read[0]);
|
|
72861
|
+
}
|
|
72862
|
+
const m = account.exec(stmt);
|
|
72863
|
+
if (!m || shown().has(m[0]))
|
|
72864
|
+
return false;
|
|
72865
|
+
for (let at = endOfEnclosingCall(stmt, m.index + m[0].length); at < stmt.length; at = endOfEnclosingCall(stmt, at)) {
|
|
72866
|
+
SCOPING_STEP.lastIndex = at;
|
|
72867
|
+
if (SCOPING_STEP.test(stmt))
|
|
72868
|
+
return false;
|
|
72869
|
+
}
|
|
72870
|
+
return true;
|
|
72871
|
+
}
|
|
72872
|
+
function endOfEnclosingCall(stmt, from) {
|
|
72873
|
+
let depth = 0;
|
|
72874
|
+
for (let i = from; i < stmt.length; i++) {
|
|
72875
|
+
const c = stmt[i];
|
|
72876
|
+
if (c === "'" || c === '"') {
|
|
72877
|
+
for (i++; i < stmt.length && stmt[i] !== c; i++)
|
|
72878
|
+
if (stmt[i] === "\\")
|
|
72879
|
+
i++;
|
|
72880
|
+
} else if (c === "(")
|
|
72881
|
+
depth++;
|
|
72882
|
+
else if (c === ")" && depth-- === 0)
|
|
72883
|
+
return i + 1;
|
|
72884
|
+
}
|
|
72885
|
+
return stmt.length;
|
|
72886
|
+
}
|
|
72707
72887
|
function isBareContainerVisibility(stmt) {
|
|
72708
72888
|
return BARE_CONTAINER_ROLE.test(stmt) && !GET_BY_TEXT.test(stmt) && !HAS_TEXT_FILTER.test(stmt) && !TEXT_CONTENT_MATCHER.test(stmt);
|
|
72709
72889
|
}
|
|
@@ -72711,19 +72891,53 @@ function isChromeTarget(stmt) {
|
|
|
72711
72891
|
return CHROME_LOCATOR.test(stmt) && !CONTENT_ROLE.test(stmt) && !/getByText\s*\(/.test(stmt);
|
|
72712
72892
|
}
|
|
72713
72893
|
function countsAsContentText(stmt) {
|
|
72714
|
-
if (!TEXT_CONTENT_MATCHER.test(stmt))
|
|
72894
|
+
if (!TEXT_CONTENT_MATCHER.test(stmt) || NEGATED_ASSERT.test(stmt))
|
|
72715
72895
|
return false;
|
|
72716
72896
|
if (isSymbolOnlyArgument(stmt, TEXT_CONTENT_MATCHER))
|
|
72717
72897
|
return false;
|
|
72718
|
-
|
|
72898
|
+
return onContentTarget(stmt);
|
|
72899
|
+
}
|
|
72900
|
+
function onContentTarget(stmt) {
|
|
72901
|
+
return !isChromeTarget(stmt) || /getByRole\s*\(\s*['"`]main['"`]/i.test(stmt);
|
|
72902
|
+
}
|
|
72903
|
+
function provesTextRemoved(stmt, presence) {
|
|
72904
|
+
const m = stmt.match(NEGATED_TEXT);
|
|
72905
|
+
if (!m || !onContentTarget(stmt))
|
|
72906
|
+
return false;
|
|
72907
|
+
const text = m[1] ?? m[2];
|
|
72908
|
+
if (text === void 0)
|
|
72719
72909
|
return true;
|
|
72720
|
-
|
|
72910
|
+
if (!/[\p{L}\p{N}]/u.test(text))
|
|
72911
|
+
return false;
|
|
72912
|
+
return !ERROR_TEXT_WORDS.test(text) || presence().includes(text);
|
|
72721
72913
|
}
|
|
72722
72914
|
function isDataContentRole(stmt) {
|
|
72723
72915
|
return CONTENT_ROLE.test(stmt) && !ANNOUNCE_ROLE.test(stmt);
|
|
72724
72916
|
}
|
|
72917
|
+
function destructuresRequest(code) {
|
|
72918
|
+
let readTo = -1;
|
|
72919
|
+
for (const m of code.matchAll(ASYNC_DESTRUCTURE_OPEN)) {
|
|
72920
|
+
const start = m.index + m[0].length;
|
|
72921
|
+
if (start <= readTo)
|
|
72922
|
+
continue;
|
|
72923
|
+
let end = start;
|
|
72924
|
+
while (end < code.length && code[end] !== "}" && code[end] !== ")")
|
|
72925
|
+
end++;
|
|
72926
|
+
readTo = end;
|
|
72927
|
+
if (end === code.length)
|
|
72928
|
+
return false;
|
|
72929
|
+
if (code[end] !== "}" || !REQUEST_WORD.test(code.slice(start, end)))
|
|
72930
|
+
continue;
|
|
72931
|
+
let close = end + 1;
|
|
72932
|
+
while (close < code.length && /\s/.test(code[close]))
|
|
72933
|
+
close++;
|
|
72934
|
+
if (code[close] === ")")
|
|
72935
|
+
return true;
|
|
72936
|
+
}
|
|
72937
|
+
return false;
|
|
72938
|
+
}
|
|
72725
72939
|
function isApiTest(code) {
|
|
72726
|
-
const usesRequestFixture =
|
|
72940
|
+
const usesRequestFixture = destructuresRequest(code) || /\brequest\.(get|post|put|patch|delete|head|fetch)\s*\(/.test(code);
|
|
72727
72941
|
if (!usesRequestFixture)
|
|
72728
72942
|
return false;
|
|
72729
72943
|
const drivesUi = /\bpage\.(getBy\w+|locator|click|fill|goto|waitForURL|reload)\s*\(/.test(code) || /\.(click|fill|check|uncheck|selectOption|pressSequentially)\s*\(/.test(code);
|
|
@@ -72751,7 +72965,7 @@ function roleNames(s) {
|
|
|
72751
72965
|
function interactedControlNames(lines) {
|
|
72752
72966
|
const names = /* @__PURE__ */ new Set();
|
|
72753
72967
|
for (const raw of lines) {
|
|
72754
|
-
const ln =
|
|
72968
|
+
const ln = stripLineComment2(raw);
|
|
72755
72969
|
if (!INTERACT_VERB.test(ln))
|
|
72756
72970
|
continue;
|
|
72757
72971
|
for (const n of roleNames(ln))
|
|
@@ -72947,6 +73161,14 @@ function balancedArguments(code, from, limit = code.length) {
|
|
|
72947
73161
|
}
|
|
72948
73162
|
return null;
|
|
72949
73163
|
}
|
|
73164
|
+
function expectCallTail(stmt) {
|
|
73165
|
+
const at = stmt.search(EXPECT_CALL_RE);
|
|
73166
|
+
if (at < 0)
|
|
73167
|
+
return null;
|
|
73168
|
+
const from = stmt.indexOf("(", at) + 1;
|
|
73169
|
+
const args = balancedArguments(stmt, from, MATCHER_ARGS_MAX);
|
|
73170
|
+
return args === null ? null : stmt.slice(from + args.length).trimStart();
|
|
73171
|
+
}
|
|
72950
73172
|
function matcherArgumentsAreConstant(body, from) {
|
|
72951
73173
|
MATCHER_OPEN.lastIndex = from;
|
|
72952
73174
|
const opened = MATCHER_OPEN.exec(body);
|
|
@@ -72982,32 +73204,70 @@ function hasOnlyConstantAssertions(code) {
|
|
|
72982
73204
|
const { constant, real } = constantAssertions(code);
|
|
72983
73205
|
return constant.length > 0 && real === 0;
|
|
72984
73206
|
}
|
|
73207
|
+
function envValueKey(name) {
|
|
73208
|
+
return `\0env:${name}`;
|
|
73209
|
+
}
|
|
72985
73210
|
function enteredValues(stmts) {
|
|
72986
73211
|
const values = /* @__PURE__ */ new Map();
|
|
72987
73212
|
const navLines = [];
|
|
73213
|
+
const accountConsts = /* @__PURE__ */ new Set();
|
|
72988
73214
|
for (const { stmt, startLine } of stmts) {
|
|
72989
73215
|
if (PAGE_NAV.test(stmt))
|
|
72990
73216
|
navLines.push(startLine);
|
|
73217
|
+
for (const c of stmt.matchAll(ACCOUNT_CONST))
|
|
73218
|
+
accountConsts.add(c[1].replace(/\$/g, "\\$"));
|
|
72991
73219
|
let m;
|
|
72992
73220
|
ENTERED_VALUE.lastIndex = 0;
|
|
72993
|
-
|
|
72994
|
-
const
|
|
72995
|
-
if (!
|
|
72996
|
-
values.set(value, startLine);
|
|
72997
|
-
|
|
73221
|
+
const add = (value) => {
|
|
73222
|
+
const lines = values.get(value);
|
|
73223
|
+
if (!lines)
|
|
73224
|
+
values.set(value, [startLine]);
|
|
73225
|
+
else if (lines[lines.length - 1] !== startLine)
|
|
73226
|
+
lines.push(startLine);
|
|
73227
|
+
};
|
|
73228
|
+
while (m = ENTERED_VALUE.exec(stmt))
|
|
73229
|
+
add((m[1] ?? m[2] ?? m[3]).toLowerCase());
|
|
73230
|
+
ENTERED_ENV.lastIndex = 0;
|
|
73231
|
+
while (m = ENTERED_ENV.exec(stmt))
|
|
73232
|
+
add(envValueKey(m[1] ?? m[2] ?? m[3] ?? m[4]));
|
|
72998
73233
|
}
|
|
72999
|
-
|
|
73234
|
+
const consts = accountConsts.size > 0 ? `|(?<![\\w$.])(?:${[...accountConsts].join("|")})(?![\\w$])` : "";
|
|
73235
|
+
return { values, navLines, account: new RegExp(`${ACCOUNT_ENV}${consts}`) };
|
|
73000
73236
|
}
|
|
73001
|
-
function
|
|
73237
|
+
function countBelow(lines, line) {
|
|
73238
|
+
let lo = 0;
|
|
73239
|
+
let hi = lines.length;
|
|
73240
|
+
while (lo < hi) {
|
|
73241
|
+
const mid = lo + hi >> 1;
|
|
73242
|
+
if (lines[mid] < line)
|
|
73243
|
+
lo = mid + 1;
|
|
73244
|
+
else
|
|
73245
|
+
hi = mid;
|
|
73246
|
+
}
|
|
73247
|
+
return lo;
|
|
73248
|
+
}
|
|
73249
|
+
function enteredLinesOf(stmt, entered) {
|
|
73002
73250
|
const m = stmt.match(/\.toHaveValue\s*\(\s*(['"`])((?:(?!\1).)+)\1/);
|
|
73003
|
-
if (
|
|
73251
|
+
if (m)
|
|
73252
|
+
return entered.values.get(m[2].toLowerCase());
|
|
73253
|
+
const env = stmt.match(HAVE_VALUE_ENV);
|
|
73254
|
+
return env ? entered.values.get(envValueKey(env[1] ?? env[2])) : void 0;
|
|
73255
|
+
}
|
|
73256
|
+
function typedSinceLastNav(stmt, entered, startLine, lines = enteredLinesOf(stmt, entered)) {
|
|
73257
|
+
if (!lines || startLine === void 0)
|
|
73258
|
+
return false;
|
|
73259
|
+
const before = countBelow(lines, startLine);
|
|
73260
|
+
if (before === 0)
|
|
73004
73261
|
return false;
|
|
73005
|
-
|
|
73006
|
-
|
|
73262
|
+
return countBelow(entered.navLines, startLine) === countBelow(entered.navLines, lines[before - 1] + 1);
|
|
73263
|
+
}
|
|
73264
|
+
function isEnteredValueEcho(stmt, entered, startLine) {
|
|
73265
|
+
const lines = enteredLinesOf(stmt, entered);
|
|
73266
|
+
if (!lines)
|
|
73007
73267
|
return false;
|
|
73008
|
-
if (startLine === void 0)
|
|
73268
|
+
if (startLine === void 0 || lines[0] >= startLine)
|
|
73009
73269
|
return true;
|
|
73010
|
-
return
|
|
73270
|
+
return typedSinceLastNav(stmt, entered, startLine, lines);
|
|
73011
73271
|
}
|
|
73012
73272
|
function isAnyValueMatcher(stmt) {
|
|
73013
73273
|
if (/\.not\.toHaveValue\s*\(\s*(?:['"`]{2}|\/\^?\$?\/)/.test(stmt))
|
|
@@ -73097,6 +73357,49 @@ function hasAttributeTransition(stmts) {
|
|
|
73097
73357
|
return true;
|
|
73098
73358
|
return false;
|
|
73099
73359
|
}
|
|
73360
|
+
function comparesWithItself(subject, tail) {
|
|
73361
|
+
const m = SELF_COMPARE_MATCHER.exec(tail);
|
|
73362
|
+
if (!m)
|
|
73363
|
+
return false;
|
|
73364
|
+
const args = balancedArguments(tail, m[0].length, MATCHER_ARGS_MAX);
|
|
73365
|
+
if (args === null)
|
|
73366
|
+
return false;
|
|
73367
|
+
const squash2 = (x) => x.replace(/^\s*await\s+/, "").replace(/\s+/g, "");
|
|
73368
|
+
const expected = squash2(args);
|
|
73369
|
+
return expected === squash2(m[1] === "toHaveCount" ? `${subject}.count()` : subject);
|
|
73370
|
+
}
|
|
73371
|
+
function asPlainAssertion(s) {
|
|
73372
|
+
return plainAssertion(s, false);
|
|
73373
|
+
}
|
|
73374
|
+
function plainAssertion(s, keepSelfCompare) {
|
|
73375
|
+
const { stmt } = s;
|
|
73376
|
+
if (COUNT_AT_LEAST_ZERO.test(stmt))
|
|
73377
|
+
return [];
|
|
73378
|
+
const subject = extractExpectSubject(stmt);
|
|
73379
|
+
if (subject === null)
|
|
73380
|
+
return [s];
|
|
73381
|
+
const plain = subject.replace(/^await\s+/, "").trim();
|
|
73382
|
+
const subjectAt = stmt.indexOf(subject, stmt.search(EXPECT_CALL_RE));
|
|
73383
|
+
const tail = (stmt.startsWith("expect.poll", stmt.search(EXPECT_CALL_RE)) ? expectCallTail(stmt) : null) ?? stmt.slice(subjectAt + subject.length).trimStart();
|
|
73384
|
+
const as = (rewritten) => [{ ...s, stmt: rewritten }];
|
|
73385
|
+
if (LOCATOR_EXPR.test(plain) && !LOCATOR_VALUE_READ.test(plain) && ALWAYS_TRUE_ON_OBJECT.test(tail))
|
|
73386
|
+
return [];
|
|
73387
|
+
if (DEFINED_VALUE_READ.test(plain) && ALWAYS_DEFINED.test(tail))
|
|
73388
|
+
return [];
|
|
73389
|
+
if (!keepSelfCompare && comparesWithItself(plain, tail))
|
|
73390
|
+
return [];
|
|
73391
|
+
const visible = /^(.+)\.\s*isVisible\s*\(\s*\)$/s.exec(plain);
|
|
73392
|
+
if (visible && IS_VISIBLE_TRUE.test(tail))
|
|
73393
|
+
return as(`await expect(${visible[1]}).toBeVisible();`);
|
|
73394
|
+
if (/^page\s*\.\s*(?:url|title)\s*\(\s*\)$/.test(plain) && PAGE_VALUE_MATCHER.test(tail)) {
|
|
73395
|
+
const matcher = plain.includes("url") ? "toHaveURL" : "toHaveTitle";
|
|
73396
|
+
return as(`await expect(page)${tail.replace(/^\)\s*\.\s*\w+\s*\(/, `.${matcher}(`)}`);
|
|
73397
|
+
}
|
|
73398
|
+
return [s];
|
|
73399
|
+
}
|
|
73400
|
+
function assertionStrengthHoistedReadsOn(value = typeof process !== "undefined" ? process.env?.ASSERTION_STRENGTH_HOISTED_READS : void 0) {
|
|
73401
|
+
return /^(1|true|on)$/i.test((value ?? "").trim());
|
|
73402
|
+
}
|
|
73100
73403
|
function creditsOutcomeAlways(stmt, entered, startLine) {
|
|
73101
73404
|
if (!OUTCOME_ALWAYS.some((re) => re.test(stmt)))
|
|
73102
73405
|
return false;
|
|
@@ -73129,6 +73432,22 @@ function successNoticeQuote(stmt) {
|
|
|
73129
73432
|
}
|
|
73130
73433
|
return null;
|
|
73131
73434
|
}
|
|
73435
|
+
function namedPagePath(arg) {
|
|
73436
|
+
const text = arg.trim();
|
|
73437
|
+
let path;
|
|
73438
|
+
const quoted = /^(['"`])([^'"`]*)\1$/.exec(text);
|
|
73439
|
+
const regex = quoted ? null : /^\/((?:\\.|[^/\\])+)\/[a-z]*$/.exec(text);
|
|
73440
|
+
if (quoted) {
|
|
73441
|
+
path = quoted[2].replace(/^\$\{[^}]*\}/, "").replace(/^\*\*/, "").replace(/^[a-z][a-z\d+.-]*:\/\/[^/]*/i, "").replace(/\*\*$/, "");
|
|
73442
|
+
} else if (regex) {
|
|
73443
|
+
path = regex[1].replace(/^\^/, "").replace(/^\.\*/, "").replace(/\$$/, "").replace(/\\([/.-])/g, "$1");
|
|
73444
|
+
} else {
|
|
73445
|
+
return null;
|
|
73446
|
+
}
|
|
73447
|
+
if (!PLAIN_PAGE_PATH.test(path))
|
|
73448
|
+
return null;
|
|
73449
|
+
return path.length > 1 && path.endsWith("/") ? path.slice(0, -1) : path;
|
|
73450
|
+
}
|
|
73132
73451
|
function provesStoredControlValue(stmt, startLine, persistence) {
|
|
73133
73452
|
if (!persistence || startLine === void 0)
|
|
73134
73453
|
return false;
|
|
@@ -73155,7 +73474,64 @@ function reopenedAfterSave(startLine, persistence, reopens = persistence.reloadL
|
|
|
73155
73474
|
}
|
|
73156
73475
|
return lo < reopens.length && reopens[lo] < startLine;
|
|
73157
73476
|
}
|
|
73158
|
-
function
|
|
73477
|
+
function actsBetween(withLines, from, to) {
|
|
73478
|
+
let acts = actLinesOf.get(withLines);
|
|
73479
|
+
if (acts === void 0) {
|
|
73480
|
+
acts = withLines.filter((s) => ACTS.test(s.stmt)).map((s) => s.startLine).sort((a, b) => a - b);
|
|
73481
|
+
actLinesOf.set(withLines, acts);
|
|
73482
|
+
}
|
|
73483
|
+
let lo = 0;
|
|
73484
|
+
let hi = acts.length;
|
|
73485
|
+
while (lo < hi) {
|
|
73486
|
+
const mid = lo + hi >> 1;
|
|
73487
|
+
if (acts[mid] <= from)
|
|
73488
|
+
lo = mid + 1;
|
|
73489
|
+
else
|
|
73490
|
+
hi = mid;
|
|
73491
|
+
}
|
|
73492
|
+
return lo < acts.length && acts[lo] < to;
|
|
73493
|
+
}
|
|
73494
|
+
function signInProofWindow(stmts, withLines, lines, blockIds) {
|
|
73495
|
+
if (blockIds === null)
|
|
73496
|
+
return void 0;
|
|
73497
|
+
const testBodies2 = /* @__PURE__ */ new Set();
|
|
73498
|
+
for (let i = 0; i < lines.length; i++) {
|
|
73499
|
+
const id = blockIds[i];
|
|
73500
|
+
if (id > 0 && (i === 0 || blockIds[i - 1] !== id) && TEST_BODY_OPEN.test(stripLineComment2(lines[i]).trim()))
|
|
73501
|
+
testBodies2.add(id);
|
|
73502
|
+
}
|
|
73503
|
+
const blockOf = (i) => blockIds[withLines[i].startLine - 1];
|
|
73504
|
+
const passwordAt = stmts.findIndex((stmt, i) => testBodies2.has(blockOf(i)) && ENV_PASSWORD_ENTRY.test(stmt));
|
|
73505
|
+
if (passwordAt < 0)
|
|
73506
|
+
return void 0;
|
|
73507
|
+
const body = blockOf(passwordAt);
|
|
73508
|
+
let clickAt = passwordAt + 1;
|
|
73509
|
+
while (clickAt < stmts.length && FORM_INPUT.test(stmts[clickAt]) && !ANY_CLICK.test(stmts[clickAt]))
|
|
73510
|
+
clickAt++;
|
|
73511
|
+
if (clickAt >= stmts.length || blockOf(clickAt) !== body || !ANY_CLICK.test(stmts[clickAt]) || NAV_LOCATOR.test(stmts[clickAt]))
|
|
73512
|
+
return void 0;
|
|
73513
|
+
let end = clickAt + 1;
|
|
73514
|
+
for (; end < stmts.length && blockOf(end) === body; end++) {
|
|
73515
|
+
if (CLOSERS_ONLY.test(stmts[end]))
|
|
73516
|
+
continue;
|
|
73517
|
+
if (!ASSERT_OR_WAIT.test(stmts[end]) || ACTS.test(stmts[end]))
|
|
73518
|
+
return void 0;
|
|
73519
|
+
}
|
|
73520
|
+
return { after: withLines[clickAt].startLine, until: end < stmts.length ? withLines[end].startLine : Number.POSITIVE_INFINITY };
|
|
73521
|
+
}
|
|
73522
|
+
function isAccountControlCheck(stmt) {
|
|
73523
|
+
if (!VISIBILITY_MATCHER.test(stmt) || NEGATED_ASSERT.test(stmt) || OPTION_ABSENCE.test(stmt))
|
|
73524
|
+
return false;
|
|
73525
|
+
const role = ACCOUNT_CONTROL_ROLE.exec(stmt);
|
|
73526
|
+
if (!role)
|
|
73527
|
+
return false;
|
|
73528
|
+
const rest = stmt.slice(role.index + role[0].length, role.index + role[0].length + 300);
|
|
73529
|
+
const close = rest.indexOf("}");
|
|
73530
|
+
const options = close < 0 ? rest : rest.slice(0, close);
|
|
73531
|
+
const name = options.match(/(?:^|[\s,])name\s*:\s*/);
|
|
73532
|
+
return name !== null && ACCOUNT_EMAIL_ENV.test(options.slice(name.index + name[0].length));
|
|
73533
|
+
}
|
|
73534
|
+
function classifyOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstMutLine, persistence, signedIn) {
|
|
73159
73535
|
if (mutated && hasAttributeTransition(stmts))
|
|
73160
73536
|
return { kind: "durable" };
|
|
73161
73537
|
const notices = [];
|
|
@@ -73165,11 +73541,25 @@ function classifyOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstM
|
|
|
73165
73541
|
};
|
|
73166
73542
|
let presenceText;
|
|
73167
73543
|
const presence = () => presenceText ??= stmts.filter((o) => !ABSENCE_MATCHER.test(o.stmt) && !NEGATED_ASSERT.test(o.stmt)).map((o) => o.stmt).join("\n");
|
|
73544
|
+
let shownAccounts;
|
|
73545
|
+
const shown = () => {
|
|
73546
|
+
if (shownAccounts)
|
|
73547
|
+
return shownAccounts;
|
|
73548
|
+
const ref = new RegExp(entered.account.source, "g");
|
|
73549
|
+
return shownAccounts = new Set(stmts.filter((o) => !claimsAbsence(o.stmt)).flatMap((o) => Array.from(o.stmt.matchAll(ref), (m) => m[0])));
|
|
73550
|
+
};
|
|
73168
73551
|
for (const { stmt, startLine } of stmts) {
|
|
73169
73552
|
if (firstMutLine !== void 0 && startLine !== void 0 && startLine < firstMutLine)
|
|
73170
73553
|
continue;
|
|
73171
73554
|
if (isVacuousErrorAbsence(stmt, presence))
|
|
73172
73555
|
continue;
|
|
73556
|
+
if (COUNT_ONE.test(stmt) && quotedAssertedStrings(stmt).some((t) => clicked.has(t.toLowerCase())))
|
|
73557
|
+
continue;
|
|
73558
|
+
if (isVacuousAccountAbsence(stmt, shown, entered.account))
|
|
73559
|
+
continue;
|
|
73560
|
+
if (signedIn && startLine !== void 0 && startLine > signedIn.after && startLine < signedIn.until && isAccountControlCheck(stmt)) {
|
|
73561
|
+
return { kind: "durable" };
|
|
73562
|
+
}
|
|
73173
73563
|
if (creditsOutcomeAlways(stmt, entered, startLine))
|
|
73174
73564
|
return { kind: "durable" };
|
|
73175
73565
|
if (mutated && !NEGATED_ASSERT.test(stmt) && MESSAGE_SURFACE.test(stmt) && OUTCOME_TEXT.test(assertedText(stmt))) {
|
|
@@ -73179,12 +73569,15 @@ function classifyOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstM
|
|
|
73179
73569
|
else
|
|
73180
73570
|
return { kind: "durable" };
|
|
73181
73571
|
}
|
|
73182
|
-
|
|
73572
|
+
const retyped = typedSinceLastNav(stmt, entered, startLine);
|
|
73573
|
+
if (!retyped && STATE_MATCHER.test(stmt) && (persistence && startLine !== void 0 ? reopenedAfterSave(startLine, persistence, persistence.reloadCalls) : reloaded))
|
|
73183
73574
|
return { kind: "durable" };
|
|
73184
|
-
if (provesStoredControlValue(stmt, startLine, persistence))
|
|
73575
|
+
if (!retyped && provesStoredControlValue(stmt, startLine, persistence))
|
|
73185
73576
|
return { kind: "durable" };
|
|
73186
73577
|
if (countsAsContentText(stmt))
|
|
73187
73578
|
return { kind: "durable" };
|
|
73579
|
+
if (provesTextRemoved(stmt, presence))
|
|
73580
|
+
return { kind: "durable" };
|
|
73188
73581
|
if (mutated && VISIBILITY_MATCHER.test(stmt)) {
|
|
73189
73582
|
const revealsText = GET_BY_TEXT.test(stmt) || HAS_TEXT_FILTER.test(stmt) || CONTENT_ROLE.test(stmt);
|
|
73190
73583
|
if (revealsText && !isChromeTarget(stmt)) {
|
|
@@ -73248,10 +73641,57 @@ function noticeOnlyExemption(clicked, noticeText, interactionStmts) {
|
|
|
73248
73641
|
function detectOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstMutLine) {
|
|
73249
73642
|
return classifyOutcomeProof(stmts, mutated, reloaded, clicked, entered, firstMutLine).kind !== "none";
|
|
73250
73643
|
}
|
|
73644
|
+
function clickLabel(stmt) {
|
|
73645
|
+
let label = null;
|
|
73646
|
+
for (const m of stmt.matchAll(CONTROL_LABEL))
|
|
73647
|
+
label = m[2] ?? m[3] ?? null;
|
|
73648
|
+
return label;
|
|
73649
|
+
}
|
|
73650
|
+
function teardownLines(lines) {
|
|
73651
|
+
const out = new Array(lines.length).fill(false);
|
|
73652
|
+
let open = false;
|
|
73653
|
+
let depth = 0;
|
|
73654
|
+
for (let i = 0; i < lines.length; i++) {
|
|
73655
|
+
const ln = stripLineComment2(lines[i]).trim();
|
|
73656
|
+
let from = 0;
|
|
73657
|
+
if (!open) {
|
|
73658
|
+
const m = TEARDOWN_OPEN.exec(ln);
|
|
73659
|
+
if (!m)
|
|
73660
|
+
continue;
|
|
73661
|
+
open = true;
|
|
73662
|
+
depth = 0;
|
|
73663
|
+
from = m.index;
|
|
73664
|
+
}
|
|
73665
|
+
out[i] = true;
|
|
73666
|
+
let closed = false;
|
|
73667
|
+
let quote = null;
|
|
73668
|
+
for (let k = from; k < ln.length; k++) {
|
|
73669
|
+
const ch = ln[k];
|
|
73670
|
+
if (quote !== null) {
|
|
73671
|
+
if (ch === "\\")
|
|
73672
|
+
k++;
|
|
73673
|
+
else if (ch === quote)
|
|
73674
|
+
quote = null;
|
|
73675
|
+
continue;
|
|
73676
|
+
}
|
|
73677
|
+
if (ch === "'" || ch === '"' || ch === "`")
|
|
73678
|
+
quote = ch;
|
|
73679
|
+
else if (ch === "{")
|
|
73680
|
+
depth++;
|
|
73681
|
+
else if (ch === "}") {
|
|
73682
|
+
depth--;
|
|
73683
|
+
closed = true;
|
|
73684
|
+
}
|
|
73685
|
+
}
|
|
73686
|
+
if (depth <= 0 && closed)
|
|
73687
|
+
open = false;
|
|
73688
|
+
}
|
|
73689
|
+
return out;
|
|
73690
|
+
}
|
|
73251
73691
|
function validateAssertionStrength(code, opts = {}) {
|
|
73252
73692
|
const body = stripLoginScaffolding(code);
|
|
73253
73693
|
const lines = body.split("\n");
|
|
73254
|
-
const stmts = liveExpectStatements(stripCoverageComments(body));
|
|
73694
|
+
const stmts = liveExpectStatements(stripCoverageComments(body)).flatMap(asPlainAssertion);
|
|
73255
73695
|
const base2 = (extra) => ({
|
|
73256
73696
|
apiTest: false,
|
|
73257
73697
|
interacted: false,
|
|
@@ -73291,7 +73731,13 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
73291
73731
|
const interactionStmts = inlineLocatorBindings(interactionStmtsRaw);
|
|
73292
73732
|
const blockIds = testBlockIds(lines);
|
|
73293
73733
|
const blockOfLine = (line) => blockIds?.[line - 1] ?? 0;
|
|
73294
|
-
const
|
|
73734
|
+
const hoistedReads = assertionStrengthHoistedReadsOn();
|
|
73735
|
+
const boundAt = hoistedReads ? /* @__PURE__ */ new Map() : void 0;
|
|
73736
|
+
const resolved = resolveSubjectBindings(stmts, scopedLocatorBindings(interactionStmtsWithLines, blockOfLine), blockOfLine, boundAt);
|
|
73737
|
+
const checks = boundAt === void 0 ? resolved : resolved.flatMap((s) => {
|
|
73738
|
+
const from = boundAt.get(s);
|
|
73739
|
+
return plainAssertion(s, from !== void 0 && actsBetween(interactionStmtsWithLines, from, s.startLine));
|
|
73740
|
+
});
|
|
73295
73741
|
const insideTest = linesInsideTestBlocks(lines);
|
|
73296
73742
|
const inTestOrder = (i) => insideTest === null || insideTest[interactionStmtsWithLines[i].startLine - 1] === true;
|
|
73297
73743
|
let mutated = opts.interactionPerformed === true;
|
|
@@ -73301,9 +73747,34 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
73301
73747
|
let navClicks = 0;
|
|
73302
73748
|
const persistence = { mutLines: [], reloadLines: [], reloadCalls: [] };
|
|
73303
73749
|
const openedPages = /* @__PURE__ */ new Set();
|
|
73750
|
+
let checkedPage = null;
|
|
73751
|
+
const savedOnCheckedPage = /* @__PURE__ */ new Set();
|
|
73752
|
+
const saveAt = (i, at) => {
|
|
73753
|
+
lastMutIdx = i;
|
|
73754
|
+
if (!inTestOrder(i))
|
|
73755
|
+
return;
|
|
73756
|
+
persistence.mutLines.push(at);
|
|
73757
|
+
if (firstMutIdx < 0)
|
|
73758
|
+
firstMutIdx = i;
|
|
73759
|
+
if (checkedPage !== null)
|
|
73760
|
+
savedOnCheckedPage.add(checkedPage);
|
|
73761
|
+
};
|
|
73762
|
+
const lastActionProof = opts.lastActionProof ?? "off";
|
|
73763
|
+
const teardown = lastActionProof === "off" ? null : teardownLines(lines);
|
|
73764
|
+
const acts = { last: null, prev: null, count: 0 };
|
|
73765
|
+
const noteAct = (i, at, kind) => {
|
|
73766
|
+
if (teardown === null || teardown[at - 1] || !inTestOrder(i))
|
|
73767
|
+
return;
|
|
73768
|
+
if (kind !== "enter")
|
|
73769
|
+
acts.count++;
|
|
73770
|
+
acts.prev = acts.last;
|
|
73771
|
+
acts.last = { i, kind };
|
|
73772
|
+
};
|
|
73304
73773
|
for (let i = 0; i < interactionStmts.length; i++) {
|
|
73305
73774
|
const ln = interactionStmts[i];
|
|
73306
73775
|
const at = interactionStmtsWithLines[i].startLine;
|
|
73776
|
+
if (teardown !== null && acts.last?.kind === "fill" && ENTER_PRESS.test(ln))
|
|
73777
|
+
noteAct(i, at, "enter");
|
|
73307
73778
|
if (RELOAD.test(ln)) {
|
|
73308
73779
|
persistence.reloadLines.push(at);
|
|
73309
73780
|
persistence.reloadCalls.push(at);
|
|
@@ -73311,32 +73782,31 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
73311
73782
|
const opened = ln.match(/\.goto\s*\(\s*([^,)]+)/);
|
|
73312
73783
|
if (opened) {
|
|
73313
73784
|
const page = opened[1].trim();
|
|
73314
|
-
|
|
73785
|
+
const path = namedPagePath(page);
|
|
73786
|
+
if (openedPages.has(page) || path !== null && savedOnCheckedPage.has(path))
|
|
73315
73787
|
persistence.reloadLines.push(at);
|
|
73316
|
-
|
|
73317
|
-
|
|
73318
|
-
}
|
|
73788
|
+
openedPages.add(page);
|
|
73789
|
+
checkedPage = null;
|
|
73790
|
+
}
|
|
73791
|
+
if (/\bpage\s*\.\s*go(?:Back|Forward)\s*\(/.test(ln))
|
|
73792
|
+
checkedPage = null;
|
|
73793
|
+
const checked = URL_CHECK_ARG.exec(ln);
|
|
73794
|
+
if (checked)
|
|
73795
|
+
checkedPage = namedPagePath(checked[1] ?? checked[2]);
|
|
73319
73796
|
if (FORM_INPUT.test(ln)) {
|
|
73320
73797
|
mutated = true;
|
|
73321
|
-
|
|
73322
|
-
|
|
73323
|
-
persistence.mutLines.push(at);
|
|
73324
|
-
if (firstMutIdx < 0)
|
|
73325
|
-
firstMutIdx = i;
|
|
73326
|
-
}
|
|
73798
|
+
saveAt(i, at);
|
|
73799
|
+
noteAct(i, at, "fill");
|
|
73327
73800
|
continue;
|
|
73328
73801
|
}
|
|
73329
73802
|
if (ANY_CLICK.test(ln)) {
|
|
73330
73803
|
if (NAV_LOCATOR.test(ln)) {
|
|
73331
73804
|
navClicks++;
|
|
73805
|
+
checkedPage = null;
|
|
73332
73806
|
} else {
|
|
73333
73807
|
mutated = true;
|
|
73334
|
-
|
|
73335
|
-
|
|
73336
|
-
persistence.mutLines.push(at);
|
|
73337
|
-
if (firstMutIdx < 0)
|
|
73338
|
-
firstMutIdx = i;
|
|
73339
|
-
}
|
|
73808
|
+
saveAt(i, at);
|
|
73809
|
+
noteAct(i, at, "click");
|
|
73340
73810
|
}
|
|
73341
73811
|
}
|
|
73342
73812
|
}
|
|
@@ -73369,9 +73839,28 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
73369
73839
|
};
|
|
73370
73840
|
}
|
|
73371
73841
|
const orderedPersistence = firstMutLine !== void 0 ? persistence : void 0;
|
|
73372
|
-
const
|
|
73842
|
+
const signedIn = signInProofWindow(interactionStmts, interactionStmtsWithLines, lines, blockIds);
|
|
73843
|
+
const proof = classifyOutcomeProof(checks, mutated, reloaded, clickedControlNames(interactionStmts), entered, firstMutLine, orderedPersistence, signedIn);
|
|
73373
73844
|
if (proof.kind === "durable") {
|
|
73374
73845
|
const signals2 = base2({ interacted, mutated, navOnly, hasOutcomeProof: true, terminal });
|
|
73846
|
+
const { last, prev } = acts;
|
|
73847
|
+
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])))) {
|
|
73848
|
+
const lastLine = interactionStmtsWithLines[last.i].startLine;
|
|
73849
|
+
const clicked = clickedControlNames(interactionStmts);
|
|
73850
|
+
const after = classifyOutcomeProof(checks, mutated, reloaded, clicked, entered, lastLine, orderedPersistence, signedIn);
|
|
73851
|
+
const unproven = after.kind === "none" || after.kind === "notice" && noticeOnlyExemption(clicked, after.noticeText, interactionStmts) === null;
|
|
73852
|
+
if (unproven && lastActionProof === "on") {
|
|
73853
|
+
const line = (keptScaffoldingLines(code.split("\n"))[lastLine - 1] ?? lastLine - 1) + 1;
|
|
73854
|
+
return {
|
|
73855
|
+
ok: false,
|
|
73856
|
+
severity: "block",
|
|
73857
|
+
reason: `the last save (line ${line}) has no outcome check after it (the earlier check proves only the earlier action)`,
|
|
73858
|
+
signals: { ...signals2, lastActionUnproven: true }
|
|
73859
|
+
};
|
|
73860
|
+
}
|
|
73861
|
+
if (unproven)
|
|
73862
|
+
signals2.lastActionUnproven = true;
|
|
73863
|
+
}
|
|
73375
73864
|
return { ok: true, severity: "none", reason: "proves an outcome (count / diff / value / revealed content)", signals: signals2 };
|
|
73376
73865
|
}
|
|
73377
73866
|
if (mutated && proof.kind === "notice") {
|
|
@@ -73420,7 +73909,7 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
73420
73909
|
signals
|
|
73421
73910
|
};
|
|
73422
73911
|
}
|
|
73423
|
-
const urlProofAfter = interactionStmts.some((s, i) => i > lastMutIdx &&
|
|
73912
|
+
const urlProofAfter = interactionStmts.some((s, i) => i > lastMutIdx && isUrlProof(s));
|
|
73424
73913
|
if (urlProofAfter) {
|
|
73425
73914
|
return {
|
|
73426
73915
|
ok: false,
|
|
@@ -73457,7 +73946,7 @@ function validateAssertionStrength(code, opts = {}) {
|
|
|
73457
73946
|
signals
|
|
73458
73947
|
};
|
|
73459
73948
|
}
|
|
73460
|
-
var ERROR_BANNER, OUTCOME_ALWAYS, FORM_INPUT, ANY_CLICK, NAV_LOCATOR, URL_PROOF, 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, 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, ERROR_TEXT_WORDS, TEXT_REGEX_ARG, 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, IN_FLIGHT_TEXT, FORM_CONTROL_LOCATOR, CONTROL_VALUE_MATCHER, COPY_CONTROL, COPIED_NOTICE, SEND_CONTROL, SEND_NOTICE, MARK_READ_CONTROL, APP_DATA_FIELD;
|
|
73949
|
+
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;
|
|
73461
73950
|
var init_assertion_strength = __esm({
|
|
73462
73951
|
"../shared/dist/assertion-strength.js"() {
|
|
73463
73952
|
"use strict";
|
|
@@ -73466,6 +73955,7 @@ var init_assertion_strength = __esm({
|
|
|
73466
73955
|
init_assertion_proof();
|
|
73467
73956
|
init_auth_handoff_coverage();
|
|
73468
73957
|
init_expect_call();
|
|
73958
|
+
init_auth_plan();
|
|
73469
73959
|
ERROR_BANNER = /(client-side exception|application error|something (?:went wrong|broke)|unhandled (?:exception|error|rejection)|runtime error|error boundary|an unexpected error|internal server error|\b5\d\d\s+(?:internal\s+)?server error|stack trace|chunkloaderror|hydration failed|maximum update depth exceeded)/i;
|
|
73470
73960
|
OUTCOME_ALWAYS = [
|
|
73471
73961
|
/\.toHaveCount\s*\(/,
|
|
@@ -73482,8 +73972,8 @@ var init_assertion_strength = __esm({
|
|
|
73482
73972
|
// form field value
|
|
73483
73973
|
/\.toMatch\s*\(/,
|
|
73484
73974
|
// string/regex content match (e.g. textContent() vs /[2-9] selected/)
|
|
73485
|
-
/\.toBeDisabled\s*\(/,
|
|
73486
|
-
// a control became DISABLED — a gating/validation outcome
|
|
73975
|
+
/\.(?<!\.not\s*\.)\s*toBeDisabled\s*\(/,
|
|
73976
|
+
// a control became DISABLED — a gating/validation outcome (not.toBeDisabled is the toBeEnabled twin)
|
|
73487
73977
|
/\.not\.toBeVisible\s*\(/,
|
|
73488
73978
|
/\.toBeHidden\s*\(/
|
|
73489
73979
|
// something the action removed/closed (disappearance proof)
|
|
@@ -73491,12 +73981,16 @@ var init_assertion_strength = __esm({
|
|
|
73491
73981
|
FORM_INPUT = /\.(fill|selectOption|setInputFiles|check|uncheck|setChecked|pressSequentially)\s*\(|keyboard\.type\s*\(/;
|
|
73492
73982
|
ANY_CLICK = /\.click\s*\(/;
|
|
73493
73983
|
NAV_LOCATOR = /getByRole\s*\(\s*['"`](?:link|menuitem)['"`]/i;
|
|
73494
|
-
URL_PROOF = /\.toHaveURL\s*\(|\.waitForURL\s*\(/;
|
|
73984
|
+
URL_PROOF = /\.toHaveURL\s*\(|\.waitForURL\s*\(|\bexpect\s*\(\s*(?:await\s+)?page\s*\.\s*url\s*\(\s*\)\s*\)\s*\.\s*(?:toBe|toEqual|toStrictEqual|toMatch|toContain)\s*\(/;
|
|
73985
|
+
POLL_OPEN = /\bexpect\s*\.\s*poll\s*\(/g;
|
|
73986
|
+
POLL_PAGE_URL = /^page\s*\.\s*url\s*\(\s*\)/;
|
|
73987
|
+
POLL_PAGE_URL_ONLY = /^page\s*\.\s*url\s*\(\s*\)$/;
|
|
73988
|
+
POLL_CALLS_MAX = 8;
|
|
73495
73989
|
RELOAD = /\.reload\s*\(/;
|
|
73496
73990
|
EXPECT_STMT = /\bexpect\s*[.(]/;
|
|
73497
73991
|
BLOCK_SCAFFOLD2 = /=>|\b(?:test|describe|it|beforeEach|afterEach|beforeAll|afterAll|function)\b/;
|
|
73498
73992
|
TEST_BLOCK_OPEN = /^(?:test|it)(?:\.(?:only|skip|fixme|slow|serial|describe\.serial))?\s*\(|^(?:test\.)?(?:beforeEach|beforeAll)\s*\(/;
|
|
73499
|
-
LOCATOR_BINDING = /^(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s
|
|
73993
|
+
LOCATOR_BINDING = /^(?:const|let|var)\s+([A-Za-z_$][\w$]*)\s*=(?:\s*(?!\s)|\s*(?=\s(?:getByRole|getByText|getByLabel|getByPlaceholder|getByTestId|getByAltText|getByTitle|locator)\s*\())(.+?(?:getByRole|getByText|getByLabel|getByPlaceholder|getByTestId|getByAltText|getByTitle|locator)\s*\(.+)$/;
|
|
73500
73994
|
EXPECT_OPEN = /\bexpect(?:\.soft)?\s*\(/;
|
|
73501
73995
|
STATE_MATCHER = /\.(toBeChecked|toBeVisible|toHaveValue|toBeDisabled|toBeEnabled)\s*\(/;
|
|
73502
73996
|
CHROME_LOCATOR = /getByRole\s*\(\s*['"`](?:heading|navigation|banner|main|contentinfo|complementary|region|search|tablist|tab|button|link|menuitem|textbox|searchbox|combobox|spinbutton)['"`]/i;
|
|
@@ -73516,16 +74010,17 @@ var init_assertion_strength = __esm({
|
|
|
73516
74010
|
EMPTY_STATE_TEXT = /\bno\b[\s\S]{0,24}?\b(yet|found|results?|items?|favou?rites?|entries|records?|matches|posts?|comments?)\b|nothing (?:here|yet|to show|found)|\bempty\b|\(\s*0\s*\)|\b0\s+(?:favou?rites?|results?|items?|entries|records?|matches|posts?|comments?)\b/i;
|
|
73517
74011
|
AUTH_START = /^\s*\/\/\s*>>>\s*VALIDATE_QA_AUTH/;
|
|
73518
74012
|
AUTH_END = /^\s*\/\/\s*<<<\s*VALIDATE_QA_AUTH/;
|
|
73519
|
-
LOGIN_CALL_LINE = /^\s*await\s+__vqaLogin\s*\(\s*page\s*\)\s
|
|
74013
|
+
LOGIN_CALL_LINE = /^\s*await\s+__vqaLogin\s*\(\s*page\s*\)\s*(?:;\s*)?$/;
|
|
73520
74014
|
INBOX_START = /^\s*\/\/\s*>>>\s*VALIDATE_QA_INBOX/;
|
|
73521
74015
|
INBOX_END = /^\s*\/\/\s*<<<\s*VALIDATE_QA_INBOX/;
|
|
73522
74016
|
NEGATED_ASSERT = /\.not\s*\.\s*to[A-Z]\w*|\.toBeHidden\s*\(/;
|
|
74017
|
+
NEGATED_ASSERT_NOT = /\.not\s*\.\s*to[A-Z]/;
|
|
73523
74018
|
CONST_CHAIN_MAX_DEPTH = 5;
|
|
73524
74019
|
TYPED_INPUT = /\.(fill|type|pressSequentially|setInputFiles)\s*\(/;
|
|
73525
74020
|
TITLE_LINE = /^\s*(?:test|describe)(?:\.\w+)?\s*\(/;
|
|
73526
74021
|
FAILURE_STATUS_ASSERT = [
|
|
73527
74022
|
/\.status\s*\(\s*\)[^;]{0,200}\.(?:toBeGreaterThanOrEqual|toBeGreaterThan)\s*\(\s*(?:399|[45]\d\d)\b/,
|
|
73528
|
-
/\bexpect\s*\(\s*[^;]{0,200}\bstatus\s*(?:\(\s*\))
|
|
74023
|
+
/\bexpect\s*\(\s*[^;]{0,200}\bstatus\s*(?:\(\s*\)\s*)?>=?\s*(?:399|[45]\d\d)\b[^;]{0,200}\)\s*\.\s*(?:toBe\s*\(\s*true|toBeTruthy)/,
|
|
73529
74024
|
/\bexpect\s*\([^;]{0,200}\.ok\s*\(\s*\)\s*\)\s*\.\s*(?:toBe\s*\(\s*false\s*\)|toBeFalsy\s*\()/
|
|
73530
74025
|
];
|
|
73531
74026
|
FAILED_LIST_ASSERT = /\bexpect\s*\(\s*[^;]{0,200}(?:fail|abort|error)\w{0,40}(?:\.length)?\s*\)\s*\.\s*(?:toBeGreaterThan\s*\(\s*0|toHaveLength\s*\(\s*[1-9]|not\s*\.\s*toHaveLength\s*\(\s*0|not\s*\.\s*toEqual\s*\(\s*\[\s*\])/i;
|
|
@@ -73535,8 +74030,15 @@ var init_assertion_strength = __esm({
|
|
|
73535
74030
|
CATCH_ALL_PATTERN = /^(['"`])\*\*(?:\/\*)?\1$|^\/\.\*\/[a-z]*$/;
|
|
73536
74031
|
GUARD_HANDLER = /\bMUTATING\.has\s*\(|blockedbyclient|Read-only guard/;
|
|
73537
74032
|
ABSENCE_MATCHER = /\.not\.toBeVisible\s*\(|\.toBeHidden\s*\(|\.toHaveCount\s*\(\s*0\s*\)/;
|
|
74033
|
+
VALUE_ABSENCE = /\.(?:count\s*\(\s*\)[\s)]{0,10}\.(?:(?:toBe|toEqual|toStrictEqual)\s*\(\s*0\s*\)|toBeLessThan\s*\(\s*1\s*\))|isVisible\s*\(\s*\)[\s)]{0,10}\.(?:(?:toBe|toEqual|toStrictEqual)\s*\(\s*false\s*\)|toBeFalsy\s*\()|isHidden\s*\(\s*\)[\s)]{0,10}\.(?:(?:toBe|toEqual|toStrictEqual)\s*\(\s*true\s*\)|toBeTruthy\s*\())/;
|
|
74034
|
+
OPTION_ABSENCE = /\.(?:toBeVisible\s*\(\s*\{[^{}()]{0,200}\bvisible|toBeAttached\s*\(\s*\{[^{}()]{0,200}\battached)\s*:\s*false\b/;
|
|
74035
|
+
NOT_BEFORE_MATCHER = /\.not\s*\.\s*(?=to[A-Z])/g;
|
|
73538
74036
|
ERROR_TEXT_WORDS = /error|fail|wrong|try again|unable|could ?n.?t|can.?t|problem|invalid|unavailable/i;
|
|
73539
74037
|
TEXT_REGEX_ARG = /(?:getByText|hasText|getByRole\([^)]{0,200}name)\s*[:(]\s*(\/(?:\\.|[^/\\\n])+\/[a-z]*)/;
|
|
74038
|
+
SCOPING_STEP = /(?:\s*\.\s*(?:first|last|nth)\s*\([^()]*\))*\s*\.\s*(?:getBy[A-Z]\w*|locator|filter)\s*\(/y;
|
|
74039
|
+
NEGATED_TEXT = /\.not\s*\.\s*(?:toHaveText|toContainText)\s*\(\s*(?:['"`]([^'"`]*)['"`]|\/((?:\\.|[^/\\\n])+)\/)?/;
|
|
74040
|
+
ASYNC_DESTRUCTURE_OPEN = /async\s*\(\s*\{/g;
|
|
74041
|
+
REQUEST_WORD = /\brequest\b/;
|
|
73540
74042
|
ROLE_NAME_RE = /getByRole\s*\(\s*['"`][a-z]+['"`]\s*,\s*\{[^}]*?name\s*:\s*(?:['"`]([^'"`]+)['"`]|\/([^/]+)\/)/gi;
|
|
73541
74043
|
INTERACT_VERB = /\.(click|fill|check|uncheck|setChecked|selectOption|pressSequentially)\s*\(/;
|
|
73542
74044
|
ROLE_SIG_RE = /getByRole\s*\(\s*['"`]([a-z]+)['"`]\s*,\s*\{[^}]*?name\s*:\s*(?:['"`]([^'"`]+)['"`]|\/([^/]+)\/)/gi;
|
|
@@ -73557,21 +74059,64 @@ var init_assertion_strength = __esm({
|
|
|
73557
74059
|
MATCHER_OPEN = /\s*(?:\.\s*(?:not|resolves|rejects)\s*)*\.\s*[A-Za-z_$][\w$]*\s*\(/y;
|
|
73558
74060
|
ENTERED_VALUE = /\.(?:fill|pressSequentially)\s*\(\s*['"`]([^'"`]+)['"`]|keyboard\.type\s*\(\s*['"`]([^'"`]+)['"`]|\.selectOption\s*\(\s*(?:\[\s*)?(?:\{\s*(?:label|value)\s*:\s*)?['"`]([^'"`]+)['"`]/g;
|
|
73559
74061
|
PAGE_NAV = /\.(?:goto|reload)\s*\(/;
|
|
74062
|
+
ENV_READ = String.raw`process\.env(?:(?:\?\.|\.)([A-Za-z_]\w*)|(?:\?\.)?\[\s*['"]([A-Za-z_]\w*)['"]\s*\])`;
|
|
74063
|
+
ENTERED_ENV = new RegExp(String.raw`\.(?:fill|pressSequentially)\s*\(\s*${ENV_READ}|keyboard\.type\s*\(\s*${ENV_READ}`, "g");
|
|
74064
|
+
HAVE_VALUE_ENV = new RegExp(String.raw`\.toHaveValue\s*\(\s*${ENV_READ}`);
|
|
74065
|
+
ACCOUNT_KEYS = TEST_USER_ENV_KEYS.join("|");
|
|
74066
|
+
ACCOUNT_ENV = `process\\.env(?:\\??\\.(?:${ACCOUNT_KEYS})\\b|(?:\\?\\.)?\\[\\s*['"\`](?:${ACCOUNT_KEYS})['"\`]\\s*\\])`;
|
|
74067
|
+
ACCOUNT_CONST = new RegExp(`\\b(?:const|let|var)\\s+([A-Za-z_$][\\w$]*)\\s*(?::\\s*string\\s*)?=\\s*${ACCOUNT_ENV}`, "g");
|
|
73560
74068
|
IN_FLIGHT_TEXT = /^(?:(?:sending|saving|loading|searching|checking|processing|submitting|preparing|updating|please wait|working|one moment)\b[^.]{0,40}\.{2,3}|\.{3}|…)$/i;
|
|
74069
|
+
LOCATOR_VALUE_READ = /\.(?:count|textContent|innerText|innerHTML|inputValue|getAttribute|isVisible|isHidden|isChecked|isEnabled|isDisabled|isEditable|allTextContents|allInnerTexts|evaluate|evaluateAll|boundingBox|all)\s*\(/;
|
|
74070
|
+
LOCATOR_EXPR = /^(?:this\.)?page\s*\.\s*(?:getBy\w+|locator)\s*\(/;
|
|
74071
|
+
ALWAYS_TRUE_ON_OBJECT = /^\)\s*\.\s*(?:toBeTruthy|toBeDefined|not\s*\.\s*(?:toBeNull|toBeUndefined|toBeFalsy))\s*\(/;
|
|
74072
|
+
COUNT_AT_LEAST_ZERO = /\.(?:count\s*\(\s*\)|length)[\s)]{0,10}\.(?:toBeGreaterThanOrEqual\s*\(\s*0\s*\)|toBeGreaterThan\s*\(\s*-\s*1\s*\))/;
|
|
74073
|
+
DEFINED_VALUE_READ = /\.\s*(?:count|textContent|innerText|innerHTML|inputValue|getAttribute|title|url|isVisible|isHidden|isChecked|isEnabled|isDisabled|isEditable|allTextContents|allInnerTexts)\s*\([^()]*\)$/;
|
|
74074
|
+
ALWAYS_DEFINED = /^\)\s*\.\s*(?:toBeDefined|not\s*\.\s*toBeUndefined)\s*\(/;
|
|
74075
|
+
SELF_COMPARE_MATCHER = /^\)\s*\.\s*(toBe|toEqual|toStrictEqual|toHaveCount)\s*\(/;
|
|
74076
|
+
IS_VISIBLE_TRUE = /^\)*\s*\.\s*(?:toBe\s*\(\s*true\s*\)|toBeTruthy\s*\(\s*\))/;
|
|
74077
|
+
PAGE_VALUE_MATCHER = /^\)\s*\.\s*(?:toBe|toEqual|toStrictEqual|toMatch|toContain)\s*\(/;
|
|
74078
|
+
COUNT_ONE = /\.\s*toHaveCount\s*\(\s*1\s*\)/;
|
|
74079
|
+
URL_CHECK_ARG = /\bpage\s*\.\s*waitForURL\s*\(\s*([^,)]+)|\bexpect(?:\s*\.\s*soft)?\s*\(\s*page\s*\)\s*\.\s*toHaveURL\s*\(\s*([^,)]+)/;
|
|
74080
|
+
PLAIN_PAGE_PATH = /^\/[\w\-./~%]*(?:[?#][^\s]*)?$/;
|
|
73561
74081
|
FORM_CONTROL_LOCATOR = /getByRole\s*\(\s*['"`](?:combobox|switch|checkbox|radio|textbox|searchbox|spinbutton|slider)['"`]|getByLabel\s*\(|getByPlaceholder\s*\(/;
|
|
73562
74082
|
CONTROL_VALUE_MATCHER = /\.(?:toHaveValue|toHaveText|toContainText)\s*\(|\.toHaveAttribute\s*\(\s*['"`]aria-checked['"`]/;
|
|
74083
|
+
ACCOUNT_EMAIL_ENV = /^process\.env(?:(?:\?\.|\.)TEST_USER_EMAIL\b|(?:\?\.)?\[\s*['"]TEST_USER_EMAIL['"]\s*\])/;
|
|
74084
|
+
ENV_PASSWORD_ENTRY = /\.(?:fill|pressSequentially)\s*\(\s*process\.env(?:(?:\?\.|\.)TEST_USER_PASSWORD\b|(?:\?\.)?\[\s*['"]TEST_USER_PASSWORD['"]\s*\])/;
|
|
74085
|
+
ACCOUNT_CONTROL_ROLE = /getByRole\s*\(\s*['"`](?:button|link|menuitem)['"`]\s*,\s*\{/;
|
|
74086
|
+
ASSERT_OR_WAIT = /^(?:await\s+)?(?:expect(?:\.soft|\.poll)?\s*\(|[\w$]+(?:\.[\w$]+)*\.waitFor[A-Za-z]*\s*\()/;
|
|
74087
|
+
ACTS = /\.(?:click|dblclick|tap|press|pressSequentially|fill|clear|type|check|uncheck|setChecked|selectOption|setInputFiles|dispatchEvent|hover|focus|dragTo|goto|reload|goBack|goForward|evaluate|evaluateHandle)\s*\(|\b(?:keyboard|mouse|touchscreen)\s*\.|\.toPass\s*\(/;
|
|
74088
|
+
actLinesOf = /* @__PURE__ */ new WeakMap();
|
|
74089
|
+
CLOSERS_ONLY = /^[})\];,\s]+$/;
|
|
74090
|
+
TEST_BODY_OPEN = /^(?:test|it)(?:\.(?:only|skip|fixme|slow))?\s*\(/;
|
|
73563
74091
|
COPY_CONTROL = /\bcopy\b/i;
|
|
73564
74092
|
COPIED_NOTICE = /\bcopied\b/i;
|
|
73565
74093
|
SEND_CONTROL = /\b(send|submit|subscribe|sign up for|contact|feedback|join (the )?waitlist)\b/i;
|
|
73566
74094
|
SEND_NOTICE = /\b(thank|thanks|sent|subscribed|received|in touch)\b/i;
|
|
73567
74095
|
MARK_READ_CONTROL = /\bmark(?:ed)? as read\b|\bmark all(?: as)? read\b/i;
|
|
73568
74096
|
APP_DATA_FIELD = /\b(title|name of|amount|price|quantity|sku|status|due|assignee|project|ticket|invoice|order)\b/i;
|
|
74097
|
+
COMMIT_CONTROL = /\b(?:save|submit|update|apply|add|create|post|send|publish)\b|\bconfirm\s+changes\b/i;
|
|
74098
|
+
NOT_COMMIT_CONTROL = /\b(?:delete|remove|cancel|close|dismiss|discard|back|sign\s*out|log\s*out|logout|done|ok|got\s+it|export|download)\b/i;
|
|
74099
|
+
DESTRUCTIVE_CONTROL = /\b(?:delete|remove|discard)\b/i;
|
|
74100
|
+
ENTER_PRESS = /\.press\s*\(\s*['"`]Enter['"`]/;
|
|
74101
|
+
CONTROL_LABEL = /(?:name\s*:\s*|getBy(?:Text|Label|Title|TestId)\s*\(\s*|has-text\(\s*)(?:(['"`])((?:(?!\1).)*)\1|\/((?:\\.|[^/\\])+)\/)/g;
|
|
74102
|
+
isCommitClick = (stmt) => {
|
|
74103
|
+
const label = clickLabel(stmt);
|
|
74104
|
+
return label !== null && COMMIT_CONTROL.test(label) && !NOT_COMMIT_CONTROL.test(label) && !EXCLUDE_AFFORDANCE.test(label);
|
|
74105
|
+
};
|
|
74106
|
+
isDestructiveClick = (stmt) => {
|
|
74107
|
+
const label = clickLabel(stmt);
|
|
74108
|
+
return label !== null && DESTRUCTIVE_CONTROL.test(label);
|
|
74109
|
+
};
|
|
74110
|
+
TEARDOWN_OPEN = /\bfinally\s*\{|^(?:test\.)?(?:after|before)(?:Each|All)\s*\(/;
|
|
73569
74111
|
}
|
|
73570
74112
|
});
|
|
73571
74113
|
|
|
73572
74114
|
// ../shared/dist/run-classification.js
|
|
73573
|
-
function
|
|
73574
|
-
|
|
74115
|
+
function isCancelledReason(error2) {
|
|
74116
|
+
if (typeof error2 !== "string")
|
|
74117
|
+
return false;
|
|
74118
|
+
const text = error2.trim();
|
|
74119
|
+
return CANCELLED_REASON_PREFIXES.some((prefix) => text.startsWith(prefix));
|
|
73575
74120
|
}
|
|
73576
74121
|
function isHeldHealRun(run) {
|
|
73577
74122
|
return run?.status === "PASSED" && typeof run.error === "string" && run.error.startsWith(HEAL_PATCH_HELD_RUN_ERROR_PREFIX);
|
|
@@ -73604,7 +74149,7 @@ function pickLatestHealthRun(runs) {
|
|
|
73604
74149
|
for (const run of runs) {
|
|
73605
74150
|
if (run.mode === "auth-setup")
|
|
73606
74151
|
continue;
|
|
73607
|
-
if (run.status === "ERROR" &&
|
|
74152
|
+
if (run.status === "ERROR" && isCancelledReason(run.error))
|
|
73608
74153
|
continue;
|
|
73609
74154
|
if (isHeldHealRun(run))
|
|
73610
74155
|
continue;
|
|
@@ -73622,6 +74167,15 @@ function pickDisplayRun(runs) {
|
|
|
73622
74167
|
return latest;
|
|
73623
74168
|
return pickLatestHealthRun(runs) ?? latest;
|
|
73624
74169
|
}
|
|
74170
|
+
function featureRowRunStatus(runs) {
|
|
74171
|
+
const latest = runs.find((run) => run.mode !== "auth-setup");
|
|
74172
|
+
if (!latest)
|
|
74173
|
+
return null;
|
|
74174
|
+
const decisive = pickLatestHealthRun(runs.filter((run) => !isEnvironmentalError(run)));
|
|
74175
|
+
if (decisive)
|
|
74176
|
+
return decisive.status;
|
|
74177
|
+
return latest.status === "PENDING" || latest.status === "RUNNING" ? latest.status : null;
|
|
74178
|
+
}
|
|
73625
74179
|
function isEnvironmentalError(run) {
|
|
73626
74180
|
if (!run)
|
|
73627
74181
|
return false;
|
|
@@ -73653,7 +74207,7 @@ function classifyErrorMessage(error2) {
|
|
|
73653
74207
|
return "config_issue";
|
|
73654
74208
|
if (EMAIL_NOT_RECEIVED_PREFIXES.some((prefix) => normalized.startsWith(prefix)))
|
|
73655
74209
|
return "email_not_received";
|
|
73656
|
-
if (
|
|
74210
|
+
if (isCancelledReason(error2))
|
|
73657
74211
|
return "cancelled";
|
|
73658
74212
|
if (isRetriedRunInterruption(error2))
|
|
73659
74213
|
return "interrupted";
|
|
@@ -73688,7 +74242,7 @@ function heldHealRunWhere() {
|
|
|
73688
74242
|
function excludeCancelledRunsWhere() {
|
|
73689
74243
|
return {
|
|
73690
74244
|
NOT: [
|
|
73691
|
-
{ status: "ERROR", error: { not: null, startsWith:
|
|
74245
|
+
{ status: "ERROR", OR: CANCELLED_REASON_PREFIXES.map((prefix) => ({ error: { not: null, startsWith: prefix } })) },
|
|
73692
74246
|
heldHealRunWhere()
|
|
73693
74247
|
]
|
|
73694
74248
|
};
|
|
@@ -73766,11 +74320,25 @@ function reportedBugWhere() {
|
|
|
73766
74320
|
function bugReviewStatus(status) {
|
|
73767
74321
|
return status === "QUARANTINED" ? "confirmed" : "needs-review";
|
|
73768
74322
|
}
|
|
73769
|
-
var USER_CANCELLED_RUN_ERROR, 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, EMAIL_NOT_RECEIVED_PREFIXES, ENVIRONMENTAL_ERROR_PREFIXES, ENVIRONMENTAL_ERROR_STORED_PREFIXES, BUG_SURFACE_SUPPRESSING_TAGS, QUARANTINE_CLOSE_TAGS, BUG_CANDIDATE_TAG, BUG_TEST_BROKEN_TAG;
|
|
74323
|
+
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;
|
|
73770
74324
|
var init_run_classification = __esm({
|
|
73771
74325
|
"../shared/dist/run-classification.js"() {
|
|
73772
74326
|
"use strict";
|
|
73773
74327
|
USER_CANCELLED_RUN_ERROR = "Cancelled by user";
|
|
74328
|
+
PLATFORM_SUPPORT_CANCELLED_RUN_ERROR = "Cancelled by platform support";
|
|
74329
|
+
PLATFORM_ADMIN_CANCELLED_RUN_ERROR = "Cancelled by platform admin";
|
|
74330
|
+
ADMIN_FORCE_CANCELLED_RUN_ERROR = "Admin force-cancelled all active runs";
|
|
74331
|
+
CHAIN_CANCELLED_RUN_ERROR = "Cancelled: parent run cancelled";
|
|
74332
|
+
RETRY_HELD_RUN_ERROR = "Cancelled: auto generation paused";
|
|
74333
|
+
CANCELLED_REASON_PREFIXES = [
|
|
74334
|
+
USER_CANCELLED_RUN_ERROR,
|
|
74335
|
+
PLATFORM_SUPPORT_CANCELLED_RUN_ERROR,
|
|
74336
|
+
PLATFORM_ADMIN_CANCELLED_RUN_ERROR,
|
|
74337
|
+
ADMIN_FORCE_CANCELLED_RUN_ERROR,
|
|
74338
|
+
CHAIN_CANCELLED_RUN_ERROR,
|
|
74339
|
+
RETRY_HELD_RUN_ERROR
|
|
74340
|
+
];
|
|
74341
|
+
isUserCancelledError = isCancelledReason;
|
|
73774
74342
|
HEAL_PATCH_HELD_RUN_ERROR_PREFIX = "Heal patch held";
|
|
73775
74343
|
RUNNER_INTERRUPT_ERROR_PREFIX = "Runner shutting down";
|
|
73776
74344
|
SERVER_INTERRUPT_ERROR_PREFIX = "Run interrupted by server restart";
|
|
@@ -73786,6 +74354,7 @@ var init_run_classification = __esm({
|
|
|
73786
74354
|
UNEXPECTED_PASS_ERROR_PREFIX = "UNEXPECTED_PASS:";
|
|
73787
74355
|
BUG_TEST_BROKEN_ERROR_PREFIX = "BUG_TEST_BROKEN:";
|
|
73788
74356
|
BUG_TEST_BROKEN_REASON = "bug test broken (not a bug verdict)";
|
|
74357
|
+
TEST_DID_NOT_RUN_ERROR = "Test did not run (a dependency failed or the run was interrupted)";
|
|
73789
74358
|
EMAIL_NOT_RECEIVED_PREFIXES = [
|
|
73790
74359
|
"VERIFICATION_EMAIL_NOT_RECEIVED:",
|
|
73791
74360
|
"VERIFICATION_EMAIL_HAS_NO_CODE:",
|
|
@@ -73798,9 +74367,10 @@ var init_run_classification = __esm({
|
|
|
73798
74367
|
];
|
|
73799
74368
|
ENVIRONMENTAL_ERROR_STORED_PREFIXES = [
|
|
73800
74369
|
...ENVIRONMENTAL_ERROR_PREFIXES.flatMap((prefix) => [prefix, `Error: ${prefix}`]),
|
|
73801
|
-
// Written by the
|
|
73802
|
-
|
|
74370
|
+
// Written by the cancels as is, with no prefix wrapper.
|
|
74371
|
+
...CANCELLED_REASON_PREFIXES
|
|
73803
74372
|
];
|
|
74373
|
+
FEATURE_ROW_RUN_WINDOW = 10;
|
|
73804
74374
|
BUG_SURFACE_SUPPRESSING_TAGS = ["@rate-limit-blocked", "@quota-exceeded", "@auth-lost"];
|
|
73805
74375
|
QUARANTINE_CLOSE_TAGS = [
|
|
73806
74376
|
"@bug-found",
|
|
@@ -76233,180 +76803,6 @@ var init_admin_view_return_to = __esm({
|
|
|
76233
76803
|
}
|
|
76234
76804
|
});
|
|
76235
76805
|
|
|
76236
|
-
// ../shared/dist/auth-plan.js
|
|
76237
|
-
function hasInlineLoginSteps(playwrightCode) {
|
|
76238
|
-
if (!playwrightCode)
|
|
76239
|
-
return false;
|
|
76240
|
-
return /process\.env\.TEST_USER_EMAIL!?/.test(playwrightCode) && /process\.env\.TEST_USER_PASSWORD!?/.test(playwrightCode);
|
|
76241
|
-
}
|
|
76242
|
-
function hasGeneratedAuthGuard(playwrightCode) {
|
|
76243
|
-
if (!playwrightCode)
|
|
76244
|
-
return false;
|
|
76245
|
-
return /\/\/ >>> VALIDATE_QA_AUTH v(\d+)\b[\s\S]*?process\.env\.AUTH_FILE[\s\S]*?\/\/ <<< VALIDATE_QA_AUTH v\1\b/.test(playwrightCode);
|
|
76246
|
-
}
|
|
76247
|
-
function legacyNeedsCookieState(tags, code, sharedAuthInjectEnabled) {
|
|
76248
|
-
if (!sharedAuthInjectEnabled)
|
|
76249
|
-
return false;
|
|
76250
|
-
if (tags.includes("@auth"))
|
|
76251
|
-
return false;
|
|
76252
|
-
if (tags.includes("@api"))
|
|
76253
|
-
return true;
|
|
76254
|
-
if (!tags.includes("@needs-auth"))
|
|
76255
|
-
return false;
|
|
76256
|
-
if (sharedAuthInjectEnabled && tags.includes("@auth-guarded") && hasGeneratedAuthGuard(code))
|
|
76257
|
-
return true;
|
|
76258
|
-
const isGeneratedVariant = tags.includes("@edge") || tags.includes("@bug");
|
|
76259
|
-
const hasLegacyInlineLogin = tags.includes("@discovered") && !isGeneratedVariant && hasInlineLoginSteps(code);
|
|
76260
|
-
return !tags.includes("@inline-login") && !hasLegacyInlineLogin;
|
|
76261
|
-
}
|
|
76262
|
-
function codeReadsStoredCredentials(code) {
|
|
76263
|
-
if (!code)
|
|
76264
|
-
return false;
|
|
76265
|
-
if (/__vqaLogin\b/.test(code))
|
|
76266
|
-
return true;
|
|
76267
|
-
for (const m of code.matchAll(/TEST_[A-Z0-9_]+/g)) {
|
|
76268
|
-
if (/_(?:EMAIL|PASSWORD)/.test(m[0]))
|
|
76269
|
-
return true;
|
|
76270
|
-
}
|
|
76271
|
-
for (const m of code.matchAll(/process\.env\s*\[([^\]]*)\]?/g)) {
|
|
76272
|
-
if (!/^\s*(['"])[^'"`]*\1\s*$/.test(m[1]))
|
|
76273
|
-
return true;
|
|
76274
|
-
}
|
|
76275
|
-
return false;
|
|
76276
|
-
}
|
|
76277
|
-
function explicitAuthTypeTags(t) {
|
|
76278
|
-
const found = /* @__PURE__ */ new Set();
|
|
76279
|
-
for (const tag of t) {
|
|
76280
|
-
if (AUTH_TYPE_TAGS.includes(tag))
|
|
76281
|
-
found.add(tag);
|
|
76282
|
-
else if (Object.hasOwn(AUTH_TAG_ALIASES, tag))
|
|
76283
|
-
found.add(AUTH_TAG_ALIASES[tag]);
|
|
76284
|
-
}
|
|
76285
|
-
return [...found];
|
|
76286
|
-
}
|
|
76287
|
-
function invalidPlan(configurationError) {
|
|
76288
|
-
return {
|
|
76289
|
-
version: 1,
|
|
76290
|
-
source: "invalid",
|
|
76291
|
-
acquisition: "unsupported",
|
|
76292
|
-
presentation: "none",
|
|
76293
|
-
needsCookieState: false,
|
|
76294
|
-
needsStandingHeaders: false,
|
|
76295
|
-
standingHeadersMode: "none",
|
|
76296
|
-
needsLoginCreds: false,
|
|
76297
|
-
requiredEnvKeys: [],
|
|
76298
|
-
configurationError
|
|
76299
|
-
};
|
|
76300
|
-
}
|
|
76301
|
-
function explicitPlan(authTypeTag2, acquisition, presentation, opts) {
|
|
76302
|
-
return {
|
|
76303
|
-
version: 1,
|
|
76304
|
-
source: "explicit",
|
|
76305
|
-
authTypeTag: authTypeTag2,
|
|
76306
|
-
acquisition,
|
|
76307
|
-
presentation,
|
|
76308
|
-
needsCookieState: opts.cookie,
|
|
76309
|
-
needsStandingHeaders: opts.standingMode === "required",
|
|
76310
|
-
standingHeadersMode: opts.standingMode,
|
|
76311
|
-
needsLoginCreds: TEST_USER_ENV_KEYS.every((k) => opts.requiredEnvKeys.includes(k)),
|
|
76312
|
-
requiredEnvKeys: opts.requiredEnvKeys
|
|
76313
|
-
};
|
|
76314
|
-
}
|
|
76315
|
-
function deriveAuthPlan(tags, code, opts) {
|
|
76316
|
-
const t = Array.isArray(tags) ? tags : [];
|
|
76317
|
-
const sharedFlag = opts?.sharedAuthInjectEnabled ?? false;
|
|
76318
|
-
const isApi = t.includes("@api");
|
|
76319
|
-
const explicit = isApi ? explicitAuthTypeTags(t) : [];
|
|
76320
|
-
if (explicit.length > 0) {
|
|
76321
|
-
if (t.includes("@auth")) {
|
|
76322
|
-
return invalidPlan("@auth (self-login UI) cannot be combined with an explicit @api auth-type tag");
|
|
76323
|
-
}
|
|
76324
|
-
const loginCompose = explicit.filter((e) => e === AUTH_TAG_COOKIE_STATE || e === AUTH_TAG_LOGIN_COOKIE || e === AUTH_TAG_LOGIN_BEARER);
|
|
76325
|
-
if (explicit.length === 2 && explicit.includes(AUTH_TAG_STANDING) && loginCompose.length === 1) {
|
|
76326
|
-
const composedKeys = [...TEST_USER_ENV_KEYS, API_AUTH_HEADERS_ENV_KEY];
|
|
76327
|
-
switch (loginCompose[0]) {
|
|
76328
|
-
case AUTH_TAG_COOKIE_STATE:
|
|
76329
|
-
return explicitPlan(AUTH_TAG_COOKIE_STATE, "browser-bootstrap", "cookie", { cookie: sharedFlag, standingMode: "required", requiredEnvKeys: composedKeys });
|
|
76330
|
-
case AUTH_TAG_LOGIN_COOKIE:
|
|
76331
|
-
return explicitPlan(AUTH_TAG_LOGIN_COOKIE, "request-login", "cookie", { cookie: false, standingMode: "required", requiredEnvKeys: composedKeys });
|
|
76332
|
-
case AUTH_TAG_LOGIN_BEARER:
|
|
76333
|
-
return explicitPlan(AUTH_TAG_LOGIN_BEARER, "request-login", "bearer", { cookie: false, standingMode: "required", requiredEnvKeys: composedKeys });
|
|
76334
|
-
}
|
|
76335
|
-
}
|
|
76336
|
-
if (explicit.length > 1) {
|
|
76337
|
-
return invalidPlan(`conflicting auth-type tags: ${explicit.join(", ")}`);
|
|
76338
|
-
}
|
|
76339
|
-
switch (explicit[0]) {
|
|
76340
|
-
case AUTH_TAG_UNSUPPORTED:
|
|
76341
|
-
return {
|
|
76342
|
-
...invalidPlan("auth scheme not yet drivable (e.g. HMAC / mTLS / provider-replay) \u2014 needs manual configuration")
|
|
76343
|
-
};
|
|
76344
|
-
case AUTH_TAG_NONE:
|
|
76345
|
-
return explicitPlan(AUTH_TAG_NONE, "none", "none", { cookie: false, standingMode: "none", requiredEnvKeys: [] });
|
|
76346
|
-
case AUTH_TAG_STANDING:
|
|
76347
|
-
return explicitPlan(AUTH_TAG_STANDING, "standing-secret", "standing-header", { cookie: false, standingMode: "required", requiredEnvKeys: [API_AUTH_HEADERS_ENV_KEY] });
|
|
76348
|
-
case AUTH_TAG_LOGIN_BEARER:
|
|
76349
|
-
return explicitPlan(AUTH_TAG_LOGIN_BEARER, "request-login", "bearer", { cookie: false, standingMode: "none", requiredEnvKeys: [...TEST_USER_ENV_KEYS] });
|
|
76350
|
-
case AUTH_TAG_LOGIN_COOKIE:
|
|
76351
|
-
return explicitPlan(AUTH_TAG_LOGIN_COOKIE, "request-login", "cookie", { cookie: false, standingMode: "legacy-if-configured", requiredEnvKeys: [...TEST_USER_ENV_KEYS] });
|
|
76352
|
-
case AUTH_TAG_COOKIE_STATE:
|
|
76353
|
-
return explicitPlan(AUTH_TAG_COOKIE_STATE, "browser-bootstrap", "cookie", { cookie: sharedFlag, standingMode: "legacy-if-configured", requiredEnvKeys: [...TEST_USER_ENV_KEYS] });
|
|
76354
|
-
}
|
|
76355
|
-
}
|
|
76356
|
-
const cookie = legacyNeedsCookieState(t, code, sharedFlag);
|
|
76357
|
-
const authedLegacy = t.includes("@auth") || t.includes("@needs-auth") || isApi;
|
|
76358
|
-
const selfLoginWithoutStoredCreds = t.includes("@auth") && !t.includes("@needs-auth") && !isApi && !!code?.trim() && !/TEST_USER_EMAIL|TEST_USER_PASSWORD|__vqaLogin\b/.test(code);
|
|
76359
|
-
const apiWithoutStoredCreds = isApi && !t.includes("@auth") && !t.includes("@needs-auth") && !!code?.trim() && !codeReadsStoredCredentials(code);
|
|
76360
|
-
const needsLoginCreds = authedLegacy && !selfLoginWithoutStoredCreds && !apiWithoutStoredCreds;
|
|
76361
|
-
return {
|
|
76362
|
-
version: 1,
|
|
76363
|
-
source: "legacy",
|
|
76364
|
-
acquisition: cookie ? "browser-bootstrap" : authedLegacy ? "request-login" : "none",
|
|
76365
|
-
presentation: authedLegacy ? "cookie" : "none",
|
|
76366
|
-
needsCookieState: cookie,
|
|
76367
|
-
needsStandingHeaders: false,
|
|
76368
|
-
// A legacy bare-@api test keeps injecting standing headers IF the project configured them
|
|
76369
|
-
// (preserving today's behavior) — but does not require them. Non-@api legacy tests never inject.
|
|
76370
|
-
standingHeadersMode: isApi ? "legacy-if-configured" : "none",
|
|
76371
|
-
needsLoginCreds,
|
|
76372
|
-
requiredEnvKeys: needsLoginCreds ? [...TEST_USER_ENV_KEYS] : []
|
|
76373
|
-
};
|
|
76374
|
-
}
|
|
76375
|
-
function authTypeTag(tags) {
|
|
76376
|
-
const t = Array.isArray(tags) ? tags : [];
|
|
76377
|
-
const explicit = explicitAuthTypeTags(t);
|
|
76378
|
-
return explicit.length === 1 ? explicit[0] : void 0;
|
|
76379
|
-
}
|
|
76380
|
-
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;
|
|
76381
|
-
var init_auth_plan = __esm({
|
|
76382
|
-
"../shared/dist/auth-plan.js"() {
|
|
76383
|
-
"use strict";
|
|
76384
|
-
AUTH_TAG_COOKIE_STATE = "@auth-cookie-state";
|
|
76385
|
-
AUTH_TAG_LOGIN_COOKIE = "@auth-login-cookie";
|
|
76386
|
-
AUTH_TAG_LOGIN_BEARER = "@auth-login-bearer";
|
|
76387
|
-
AUTH_TAG_STANDING = "@auth-standing";
|
|
76388
|
-
AUTH_TAG_NONE = "@auth-none";
|
|
76389
|
-
AUTH_TAG_UNSUPPORTED = "@auth-unsupported";
|
|
76390
|
-
AUTH_TYPE_TAGS = [
|
|
76391
|
-
AUTH_TAG_COOKIE_STATE,
|
|
76392
|
-
AUTH_TAG_LOGIN_COOKIE,
|
|
76393
|
-
AUTH_TAG_LOGIN_BEARER,
|
|
76394
|
-
AUTH_TAG_STANDING,
|
|
76395
|
-
AUTH_TAG_NONE,
|
|
76396
|
-
AUTH_TAG_UNSUPPORTED
|
|
76397
|
-
];
|
|
76398
|
-
AUTH_TAG_ALIASES = {
|
|
76399
|
-
"@auth-cookie": AUTH_TAG_COOKIE_STATE,
|
|
76400
|
-
"@auth-bearer": AUTH_TAG_LOGIN_BEARER,
|
|
76401
|
-
"@auth-token": AUTH_TAG_LOGIN_BEARER,
|
|
76402
|
-
"@auth-api-key": AUTH_TAG_STANDING,
|
|
76403
|
-
"@auth-standing-header": AUTH_TAG_STANDING
|
|
76404
|
-
};
|
|
76405
|
-
TEST_USER_ENV_KEYS = ["TEST_USER_EMAIL", "TEST_USER_PASSWORD"];
|
|
76406
|
-
API_AUTH_HEADERS_ENV_KEY = "API_AUTH_HEADERS";
|
|
76407
|
-
}
|
|
76408
|
-
});
|
|
76409
|
-
|
|
76410
76806
|
// ../shared/dist/auth-block-detector.js
|
|
76411
76807
|
function stripEchoLines(text) {
|
|
76412
76808
|
return text.split("\n").filter((line) => !ECHO_LINE_RE.test(line)).join("\n");
|
|
@@ -76414,13 +76810,16 @@ function stripEchoLines(text) {
|
|
|
76414
76810
|
function matchesAny(text, patterns) {
|
|
76415
76811
|
return patterns.some((p) => p.test(text));
|
|
76416
76812
|
}
|
|
76813
|
+
function isIntentionalNegativeAuthTest(input) {
|
|
76814
|
+
const meta = [input.testName, input.description].filter(Boolean).join(" ");
|
|
76815
|
+
return matchesAny(meta, INTENTIONAL_NEGATIVE_AUTH);
|
|
76816
|
+
}
|
|
76417
76817
|
function detectAuthBlock(input) {
|
|
76418
76818
|
const tags = input.tags ?? [];
|
|
76419
76819
|
const isAuthed = tags.some((t) => AUTHED_TAGS.includes(t));
|
|
76420
76820
|
if (!isAuthed)
|
|
76421
76821
|
return NO_DETECTION;
|
|
76422
|
-
|
|
76423
|
-
if (matchesAny(meta, INTENTIONAL_NEGATIVE_AUTH))
|
|
76822
|
+
if (isIntentionalNegativeAuthTest(input))
|
|
76424
76823
|
return NO_DETECTION;
|
|
76425
76824
|
const sources = [];
|
|
76426
76825
|
if (input.error)
|
|
@@ -76523,7 +76922,24 @@ var init_auth_block_detector = __esm({
|
|
|
76523
76922
|
/\b(reject|deny|denied|block(ed)?)\b[^\n]{0,20}\b(login|sign[\s-]?in|auth|credential|password)\b/i
|
|
76524
76923
|
];
|
|
76525
76924
|
ECHO_LINE_RE = /^\s*(?:(?:📋|🎭|🌐|⚙️?)|(?:stderr:\s*|stdout:\s*)?Locator:)/u;
|
|
76526
|
-
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
|
|
76925
|
+
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;
|
|
76926
|
+
}
|
|
76927
|
+
});
|
|
76928
|
+
|
|
76929
|
+
// ../shared/dist/auth-session-stamp.js
|
|
76930
|
+
function parseAuthSessionStamp(value) {
|
|
76931
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
76932
|
+
return null;
|
|
76933
|
+
const { shared, role, generation } = value;
|
|
76934
|
+
if (shared !== true || role !== "producer" && role !== "follower")
|
|
76935
|
+
return null;
|
|
76936
|
+
return typeof generation === "string" && AUTH_SESSION_GENERATION_RE.test(generation) ? { shared: true, role, generation } : { shared: true, role };
|
|
76937
|
+
}
|
|
76938
|
+
var AUTH_SESSION_GENERATION_RE;
|
|
76939
|
+
var init_auth_session_stamp = __esm({
|
|
76940
|
+
"../shared/dist/auth-session-stamp.js"() {
|
|
76941
|
+
"use strict";
|
|
76942
|
+
AUTH_SESSION_GENERATION_RE = /^[0-9a-z]{1,16}$/;
|
|
76527
76943
|
}
|
|
76528
76944
|
});
|
|
76529
76945
|
|
|
@@ -77447,12 +77863,70 @@ function isSharedAuthInjectEnabled(value = process.env.SHARED_AUTH_INJECT) {
|
|
|
77447
77863
|
function isAuthReadinessGuardEnabled(value = process.env.AUTH_READINESS_GUARD) {
|
|
77448
77864
|
return value?.trim().toLowerCase() !== "false";
|
|
77449
77865
|
}
|
|
77866
|
+
function visualBaselinesEnabled(projectId, raw = process.env.VISUAL_BASELINES_PROJECTS) {
|
|
77867
|
+
if (typeof projectId !== "string" || projectId.trim() === "")
|
|
77868
|
+
return false;
|
|
77869
|
+
const listed = (raw ?? "").split(",").map((entry) => entry.trim()).filter(Boolean);
|
|
77870
|
+
return listed.includes("*") || listed.includes(projectId);
|
|
77871
|
+
}
|
|
77450
77872
|
var init_feature_flags = __esm({
|
|
77451
77873
|
"../shared/dist/feature-flags.js"() {
|
|
77452
77874
|
"use strict";
|
|
77453
77875
|
}
|
|
77454
77876
|
});
|
|
77455
77877
|
|
|
77878
|
+
// ../shared/dist/visual-compare-limits.js
|
|
77879
|
+
function isSafeMaskSelector(selector) {
|
|
77880
|
+
if (typeof selector !== "string")
|
|
77881
|
+
return false;
|
|
77882
|
+
if (selector.trim().length === 0)
|
|
77883
|
+
return false;
|
|
77884
|
+
if (selector.length > VISUAL_MASK_SELECTOR_MAX_LENGTH)
|
|
77885
|
+
return false;
|
|
77886
|
+
return !VISUAL_MASK_SELECTOR_FORBIDDEN.test(selector);
|
|
77887
|
+
}
|
|
77888
|
+
var VISUAL_MASK_SELECTORS_MAX, VISUAL_MASK_SELECTOR_MAX_LENGTH, VISUAL_MASK_SELECTOR_FORBIDDEN;
|
|
77889
|
+
var init_visual_compare_limits = __esm({
|
|
77890
|
+
"../shared/dist/visual-compare-limits.js"() {
|
|
77891
|
+
"use strict";
|
|
77892
|
+
VISUAL_MASK_SELECTORS_MAX = 50;
|
|
77893
|
+
VISUAL_MASK_SELECTOR_MAX_LENGTH = 300;
|
|
77894
|
+
VISUAL_MASK_SELECTOR_FORBIDDEN = /[{};@<\r\n]/;
|
|
77895
|
+
}
|
|
77896
|
+
});
|
|
77897
|
+
|
|
77898
|
+
// ../shared/dist/visual-baseline-identity.js
|
|
77899
|
+
function isBrowserVersion(value) {
|
|
77900
|
+
return typeof value === "string" && value.length <= 32 && BROWSER_VERSION.test(value);
|
|
77901
|
+
}
|
|
77902
|
+
function renderIdentity(flavour, version, image) {
|
|
77903
|
+
if (!/^[a-z][a-z-]{0,31}$/.test(flavour) || !/^[a-z][a-z-]{0,31}$/.test(image) || !isBrowserVersion(version))
|
|
77904
|
+
return null;
|
|
77905
|
+
const identity = `${flavour}/${version}/${image}`;
|
|
77906
|
+
return identity.length <= RENDER_IDENTITY_MAX_LENGTH ? identity : null;
|
|
77907
|
+
}
|
|
77908
|
+
function v1RenderIdentity(version) {
|
|
77909
|
+
return renderIdentity(VISUAL_V1_IDENTITY.flavour, version, VISUAL_V1_IDENTITY.image);
|
|
77910
|
+
}
|
|
77911
|
+
function parseRenderIdentity(value) {
|
|
77912
|
+
if (typeof value !== "string" || value.length > RENDER_IDENTITY_MAX_LENGTH)
|
|
77913
|
+
return null;
|
|
77914
|
+
const parts = value.split("/");
|
|
77915
|
+
if (parts.length !== 3)
|
|
77916
|
+
return null;
|
|
77917
|
+
const [flavour, version, image] = parts;
|
|
77918
|
+
return renderIdentity(flavour, version, image) === value ? { flavour, version, image } : null;
|
|
77919
|
+
}
|
|
77920
|
+
var VISUAL_V1_IDENTITY, RENDER_IDENTITY_MAX_LENGTH, BROWSER_VERSION;
|
|
77921
|
+
var init_visual_baseline_identity = __esm({
|
|
77922
|
+
"../shared/dist/visual-baseline-identity.js"() {
|
|
77923
|
+
"use strict";
|
|
77924
|
+
VISUAL_V1_IDENTITY = { platform: "linux", image: "runner-fast", flavour: "headless-shell" };
|
|
77925
|
+
RENDER_IDENTITY_MAX_LENGTH = 64;
|
|
77926
|
+
BROWSER_VERSION = /^\d{1,4}(\.\d{1,6}){0,3}$/;
|
|
77927
|
+
}
|
|
77928
|
+
});
|
|
77929
|
+
|
|
77456
77930
|
// ../shared/dist/analytics-url.js
|
|
77457
77931
|
function isSensitiveQueryKey(key) {
|
|
77458
77932
|
return SENSITIVE_QUERY_KEY_RE.test(key);
|
|
@@ -77755,7 +78229,7 @@ var init_agentic_cli_runtime = __esm({
|
|
|
77755
78229
|
GROK_CLI_DEFAULT_MODEL = "grok-4.7";
|
|
77756
78230
|
GROK_CLI_DEFAULT_REASONING_EFFORT = "high";
|
|
77757
78231
|
CLAUDE_CLI_DEFAULT_MODEL = "claude-sonnet-5-5";
|
|
77758
|
-
CLAUDE_CLI_DEFAULT_EFFORT = "
|
|
78232
|
+
CLAUDE_CLI_DEFAULT_EFFORT = "high";
|
|
77759
78233
|
MUSE_CLI_DEFAULT_MODEL = "muse-spark-1.3-contributor";
|
|
77760
78234
|
MUSE_CLI_DEFAULT_EFFORT = "high";
|
|
77761
78235
|
CODEX_CLI_DEFAULT_MODEL = "gpt-6.1-sol";
|
|
@@ -77810,6 +78284,17 @@ function openCodeGoWireModel(id) {
|
|
|
77810
78284
|
const trimmed = id?.trim() ?? "";
|
|
77811
78285
|
return isOpenCodeGoModelId(trimmed) ? trimmed.slice(OPENCODE_GO_PREFIX.length) : null;
|
|
77812
78286
|
}
|
|
78287
|
+
function isZaiModelId(id) {
|
|
78288
|
+
const trimmed = id?.trim() ?? "";
|
|
78289
|
+
return ZAI_MODEL_PATTERN.test(trimmed) && !trimmed.includes("..");
|
|
78290
|
+
}
|
|
78291
|
+
function hasZaiPrefix(id) {
|
|
78292
|
+
return (id?.trim() ?? "").startsWith(ZAI_PREFIX);
|
|
78293
|
+
}
|
|
78294
|
+
function zaiWireModel(id) {
|
|
78295
|
+
const trimmed = id?.trim() ?? "";
|
|
78296
|
+
return isZaiModelId(trimmed) ? trimmed.slice(ZAI_PREFIX.length) : null;
|
|
78297
|
+
}
|
|
77813
78298
|
function isEngineId(value) {
|
|
77814
78299
|
return CLI_ENGINE_MODEL_IDS.includes(value);
|
|
77815
78300
|
}
|
|
@@ -77906,7 +78391,7 @@ function museCliContributorMode(env = process.env) {
|
|
|
77906
78391
|
const raw = (env.MUSE_CLI_CONTRIBUTOR_MODE ?? "").trim().toLowerCase();
|
|
77907
78392
|
return raw === "off" || raw === "false" || raw === "0" || raw === "no" ? "off" : "on";
|
|
77908
78393
|
}
|
|
77909
|
-
var CLI_ENGINE_MODEL_IDS, BROWSER_CLI_ENGINE_IDS, PIPELINE_STEPS, CLI_ENGINE_RULES, ENGINE_NAMES, OPENROUTER_PREFIX, OPENROUTER_MODEL_PATTERN, OPENCODE_GO_PREFIX, OPENCODE_GO_MODEL_PATTERN;
|
|
78394
|
+
var CLI_ENGINE_MODEL_IDS, BROWSER_CLI_ENGINE_IDS, PIPELINE_STEPS, CLI_ENGINE_RULES, ENGINE_NAMES, OPENROUTER_PREFIX, OPENROUTER_MODEL_PATTERN, OPENCODE_GO_PREFIX, OPENCODE_GO_MODEL_PATTERN, ZAI_PREFIX, ZAI_MODEL_PATTERN;
|
|
77910
78395
|
var init_engine_spec = __esm({
|
|
77911
78396
|
"../shared/dist/engine-spec.js"() {
|
|
77912
78397
|
"use strict";
|
|
@@ -77966,6 +78451,8 @@ var init_engine_spec = __esm({
|
|
|
77966
78451
|
OPENROUTER_MODEL_PATTERN = /^openrouter:[a-z0-9][a-z0-9._-]{0,40}\/[A-Za-z0-9._:-]{1,100}$/;
|
|
77967
78452
|
OPENCODE_GO_PREFIX = "opencode-go:";
|
|
77968
78453
|
OPENCODE_GO_MODEL_PATTERN = /^opencode-go:[a-z0-9][a-z0-9._-]{0,100}$/;
|
|
78454
|
+
ZAI_PREFIX = "zai:";
|
|
78455
|
+
ZAI_MODEL_PATTERN = /^zai:glm-[a-z0-9][a-z0-9._-]{0,60}$/;
|
|
77969
78456
|
}
|
|
77970
78457
|
});
|
|
77971
78458
|
|
|
@@ -78250,6 +78737,8 @@ var init_api_model_catalog = __esm({
|
|
|
78250
78737
|
authCaptureModel: "Login capture",
|
|
78251
78738
|
plannerModel: "Scenario Planner",
|
|
78252
78739
|
plannerGateModel: "Planner Gate",
|
|
78740
|
+
pwAgentsHealerModel: "Test Healer (Playwright agents)",
|
|
78741
|
+
pwAgentsReviewModel: "Plan Review (Playwright agents)",
|
|
78253
78742
|
generationModel: "Code Generation",
|
|
78254
78743
|
reviewModel: "Code Review",
|
|
78255
78744
|
apiTestModel: "API Test Generator",
|
|
@@ -78274,11 +78763,6 @@ var init_api_model_catalog = __esm({
|
|
|
78274
78763
|
});
|
|
78275
78764
|
|
|
78276
78765
|
// ../shared/dist/provider-chains.js
|
|
78277
|
-
function isClaudeModel(id) {
|
|
78278
|
-
if (/claude|anthropic/i.test(id))
|
|
78279
|
-
return true;
|
|
78280
|
-
return API_MODEL_CATALOG.some((m) => m.provider === "anthropic" && (m.id === id || m.apiModel === id));
|
|
78281
|
-
}
|
|
78282
78766
|
function chainKey(modelId) {
|
|
78283
78767
|
const id = canonicalModelId(modelId);
|
|
78284
78768
|
if (!id)
|
|
@@ -78286,35 +78770,334 @@ function chainKey(modelId) {
|
|
|
78286
78770
|
const entry = API_MODEL_CATALOG.find((m) => m.id === id || m.apiModel === id);
|
|
78287
78771
|
return entry?.id ?? id;
|
|
78288
78772
|
}
|
|
78773
|
+
function has(map2, key) {
|
|
78774
|
+
return Object.prototype.hasOwnProperty.call(map2, key);
|
|
78775
|
+
}
|
|
78289
78776
|
function providerChainFor(modelId) {
|
|
78290
78777
|
const key = chainKey(modelId);
|
|
78291
|
-
if (
|
|
78292
|
-
return [];
|
|
78293
|
-
return
|
|
78778
|
+
if (key && has(_overrideHops, key))
|
|
78779
|
+
return _overrideHops[key];
|
|
78780
|
+
return key && has(PROVIDER_CHAINS, key) ? PROVIDER_CHAINS[key] : [];
|
|
78781
|
+
}
|
|
78782
|
+
function providerChainLeadsFor(modelId) {
|
|
78783
|
+
const key = chainKey(modelId);
|
|
78784
|
+
if (key && has(_overrideLeads, key))
|
|
78785
|
+
return _overrideLeads[key];
|
|
78786
|
+
return key && has(PROVIDER_CHAIN_LEADS, key) ? PROVIDER_CHAIN_LEADS[key] : [];
|
|
78787
|
+
}
|
|
78788
|
+
function allChains() {
|
|
78789
|
+
const ordered = (map2, override) => [...Object.entries(map2).filter(([key]) => !has(override, key)), ...Object.entries(override)];
|
|
78790
|
+
return [...ordered(PROVIDER_CHAINS, _overrideHops), ...ordered(PROVIDER_CHAIN_LEADS, _overrideLeads)];
|
|
78294
78791
|
}
|
|
78295
78792
|
function isProviderChainHopId(modelId) {
|
|
78296
78793
|
const id = modelId ?? "";
|
|
78297
|
-
return id !== "" &&
|
|
78794
|
+
return id !== "" && allChains().some(([, hops]) => hops.includes(id));
|
|
78298
78795
|
}
|
|
78299
78796
|
function providerChainPrimariesForHop(hopId) {
|
|
78300
78797
|
const id = hopId ?? "";
|
|
78301
78798
|
if (!id)
|
|
78302
78799
|
return [];
|
|
78303
|
-
return
|
|
78800
|
+
return allChains().filter(([, hops]) => hops.includes(id)).map(([primary]) => primary);
|
|
78801
|
+
}
|
|
78802
|
+
function providerChainHostOf(value, modelValue) {
|
|
78803
|
+
if (value === modelValue)
|
|
78804
|
+
return "own";
|
|
78805
|
+
if (hasZaiPrefix(value))
|
|
78806
|
+
return "zai";
|
|
78807
|
+
if (hasOpenCodeGoPrefix(value))
|
|
78808
|
+
return "opencode-go";
|
|
78809
|
+
if (hasOpenRouterPrefix(value))
|
|
78810
|
+
return "openrouter";
|
|
78811
|
+
return "own";
|
|
78812
|
+
}
|
|
78813
|
+
function providerChainHostProvider(value) {
|
|
78814
|
+
if (typeof value !== "string" || !value)
|
|
78815
|
+
return null;
|
|
78816
|
+
if (hasOpenRouterPrefix(value))
|
|
78817
|
+
return "openrouter";
|
|
78818
|
+
if (hasOpenCodeGoPrefix(value))
|
|
78819
|
+
return "opencode-go";
|
|
78820
|
+
if (hasZaiPrefix(value))
|
|
78821
|
+
return "zai";
|
|
78822
|
+
const key = chainKey(value);
|
|
78823
|
+
return API_MODEL_CATALOG.find((m) => m.id === key)?.provider ?? GEMINI_ASSISTANT_MODELS.find((m) => m.id === key)?.provider ?? null;
|
|
78824
|
+
}
|
|
78825
|
+
function providerHostPlan(modelId) {
|
|
78826
|
+
const key = chainKey(modelId);
|
|
78827
|
+
if (!key)
|
|
78828
|
+
return [];
|
|
78829
|
+
const own = { host: hasOpenRouterPrefix(key) ? "openrouter" : "own", value: key };
|
|
78830
|
+
const steps = [
|
|
78831
|
+
...providerChainLeadsFor(key).map((value) => ({ host: providerChainHostOf(value, key), value })),
|
|
78832
|
+
own,
|
|
78833
|
+
...providerChainFor(key).map((value) => ({ host: providerChainHostOf(value, key), value }))
|
|
78834
|
+
];
|
|
78835
|
+
const notOffered = Object.prototype.hasOwnProperty.call(PROVIDER_HOST_NOT_OFFERED, key) ? PROVIDER_HOST_NOT_OFFERED[key] : {};
|
|
78836
|
+
for (const [host, reason] of Object.entries(notOffered)) {
|
|
78837
|
+
const at = steps.findIndex((step) => step === own) + 1;
|
|
78838
|
+
steps.splice(at, 0, { host, value: null, notOffered: reason });
|
|
78839
|
+
}
|
|
78840
|
+
return steps;
|
|
78841
|
+
}
|
|
78842
|
+
function providerChainModelKey(modelId) {
|
|
78843
|
+
return chainKey(modelId);
|
|
78844
|
+
}
|
|
78845
|
+
function hasProviderChainLeadsByDefault(modelId) {
|
|
78846
|
+
const key = chainKey(modelId);
|
|
78847
|
+
return key !== null && has(PROVIDER_CHAIN_LEADS, key);
|
|
78848
|
+
}
|
|
78849
|
+
function isChainablePrimary(id) {
|
|
78850
|
+
return typeof id === "string" && id !== "" && (has(PROVIDER_CHAINS, id) || has(PROVIDER_CHAIN_LEADS, id));
|
|
78851
|
+
}
|
|
78852
|
+
function defaultProviderChainEntries(primary) {
|
|
78853
|
+
if (!isChainablePrimary(primary))
|
|
78854
|
+
return [];
|
|
78855
|
+
const leads = has(PROVIDER_CHAIN_LEADS, primary) ? PROVIDER_CHAIN_LEADS[primary] : [];
|
|
78856
|
+
const hops = has(PROVIDER_CHAINS, primary) ? PROVIDER_CHAINS[primary] : [];
|
|
78857
|
+
return [...leads, primary, ...hops].map((hop) => ({ hop, enabled: true }));
|
|
78858
|
+
}
|
|
78859
|
+
function allowedProviderChainHosts(primary) {
|
|
78860
|
+
return defaultProviderChainEntries(primary).map((entry) => entry.hop);
|
|
78861
|
+
}
|
|
78862
|
+
function isPlainObject2(value) {
|
|
78863
|
+
return value !== null && typeof value === "object" && !Array.isArray(value) && Object.getPrototypeOf(value) === Object.prototype;
|
|
78864
|
+
}
|
|
78865
|
+
function validateProviderChainEntries(primary, entries) {
|
|
78866
|
+
if (!isChainablePrimary(primary))
|
|
78867
|
+
return `${String(primary).slice(0, 80)} has no provider chain to order`;
|
|
78868
|
+
if (!Array.isArray(entries))
|
|
78869
|
+
return `${primary}: the chain must be a list`;
|
|
78870
|
+
if (entries.length > PROVIDER_CHAIN_MAX_ENTRIES)
|
|
78871
|
+
return `${primary}: at most ${PROVIDER_CHAIN_MAX_ENTRIES} hosts`;
|
|
78872
|
+
const allowed = allowedProviderChainHosts(primary);
|
|
78873
|
+
const seen = /* @__PURE__ */ new Set();
|
|
78874
|
+
for (const entry of entries) {
|
|
78875
|
+
if (!isPlainObject2(entry))
|
|
78876
|
+
return `${primary}: each host must be { hop, enabled }`;
|
|
78877
|
+
const keys = Object.keys(entry);
|
|
78878
|
+
if (keys.length !== 2 || !keys.includes("hop") || !keys.includes("enabled"))
|
|
78879
|
+
return `${primary}: each host must be { hop, enabled } and nothing else`;
|
|
78880
|
+
const { hop, enabled } = entry;
|
|
78881
|
+
if (typeof enabled !== "boolean")
|
|
78882
|
+
return `${primary}: enabled must be true or false`;
|
|
78883
|
+
if (typeof hop !== "string" || !hop)
|
|
78884
|
+
return `${primary}: hop must be a model value`;
|
|
78885
|
+
if (!allowed.includes(hop))
|
|
78886
|
+
return `${primary}: ${hop.slice(0, 80)} is not a host of this model`;
|
|
78887
|
+
if (seen.has(hop))
|
|
78888
|
+
return `${primary}: ${hop} is listed twice`;
|
|
78889
|
+
if (hop === primary && !enabled)
|
|
78890
|
+
return `${primary}: the model's own value stays on (pick another model on AI Models instead)`;
|
|
78891
|
+
seen.add(hop);
|
|
78892
|
+
}
|
|
78893
|
+
if (!seen.has(primary))
|
|
78894
|
+
return `${primary}: list the model's own value once, where its own host sits`;
|
|
78895
|
+
return null;
|
|
78896
|
+
}
|
|
78897
|
+
function decodeProviderChains(raw) {
|
|
78898
|
+
let value = raw;
|
|
78899
|
+
if (typeof raw === "string") {
|
|
78900
|
+
if (raw.length > PROVIDER_CHAINS_SETTING_MAX_CHARS)
|
|
78901
|
+
return { ok: false, error: `AI_PROVIDER_CHAINS is too long (at most ${PROVIDER_CHAINS_SETTING_MAX_CHARS} characters)` };
|
|
78902
|
+
try {
|
|
78903
|
+
value = JSON.parse(raw);
|
|
78904
|
+
} catch {
|
|
78905
|
+
return { ok: false, error: "AI_PROVIDER_CHAINS must be valid JSON" };
|
|
78906
|
+
}
|
|
78907
|
+
} else if (JSON.stringify(raw ?? null).length > PROVIDER_CHAINS_SETTING_MAX_CHARS) {
|
|
78908
|
+
return { ok: false, error: `AI_PROVIDER_CHAINS is too long (at most ${PROVIDER_CHAINS_SETTING_MAX_CHARS} characters)` };
|
|
78909
|
+
}
|
|
78910
|
+
if (!isPlainObject2(value))
|
|
78911
|
+
return { ok: false, error: 'AI_PROVIDER_CHAINS must be an object: { "<model>": [ { "hop": "<model value>", "enabled": true } ] }' };
|
|
78912
|
+
if (Object.keys(value).length > PROVIDER_CHAIN_MAX_PRIMARIES)
|
|
78913
|
+
return { ok: false, error: `AI_PROVIDER_CHAINS names at most ${PROVIDER_CHAIN_MAX_PRIMARIES} models` };
|
|
78914
|
+
return { ok: true, value };
|
|
78915
|
+
}
|
|
78916
|
+
function checkedProviderChains(value) {
|
|
78917
|
+
const out = {};
|
|
78918
|
+
for (const [primary, entries] of Object.entries(value)) {
|
|
78919
|
+
const problem = validateProviderChainEntries(primary, entries);
|
|
78920
|
+
if (problem)
|
|
78921
|
+
return { ok: false, error: problem };
|
|
78922
|
+
out[primary] = entries.map(({ hop, enabled }) => ({ hop, enabled }));
|
|
78923
|
+
}
|
|
78924
|
+
return { ok: true, value: out };
|
|
78925
|
+
}
|
|
78926
|
+
function parseProviderChainOverrides(raw) {
|
|
78927
|
+
const decoded = decodeProviderChains(raw);
|
|
78928
|
+
return decoded.ok ? checkedProviderChains(decoded.value) : decoded;
|
|
78929
|
+
}
|
|
78930
|
+
function parseStoredProviderChainOverrides(raw) {
|
|
78931
|
+
const decoded = decodeProviderChains(raw);
|
|
78932
|
+
if (!decoded.ok)
|
|
78933
|
+
return decoded;
|
|
78934
|
+
const dropped = [];
|
|
78935
|
+
const kept = {};
|
|
78936
|
+
for (const [primary, entries] of Object.entries(decoded.value)) {
|
|
78937
|
+
if (!isChainablePrimary(primary) || !Array.isArray(entries)) {
|
|
78938
|
+
kept[primary] = entries;
|
|
78939
|
+
continue;
|
|
78940
|
+
}
|
|
78941
|
+
const allowed = allowedProviderChainHosts(primary);
|
|
78942
|
+
kept[primary] = entries.filter((entry) => {
|
|
78943
|
+
const hop = isPlainObject2(entry) ? entry.hop : void 0;
|
|
78944
|
+
if (typeof hop !== "string" || hop === "" || allowed.includes(hop))
|
|
78945
|
+
return true;
|
|
78946
|
+
dropped.push({ primary, hop: hop.slice(0, 80) });
|
|
78947
|
+
return false;
|
|
78948
|
+
});
|
|
78949
|
+
}
|
|
78950
|
+
const checked = checkedProviderChains(kept);
|
|
78951
|
+
return checked.ok ? { ...checked, dropped } : checked;
|
|
78304
78952
|
}
|
|
78305
|
-
|
|
78953
|
+
function validateProviderChainsSetting(raw) {
|
|
78954
|
+
const parsed = parseProviderChainOverrides(raw);
|
|
78955
|
+
return parsed.ok ? null : parsed.error;
|
|
78956
|
+
}
|
|
78957
|
+
function setProviderChainOverrides(value, onDropped) {
|
|
78958
|
+
const parsed = value === null || value === void 0 || value === "" ? null : parseStoredProviderChainOverrides(value);
|
|
78959
|
+
if (parsed?.ok && parsed.dropped.length > 0)
|
|
78960
|
+
onDropped?.(parsed.dropped);
|
|
78961
|
+
_overrides = parsed?.ok ? parsed.value : null;
|
|
78962
|
+
_overrideLeads = {};
|
|
78963
|
+
_overrideHops = {};
|
|
78964
|
+
for (const [primary, entries] of Object.entries(_overrides ?? {})) {
|
|
78965
|
+
const at = entries.findIndex((entry) => entry.hop === primary);
|
|
78966
|
+
const on = (list) => list.filter((entry) => entry.enabled).map((entry) => entry.hop);
|
|
78967
|
+
_overrideLeads[primary] = on(entries.slice(0, at));
|
|
78968
|
+
_overrideHops[primary] = on(entries.slice(at + 1));
|
|
78969
|
+
}
|
|
78970
|
+
return parsed === null || parsed.ok;
|
|
78971
|
+
}
|
|
78972
|
+
function getProviderChainOverrides() {
|
|
78973
|
+
return _overrides;
|
|
78974
|
+
}
|
|
78975
|
+
var PROVIDER_CHAINS, PROVIDER_CHAIN_LEADS, PROVIDER_HOST_NOT_OFFERED, PROVIDER_CHAIN_MAX_ENTRIES, PROVIDER_CHAINS_SETTING_MAX_CHARS, PROVIDER_CHAIN_MAX_PRIMARIES, ALLOWED_PROVIDER_CHAIN_HOPS, _overrides, _overrideLeads, _overrideHops;
|
|
78306
78976
|
var init_provider_chains = __esm({
|
|
78307
78977
|
"../shared/dist/provider-chains.js"() {
|
|
78308
78978
|
"use strict";
|
|
78309
78979
|
init_api_model_catalog();
|
|
78980
|
+
init_engine_spec();
|
|
78310
78981
|
PROVIDER_CHAINS = {
|
|
78311
|
-
"minimax-m3": ["
|
|
78312
|
-
"minimax-m3.1-flash": ["
|
|
78982
|
+
"minimax-m3": ["opencode-go:minimax-m3", "openrouter:minimax/minimax-m3"],
|
|
78983
|
+
"minimax-m3.1-flash": ["opencode-go:minimax-m3.1-flash", "openrouter:minimax/minimax-m3.1-flash"],
|
|
78313
78984
|
"muse-spark-1.3-contributor": ["openrouter:meta/muse-spark-1.3-contributor"],
|
|
78314
|
-
"
|
|
78315
|
-
"
|
|
78316
|
-
"
|
|
78985
|
+
"claude-haiku-5-5": ["opencode-go:claude-haiku-5-5", "openrouter:anthropic/claude-haiku-5.5"],
|
|
78986
|
+
"gemini-3.1-pro-preview": ["openrouter:google/gemini-3.1-pro-preview"],
|
|
78987
|
+
"deepseek-flash": ["opencode-go:deepseek-v4.1-flash", "openrouter:deepseek/deepseek-v4.1-flash"],
|
|
78988
|
+
"deepseek-v4-pro": ["opencode-go:deepseek-v4-pro", "openrouter:deepseek/deepseek-v4-pro"]
|
|
78317
78989
|
};
|
|
78990
|
+
PROVIDER_CHAIN_LEADS = {
|
|
78991
|
+
"openrouter:z-ai/glm-5.3-flash": ["zai:glm-5.3-flash", "opencode-go:glm-5.3-flash"],
|
|
78992
|
+
"openrouter:z-ai/glm-5.3": ["zai:glm-5.3", "opencode-go:glm-5.3"],
|
|
78993
|
+
"openrouter:z-ai/glm-5.2": ["zai:glm-5.2", "opencode-go:glm-5.2"]
|
|
78994
|
+
};
|
|
78995
|
+
PROVIDER_HOST_NOT_OFFERED = {
|
|
78996
|
+
"muse-spark-1.3-contributor": { "opencode-go": "OpenCode Go serves Muse only on its Responses API" },
|
|
78997
|
+
"gemini-3.1-pro-preview": { "opencode-go": "OpenCode Go does not serve Gemini" }
|
|
78998
|
+
};
|
|
78999
|
+
PROVIDER_CHAIN_MAX_ENTRIES = 8;
|
|
79000
|
+
PROVIDER_CHAINS_SETTING_MAX_CHARS = 16e3;
|
|
79001
|
+
PROVIDER_CHAIN_MAX_PRIMARIES = 32;
|
|
79002
|
+
ALLOWED_PROVIDER_CHAIN_HOPS = /* @__PURE__ */ new Set([
|
|
79003
|
+
...Object.values(PROVIDER_CHAINS).flat(),
|
|
79004
|
+
...Object.values(PROVIDER_CHAIN_LEADS).flat()
|
|
79005
|
+
]);
|
|
79006
|
+
_overrides = null;
|
|
79007
|
+
_overrideLeads = {};
|
|
79008
|
+
_overrideHops = {};
|
|
79009
|
+
}
|
|
79010
|
+
});
|
|
79011
|
+
|
|
79012
|
+
// ../shared/dist/provider-accounts.js
|
|
79013
|
+
function modelNames(modelId) {
|
|
79014
|
+
const value = modelId.trim();
|
|
79015
|
+
const names = /* @__PURE__ */ new Set([value]);
|
|
79016
|
+
for (const prefix of HOST_PREFIXES) {
|
|
79017
|
+
if (!value.startsWith(prefix))
|
|
79018
|
+
continue;
|
|
79019
|
+
const bare = value.slice(prefix.length);
|
|
79020
|
+
names.add(bare);
|
|
79021
|
+
const slash = bare.lastIndexOf("/");
|
|
79022
|
+
if (slash >= 0)
|
|
79023
|
+
names.add(bare.slice(slash + 1));
|
|
79024
|
+
}
|
|
79025
|
+
const canonical = canonicalModelId(value);
|
|
79026
|
+
if (canonical) {
|
|
79027
|
+
names.add(canonical);
|
|
79028
|
+
const entry = API_MODEL_CATALOG.find((m) => m.id === canonical || m.apiModel === canonical);
|
|
79029
|
+
if (entry) {
|
|
79030
|
+
names.add(entry.id);
|
|
79031
|
+
if (entry.apiModel)
|
|
79032
|
+
names.add(entry.apiModel);
|
|
79033
|
+
}
|
|
79034
|
+
}
|
|
79035
|
+
return names;
|
|
79036
|
+
}
|
|
79037
|
+
function accountServesModel(models, modelId) {
|
|
79038
|
+
if (!models || models.length === 0)
|
|
79039
|
+
return true;
|
|
79040
|
+
if (!modelId)
|
|
79041
|
+
return false;
|
|
79042
|
+
const names = modelNames(modelId);
|
|
79043
|
+
return models.some((model) => names.has(model.trim()));
|
|
79044
|
+
}
|
|
79045
|
+
function normalizeProviderAccountModels(models) {
|
|
79046
|
+
if (!Array.isArray(models))
|
|
79047
|
+
return null;
|
|
79048
|
+
const out = [];
|
|
79049
|
+
for (const model of models) {
|
|
79050
|
+
if (typeof model !== "string")
|
|
79051
|
+
return null;
|
|
79052
|
+
const trimmed = model.trim();
|
|
79053
|
+
if (!PROVIDER_ACCOUNT_MODEL_PATTERN.test(trimmed) || trimmed.includes(".."))
|
|
79054
|
+
return null;
|
|
79055
|
+
if (!out.includes(trimmed))
|
|
79056
|
+
out.push(trimmed);
|
|
79057
|
+
}
|
|
79058
|
+
return out.length > MAX_PROVIDER_ACCOUNT_MODELS ? null : out;
|
|
79059
|
+
}
|
|
79060
|
+
function parseProviderAccountLists(value, providers) {
|
|
79061
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
79062
|
+
return null;
|
|
79063
|
+
const parsed = {};
|
|
79064
|
+
for (const provider of providers) {
|
|
79065
|
+
const list = value[provider];
|
|
79066
|
+
if (!Array.isArray(list))
|
|
79067
|
+
continue;
|
|
79068
|
+
const accounts = [];
|
|
79069
|
+
for (const raw of list) {
|
|
79070
|
+
if (!raw || typeof raw !== "object")
|
|
79071
|
+
continue;
|
|
79072
|
+
const { id, label, key, models } = raw;
|
|
79073
|
+
if (typeof id !== "string" || !id.trim() || typeof key !== "string" || !key.trim())
|
|
79074
|
+
continue;
|
|
79075
|
+
const modelList = Array.isArray(models) ? models.filter((m) => typeof m === "string" && m.trim() !== "").map((m) => m.trim()) : [];
|
|
79076
|
+
accounts.push({ id: id.trim(), label: typeof label === "string" && label.trim() ? label.trim() : null, key: key.trim(), models: modelList });
|
|
79077
|
+
}
|
|
79078
|
+
if (accounts.length > 0)
|
|
79079
|
+
parsed[provider] = accounts;
|
|
79080
|
+
}
|
|
79081
|
+
return parsed;
|
|
79082
|
+
}
|
|
79083
|
+
var DEFAULT_PROVIDER_ACCOUNT_ID, PROVIDER_ACCOUNT_ID_PATTERN, MAX_PROVIDER_ACCOUNTS, MAX_PROVIDER_ACCOUNT_MODELS, PROVIDER_ACCOUNT_MODEL_PATTERN, OPENCODE_GO_DEEPSEEK_GLM_MODELS, HOST_PREFIXES;
|
|
79084
|
+
var init_provider_accounts = __esm({
|
|
79085
|
+
"../shared/dist/provider-accounts.js"() {
|
|
79086
|
+
"use strict";
|
|
79087
|
+
init_api_model_catalog();
|
|
79088
|
+
DEFAULT_PROVIDER_ACCOUNT_ID = "primary";
|
|
79089
|
+
PROVIDER_ACCOUNT_ID_PATTERN = /^[a-z0-9][a-z0-9-]{0,39}$/;
|
|
79090
|
+
MAX_PROVIDER_ACCOUNTS = 10;
|
|
79091
|
+
MAX_PROVIDER_ACCOUNT_MODELS = 50;
|
|
79092
|
+
PROVIDER_ACCOUNT_MODEL_PATTERN = /^[A-Za-z0-9][A-Za-z0-9._:/-]{0,120}$/;
|
|
79093
|
+
OPENCODE_GO_DEEPSEEK_GLM_MODELS = [
|
|
79094
|
+
"deepseek-v4.1-flash",
|
|
79095
|
+
"deepseek-v4-pro",
|
|
79096
|
+
"glm-5.3-flash",
|
|
79097
|
+
"glm-5.3",
|
|
79098
|
+
"glm-5.2"
|
|
79099
|
+
];
|
|
79100
|
+
HOST_PREFIXES = ["opencode-go:", "zai:", "openrouter:"];
|
|
78318
79101
|
}
|
|
78319
79102
|
});
|
|
78320
79103
|
|
|
@@ -78433,6 +79216,25 @@ var init_project_engine_overrides = __esm({
|
|
|
78433
79216
|
}
|
|
78434
79217
|
});
|
|
78435
79218
|
|
|
79219
|
+
// ../shared/dist/trailing-slashes.js
|
|
79220
|
+
function stripTrailingSlashes(value) {
|
|
79221
|
+
let end = value.length;
|
|
79222
|
+
while (end > 0 && value.charCodeAt(end - 1) === 47)
|
|
79223
|
+
end--;
|
|
79224
|
+
return end === value.length ? value : value.slice(0, end);
|
|
79225
|
+
}
|
|
79226
|
+
function stripTrailingChars(value, isTrailing) {
|
|
79227
|
+
let end = value.length;
|
|
79228
|
+
while (end > 0 && isTrailing.test(value[end - 1]))
|
|
79229
|
+
end--;
|
|
79230
|
+
return end === value.length ? value : value.slice(0, end);
|
|
79231
|
+
}
|
|
79232
|
+
var init_trailing_slashes = __esm({
|
|
79233
|
+
"../shared/dist/trailing-slashes.js"() {
|
|
79234
|
+
"use strict";
|
|
79235
|
+
}
|
|
79236
|
+
});
|
|
79237
|
+
|
|
78436
79238
|
// ../shared/dist/gemini-visual.js
|
|
78437
79239
|
function visualProDailyBudget(raw) {
|
|
78438
79240
|
const parsed = raw && /^\s*\d{1,6}\s*$/.test(raw) ? Number(raw.trim()) : NaN;
|
|
@@ -78446,7 +79248,7 @@ function isRetiredGeminiModel(id) {
|
|
|
78446
79248
|
}
|
|
78447
79249
|
function geminiNativeModelsUrl(base2 = process.env.GEMINI_API_BASE) {
|
|
78448
79250
|
const raw = base2 && base2.trim() || GEMINI_OPENAI_BASE;
|
|
78449
|
-
const native = raw.replace(/\/openai\/?$/, "/")
|
|
79251
|
+
const native = stripTrailingSlashes(raw.replace(/\/openai\/?$/, "/"));
|
|
78450
79252
|
return `${native}/models?pageSize=1000`;
|
|
78451
79253
|
}
|
|
78452
79254
|
function asRecord(value) {
|
|
@@ -78566,6 +79368,7 @@ var KNOWN_INPUT_USD_PER_M, GEMINI_OPENAI_BASE, DEFAULT_GEMINI_SCREEN_MODEL, DEFA
|
|
|
78566
79368
|
var init_gemini_visual = __esm({
|
|
78567
79369
|
"../shared/dist/gemini-visual.js"() {
|
|
78568
79370
|
"use strict";
|
|
79371
|
+
init_trailing_slashes();
|
|
78569
79372
|
KNOWN_INPUT_USD_PER_M = {
|
|
78570
79373
|
"gemini-2.5-flash-lite": 0.1,
|
|
78571
79374
|
"gemini-3.1-flash-lite": 0.25,
|
|
@@ -79929,12 +80732,13 @@ function truncateAtWord(text, max) {
|
|
|
79929
80732
|
const slice = trimmed.slice(0, room + 1);
|
|
79930
80733
|
const lastSpace = slice.lastIndexOf(" ");
|
|
79931
80734
|
const cut = lastSpace > room * 0.5 ? slice.slice(0, lastSpace) : trimmed.slice(0, room);
|
|
79932
|
-
return `${cut
|
|
80735
|
+
return `${stripTrailingChars(cut, TRAILING_PUNCTUATION)}\u2026`;
|
|
79933
80736
|
}
|
|
79934
|
-
var CANVAS_UNSUPPORTED_CODE, CANVAS_UNSUPPORTED_TITLE, CANVAS_UNSUPPORTED_BODY, CANVAS_UNSUPPORTED_NOT_CHARGED, CANVAS_UNSUPPORTED_OVERRIDE_HINT, GAME_ENGINES, RENDERER_ENGINES, ENGINE_TEXT_SIGNATURES, GAME_LIBRARY_TEXT_PATTERNS, ENGINE_PACKAGES, GAME_HINT_PACKAGES, MAX_TAG_CHARS, MAX_CSS_SELECTOR_CHARS, MAX_CSS_BLOCK_CHARS, TAG_NAME_RE, ATTR_RE, INTERACTIVE_TAGS, INTERACTIVE_ROLES, ROOT_SELECTOR_RE, OVERFLOW_HIDDEN_RE, TOUCH_NONE_RE, CODE_TAGS, STATIC_STANDARD_MIN_INTERACTIVE;
|
|
80737
|
+
var CANVAS_UNSUPPORTED_CODE, CANVAS_UNSUPPORTED_TITLE, CANVAS_UNSUPPORTED_BODY, CANVAS_UNSUPPORTED_NOT_CHARGED, CANVAS_UNSUPPORTED_OVERRIDE_HINT, GAME_ENGINES, RENDERER_ENGINES, ENGINE_TEXT_SIGNATURES, GAME_LIBRARY_TEXT_PATTERNS, ENGINE_PACKAGES, GAME_HINT_PACKAGES, MAX_TAG_CHARS, MAX_CSS_SELECTOR_CHARS, MAX_CSS_BLOCK_CHARS, TAG_NAME_RE, ATTR_RE, INTERACTIVE_TAGS, INTERACTIVE_ROLES, ROOT_SELECTOR_RE, OVERFLOW_HIDDEN_RE, TOUCH_NONE_RE, CODE_TAGS, STATIC_STANDARD_MIN_INTERACTIVE, TRAILING_PUNCTUATION;
|
|
79935
80738
|
var init_canvas_support = __esm({
|
|
79936
80739
|
"../shared/dist/canvas-support.js"() {
|
|
79937
80740
|
"use strict";
|
|
80741
|
+
init_trailing_slashes();
|
|
79938
80742
|
CANVAS_UNSUPPORTED_CODE = "canvas_unsupported";
|
|
79939
80743
|
CANVAS_UNSUPPORTED_TITLE = "Games and canvas apps aren't supported yet";
|
|
79940
80744
|
CANVAS_UNSUPPORTED_BODY = "This app draws its screen on a canvas (like a game), so there are no page elements for Validate.QA to read and test. Support for games and canvas apps is coming.";
|
|
@@ -80059,6 +80863,7 @@ var init_canvas_support = __esm({
|
|
|
80059
80863
|
TOUCH_NONE_RE = /touch-action\s{0,8}:\s{0,8}none/;
|
|
80060
80864
|
CODE_TAGS = /* @__PURE__ */ new Set(["script", "link", "flt-glass-pane", "flutter-view", "flt-scene-host"]);
|
|
80061
80865
|
STATIC_STANDARD_MIN_INTERACTIVE = 3;
|
|
80866
|
+
TRAILING_PUNCTUATION = /[\s,;:.\-–—]/u;
|
|
80062
80867
|
}
|
|
80063
80868
|
});
|
|
80064
80869
|
|
|
@@ -80241,22 +81046,22 @@ function joinChainedLines(code) {
|
|
|
80241
81046
|
const trimmed = lines[i].trimStart();
|
|
80242
81047
|
if (last !== -1 && trimmed.startsWith(".") && !trimmed.startsWith("...")) {
|
|
80243
81048
|
if (!lastStripped) {
|
|
80244
|
-
lines[last] =
|
|
81049
|
+
lines[last] = stripLineComment3(lines[last]).trimEnd();
|
|
80245
81050
|
lastStripped = true;
|
|
80246
81051
|
}
|
|
80247
81052
|
if (lines[last].length <= MAX_LINE_CHARS)
|
|
80248
|
-
lines[last] = `${lines[last]} ${
|
|
81053
|
+
lines[last] = `${lines[last]} ${stripLineComment3(trimmed).trimEnd()}`;
|
|
80249
81054
|
lines[i] = "";
|
|
80250
81055
|
continue;
|
|
80251
81056
|
}
|
|
80252
|
-
if (
|
|
81057
|
+
if (stripLineComment3(lines[i]).trim()) {
|
|
80253
81058
|
last = i;
|
|
80254
81059
|
lastStripped = false;
|
|
80255
81060
|
}
|
|
80256
81061
|
}
|
|
80257
81062
|
return lines.join("\n");
|
|
80258
81063
|
}
|
|
80259
|
-
function
|
|
81064
|
+
function stripLineComment3(rawLine) {
|
|
80260
81065
|
if (rawLine.trimStart().startsWith("//"))
|
|
80261
81066
|
return "";
|
|
80262
81067
|
const at = rawLine.indexOf(" // ");
|
|
@@ -80272,7 +81077,7 @@ function stateLiteralsOf(line) {
|
|
|
80272
81077
|
const out = [];
|
|
80273
81078
|
for (const m of line.matchAll(STRING_LITERAL_RE)) {
|
|
80274
81079
|
const text = m[1] ?? m[2] ?? m[3] ?? "";
|
|
80275
|
-
if (
|
|
81080
|
+
if (PLACEHOLDER_ATTR_RE.test(text))
|
|
80276
81081
|
continue;
|
|
80277
81082
|
if (PLACEHOLDER_CALL_TAIL_RE.test(line.slice(Math.max(0, m.index - 40), m.index)))
|
|
80278
81083
|
continue;
|
|
@@ -80305,7 +81110,7 @@ function analyzeReadinessPolling(rawCode) {
|
|
|
80305
81110
|
offset += rawLine.length + 1;
|
|
80306
81111
|
if (rawLine.length > MAX_LINE_CHARS)
|
|
80307
81112
|
continue;
|
|
80308
|
-
const line =
|
|
81113
|
+
const line = stripLineComment3(rawLine);
|
|
80309
81114
|
if (!line.trim())
|
|
80310
81115
|
continue;
|
|
80311
81116
|
const literals = literalsOf(line);
|
|
@@ -80368,7 +81173,7 @@ function formatReadinessPollAdvisory(findings) {
|
|
|
80368
81173
|
const where = findings.length === 1 ? "One place" : `${findings.length} places`;
|
|
80369
81174
|
return `${where} re-check a background state once and assert the finished state at once (${short(first.line, 90)} then ${short(first.assertion, 90)}). ${first.reason}`;
|
|
80370
81175
|
}
|
|
80371
|
-
var READINESS_POLL_MAX_CODE_CHARS, MAX_LINE_CHARS, MAX_FINDINGS, ASSERTION_WINDOW_LINES, MAX_BLOCK_CHARS, MAX_HEAD_CHARS, STRING_LITERAL_RE, RECHECK_NAME_RE, RETRY_NAME_RE, PENDING_STATE_RE, LOCATOR_LINE_RE, CLICK_RE, RELOAD_RE, GOTO_RE, ACTION_RE, EXPECT_RE, NEGATED_RE, PENDING_ENDED_RE, POSITIVE_MATCHER_RE, ZERO_COUNT_RE, TEST_END_RE, TEST_START_RE, POLL_OPEN_RE, PLACEHOLDER_CALL_TAIL_RE, POLL_SHAPE;
|
|
81176
|
+
var READINESS_POLL_MAX_CODE_CHARS, MAX_LINE_CHARS, MAX_FINDINGS, ASSERTION_WINDOW_LINES, MAX_BLOCK_CHARS, MAX_HEAD_CHARS, STRING_LITERAL_RE, RECHECK_NAME_RE, RETRY_NAME_RE, PENDING_STATE_RE, LOCATOR_LINE_RE, CLICK_RE, RELOAD_RE, GOTO_RE, ACTION_RE, EXPECT_RE, NEGATED_RE, PENDING_ENDED_RE, POSITIVE_MATCHER_RE, ZERO_COUNT_RE, TEST_END_RE, TEST_START_RE, POLL_OPEN_RE, PLACEHOLDER_ATTR_RE, PLACEHOLDER_CALL_TAIL_RE, POLL_SHAPE;
|
|
80372
81177
|
var init_readiness_poll = __esm({
|
|
80373
81178
|
"../shared/dist/readiness-poll.js"() {
|
|
80374
81179
|
"use strict";
|
|
@@ -80381,7 +81186,7 @@ var init_readiness_poll = __esm({
|
|
|
80381
81186
|
STRING_LITERAL_RE = /'((?:\\.|[^'\\\n]){0,300})'|"((?:\\.|[^"\\\n]){0,300})"|`((?:\\.|[^`\\\n]){0,300})`/g;
|
|
80382
81187
|
RECHECK_NAME_RE = /^\s{0,10}(?:check again|check (?:status|availability|now|for updates|progress)|re-?check(?: status)?|update status|see (?:latest|updates))\s{0,10}(?:\.\.\.|…)?\s{0,10}$/i;
|
|
80383
81188
|
RETRY_NAME_RE = /^\s{0,10}(?:refresh(?: (?:status|list|page|results|now))?|reload(?: (?:page|results|list))?|try again|retry|load (?:again|latest))\s{0,10}(?:\.\.\.|…)?\s{0,10}$/i;
|
|
80384
|
-
PENDING_STATE_RE = /\b(?:searching|checking|sending|pending|processing|queued|in progress|loading|generating|calculating|preparing|verifying|syncing|refreshing|not ready|please wait|waiting)\b|\b[a-z]{3,
|
|
81189
|
+
PENDING_STATE_RE = /\b(?:searching|checking|sending|pending|processing|queued|in progress|loading|generating|calculating|preparing|verifying|syncing|refreshing|not ready|please wait|waiting)\b|\b(?:saving|uploading|downloading|signing|logging|submitting|creating|updating|deleting|importing|exporting|publishing|connecting|redirecting|authenticating|installing|retrieving|fetching|analy[sz]ing|running|rendering|restarting|building|compiling|booting|provisioning|deploying|indexing|migrating|launching|initiali[sz]ing|optimi[sz]ing|converting|processing)(?:\s{1,3}[a-z]{1,20}){0,2}\s{0,3}(?:\.\.\.|…)\s{0,10}$|^\s{0,10}(?:starting|scanning|working|applying|finishing)(?:\s{1,3}[a-z]{1,20}){0,2}\s{0,3}(?:\.\.\.|…)\s{0,10}$|^\s{0,10}[a-z]{3,40}(?<!th)ing\s{0,3}(?:\.\.\.|…)\s{0,10}$/i;
|
|
80385
81190
|
LOCATOR_LINE_RE = /\.(?:getBy[A-Z]\w{0,30}|locator|toHaveText|toContainText)\s{0,20}\(/;
|
|
80386
81191
|
CLICK_RE = /\.(?:click|dblclick|tap)\s{0,20}\(/;
|
|
80387
81192
|
RELOAD_RE = /\bpage\.reload\s{0,20}\(/;
|
|
@@ -80395,6 +81200,7 @@ var init_readiness_poll = __esm({
|
|
|
80395
81200
|
TEST_END_RE = /^\s{0,20}\}\s{0,20}\)\s{0,20};?\s{0,20}$/;
|
|
80396
81201
|
TEST_START_RE = /\btest(?:\.\w{1,20})?\s{0,20}\(/;
|
|
80397
81202
|
POLL_OPEN_RE = /\bexpect(?:\.soft)?\s{0,20}\(\s{0,20}async\b|\bexpect\.poll\s{0,20}\(|\bfor\s{0,20}\(|\bwhile\s{0,20}\(|\bdo\s{0,20}\{/g;
|
|
81203
|
+
PLACEHOLDER_ATTR_RE = /placeholder\s{0,4}[*^$~|]?=/;
|
|
80398
81204
|
PLACEHOLDER_CALL_TAIL_RE = /getByPlaceholder\s{0,20}\(\s{0,20}$/;
|
|
80399
81205
|
POLL_SHAPE = "await expect(async () => { await page.reload(); await expect(<the finished state>).toBeVisible({ timeout: 1500 }); }).toPass({ timeout: 20000 });";
|
|
80400
81206
|
}
|
|
@@ -80416,7 +81222,7 @@ function blankBlockComments2(code) {
|
|
|
80416
81222
|
from = close + 2;
|
|
80417
81223
|
}
|
|
80418
81224
|
}
|
|
80419
|
-
function
|
|
81225
|
+
function stripLineComment4(rawLine) {
|
|
80420
81226
|
if (rawLine.trimStart().startsWith("//"))
|
|
80421
81227
|
return "";
|
|
80422
81228
|
const at = rawLine.indexOf(" // ");
|
|
@@ -80427,7 +81233,7 @@ function logicalLines(code) {
|
|
|
80427
81233
|
for (const raw of code.split("\n")) {
|
|
80428
81234
|
if (raw.length > MAX_LINE_CHARS2)
|
|
80429
81235
|
continue;
|
|
80430
|
-
const line =
|
|
81236
|
+
const line = stripLineComment4(raw).trimEnd();
|
|
80431
81237
|
if (!line.trim())
|
|
80432
81238
|
continue;
|
|
80433
81239
|
const trimmed = line.trimStart();
|
|
@@ -80789,13 +81595,33 @@ function short4(text, max) {
|
|
|
80789
81595
|
const flat = text.replace(/\s+/g, " ").trim();
|
|
80790
81596
|
return flat.length > max ? `${flat.slice(0, max - 1)}\u2026` : flat;
|
|
80791
81597
|
}
|
|
81598
|
+
function stripFractionZeros(s) {
|
|
81599
|
+
let end = s.length;
|
|
81600
|
+
while (end > 0 && s[end - 1] === "0")
|
|
81601
|
+
end--;
|
|
81602
|
+
if (end === s.length)
|
|
81603
|
+
return s;
|
|
81604
|
+
const dot = s.lastIndexOf(".");
|
|
81605
|
+
if (dot < 0)
|
|
81606
|
+
return s;
|
|
81607
|
+
return s.slice(0, end === dot + 1 ? dot : end);
|
|
81608
|
+
}
|
|
80792
81609
|
function digitsOf(token) {
|
|
80793
|
-
return token.replace(/[^\d.]/g, "")
|
|
81610
|
+
return stripFractionZeros(token.replace(/[^\d.]/g, "")).replace(/^0+(?=\d)/, "");
|
|
80794
81611
|
}
|
|
80795
81612
|
function computes(line) {
|
|
80796
81613
|
const code = line.replace(STRING_RE, '""').replace(REGEX_LITERAL_RE, "$1RX").replace(LITERAL_ARITH_RE, "N");
|
|
80797
81614
|
return COMPUTE_RE.test(code) || RELATIONAL_RE.test(line);
|
|
80798
81615
|
}
|
|
81616
|
+
function identifiersIn(line) {
|
|
81617
|
+
const code = line.replace(STRING_RE, '""').replace(REGEX_LITERAL_RE, "$1RX");
|
|
81618
|
+
return [code, ...[...line.matchAll(TEMPLATE_EXPR_RE)].map((m) => m[1])].flatMap((part) => part.match(IDENTIFIER_RE) ?? []);
|
|
81619
|
+
}
|
|
81620
|
+
function addTyped(typed, value) {
|
|
81621
|
+
const d = digitsOf(value);
|
|
81622
|
+
if (/\d/.test(d))
|
|
81623
|
+
typed.add(d);
|
|
81624
|
+
}
|
|
80799
81625
|
function reasonFor4(kind, label, value) {
|
|
80800
81626
|
const what = kind === "derived-value-shape-only" ? `The ${label} is checked only for its shape, so any amount passes, including a wrongly computed one.` : `The ${label} is checked against a number written into the test (${value}). That number was read off the page, so when the page computes it wrong the check still passes.`;
|
|
80801
81627
|
return `${what} Instead, ${COMPUTE_SHAPE} If the number is not computed from other values (a list price, an id, a fixed fee), leave it as it is. Keep the existing checks.`;
|
|
@@ -80807,25 +81633,32 @@ function analyzeDerivedValues(rawCode) {
|
|
|
80807
81633
|
for (const body of testBodies(rawCode)) {
|
|
80808
81634
|
if (findings.length >= MAX_FINDINGS4)
|
|
80809
81635
|
break;
|
|
80810
|
-
if (body.some(computes))
|
|
80811
|
-
continue;
|
|
80812
81636
|
const typed = /* @__PURE__ */ new Set();
|
|
80813
81637
|
const definitions = /* @__PURE__ */ new Map();
|
|
81638
|
+
const computed = /* @__PURE__ */ new Set();
|
|
81639
|
+
const usesComputed = (text) => identifiersIn(text).some((id) => computed.has(id));
|
|
80814
81640
|
for (const line of body) {
|
|
80815
81641
|
if (FILL_RE2.test(line) && !EXPECT_RE3.test(line)) {
|
|
80816
|
-
for (const m of line.matchAll(
|
|
80817
|
-
|
|
80818
|
-
|
|
80819
|
-
|
|
80820
|
-
|
|
81642
|
+
for (const m of line.matchAll(QUOTED_RE))
|
|
81643
|
+
addTyped(typed, m[1]);
|
|
81644
|
+
const arg = FILL_ARG_RE.exec(line)?.[1];
|
|
81645
|
+
const literal = arg === void 0 ? null : LITERAL_VALUE_RE.exec(definitions.get(arg) ?? "");
|
|
81646
|
+
const value = literal?.slice(1).find((v) => v !== void 0);
|
|
81647
|
+
if (value !== void 0)
|
|
81648
|
+
addTyped(typed, value);
|
|
80821
81649
|
}
|
|
80822
81650
|
const def = DEFINITION_RE.exec(line);
|
|
80823
|
-
if (def)
|
|
81651
|
+
if (def) {
|
|
80824
81652
|
definitions.set(def[1], def[2]);
|
|
81653
|
+
if (computes(def[2]) || usesComputed(def[2]))
|
|
81654
|
+
computed.add(def[1]);
|
|
81655
|
+
}
|
|
80825
81656
|
}
|
|
80826
81657
|
for (const line of body) {
|
|
80827
81658
|
if (!EXPECT_RE3.test(line) || !VALUE_MATCHER_RE2.test(line) || /\.not\s{0,20}\./.test(line))
|
|
80828
81659
|
continue;
|
|
81660
|
+
if (computes(line) || usesComputed(line))
|
|
81661
|
+
continue;
|
|
80829
81662
|
const subject = EXPECT_SUBJECT_RE.exec(line)?.[1];
|
|
80830
81663
|
const label = DERIVED_WORD_RE.exec(`${line} ${(subject && definitions.get(subject)) ?? ""}`)?.[0];
|
|
80831
81664
|
if (!label)
|
|
@@ -80855,7 +81688,7 @@ function formatDerivedValueAdvisory(findings) {
|
|
|
80855
81688
|
const where = findings.length === 1 ? "One computed value is" : `${findings.length} computed values are`;
|
|
80856
81689
|
return `${where} checked against a copied number or only its shape (${short4(first.line, 90)}). ${first.reason}`;
|
|
80857
81690
|
}
|
|
80858
|
-
var MAX_FINDINGS4, EXPECT_RE3, DERIVED_WORD_RE, VALUE_MATCHER_RE2, MONEY_TOKEN_RE, SHAPE_ARG_RE, FILL_RE2, EXPECT_MESSAGE_RE, STRING_RE, REGEX_LITERAL_RE, COMPUTE_RE, RELATIONAL_RE, DEFINITION_RE, EXPECT_SUBJECT_RE, LITERAL_ARITH_RE, COMPUTE_SHAPE;
|
|
81691
|
+
var MAX_FINDINGS4, EXPECT_RE3, DERIVED_WORD_RE, VALUE_MATCHER_RE2, MONEY_TOKEN_RE, SHAPE_ARG_RE, FILL_RE2, EXPECT_MESSAGE_RE, STRING_RE, REGEX_LITERAL_RE, COMPUTE_RE, RELATIONAL_RE, DEFINITION_RE, EXPECT_SUBJECT_RE, LITERAL_ARITH_RE, TEMPLATE_EXPR_RE, IDENTIFIER_RE, QUOTED_RE, FILL_ARG_RE, LITERAL_VALUE_RE, COMPUTE_SHAPE;
|
|
80859
81692
|
var init_derived_value_check = __esm({
|
|
80860
81693
|
"../shared/dist/derived-value-check.js"() {
|
|
80861
81694
|
"use strict";
|
|
@@ -80875,6 +81708,11 @@ var init_derived_value_check = __esm({
|
|
|
80875
81708
|
DEFINITION_RE = /\b(?:const|let)\s{1,10}([\w$]{1,60})\s{0,10}=\s{0,10}([^\n]{0,300})/;
|
|
80876
81709
|
EXPECT_SUBJECT_RE = /\bexpect(?:\.soft)?\s{0,20}\(\s{0,20}([\w$]{1,60})/;
|
|
80877
81710
|
LITERAL_ARITH_RE = /\b\d[\d_.]{0,15}(?:\s{0,5}[*/+-]\s{0,5}\d[\d_.]{0,15}){1,8}\b/g;
|
|
81711
|
+
TEMPLATE_EXPR_RE = /\$\{([^{}\n]{0,200})\}/g;
|
|
81712
|
+
IDENTIFIER_RE = /[A-Za-z_$][\w$]{0,60}/g;
|
|
81713
|
+
QUOTED_RE = /['"`]([^'"`\n]{0,40})['"`]/g;
|
|
81714
|
+
FILL_ARG_RE = /\.(?:fill|type|pressSequentially|selectOption)\s{0,20}\(\s{0,20}([A-Za-z_$][\w$]{0,60})\s{0,20}[,)]/;
|
|
81715
|
+
LITERAL_VALUE_RE = /^\s{0,10}(?:'([^'\n]{0,40})'|"([^"\n]{0,40})"|`([^`$\n]{0,40})`|(\d[\d_,]{0,15}(?:\.\d{1,4})?))\s{0,10};?\s{0,10}$/;
|
|
80878
81716
|
COMPUTE_SHAPE = "compute the expected value in the test from its inputs (the values the test typed, or each input read from the page) and compare: const toNumber = (s) => Number(s.replace(/[^\\d.-]/g, '')); const unit = toNumber(await <unit price locator>.innerText()); then expect(toNumber(await <shown value locator>.innerText())).toBeCloseTo(unit * quantity, 2); for several lines, read them all and sum them with reduce. For a comma-decimal price like \u20AC1.234,56, drop the dots and turn the comma into a point before Number, since the replace above would read it as 1.23456.";
|
|
80879
81717
|
}
|
|
80880
81718
|
});
|
|
@@ -80987,7 +81825,7 @@ function findExpectCalls(code) {
|
|
|
80987
81825
|
if (!subj)
|
|
80988
81826
|
continue;
|
|
80989
81827
|
const rest = code.slice(subj.end + 1, subj.end + 1 + 80);
|
|
80990
|
-
const mm = /^\s*((?:\.\s*not)
|
|
81828
|
+
const mm = /^\s*((?:\.\s*not\s*)?\.\s*(\w+))\s{0,20}\(/.exec(rest);
|
|
80991
81829
|
if (!mm)
|
|
80992
81830
|
continue;
|
|
80993
81831
|
const argStart = subj.end + 1 + mm[0].length;
|
|
@@ -82909,6 +83747,133 @@ function formatStaleAfterSubmitAdvisory(rawCode) {
|
|
|
82909
83747
|
const more = described.length > 3 ? ` (+${described.length - 3} more)` : "";
|
|
82910
83748
|
return `stale-after-submit: ${described.slice(0, 3).join("; ")}${more}; these pass before the request lands and still pass if the server rejects or ignores the save. Wait for the result instead: page.waitForResponse around the click, or assert something the submit creates (the new row, the confirmation message, a path with an end anchor such as /\\/orders\\/\\d+$/)`;
|
|
82911
83749
|
}
|
|
83750
|
+
function regexLiteralEnd4(text, at) {
|
|
83751
|
+
let inClass = false;
|
|
83752
|
+
for (let i = at + 1; i < text.length; i++) {
|
|
83753
|
+
const ch = text[i];
|
|
83754
|
+
if (ch === "\n")
|
|
83755
|
+
return -1;
|
|
83756
|
+
if (ch === "\\") {
|
|
83757
|
+
i++;
|
|
83758
|
+
continue;
|
|
83759
|
+
}
|
|
83760
|
+
if (inClass) {
|
|
83761
|
+
if (ch === "]")
|
|
83762
|
+
inClass = false;
|
|
83763
|
+
continue;
|
|
83764
|
+
}
|
|
83765
|
+
if (ch === "[") {
|
|
83766
|
+
inClass = true;
|
|
83767
|
+
continue;
|
|
83768
|
+
}
|
|
83769
|
+
if (ch === "/")
|
|
83770
|
+
return i + 1;
|
|
83771
|
+
}
|
|
83772
|
+
return -1;
|
|
83773
|
+
}
|
|
83774
|
+
function startsWithRegexLiteral(text) {
|
|
83775
|
+
const t = text.trimStart();
|
|
83776
|
+
return t[0] === "/" && t[1] !== "/" && t[1] !== "*" && regexLiteralEnd4(t, 0) !== -1;
|
|
83777
|
+
}
|
|
83778
|
+
function isBareRegexLiteral(text) {
|
|
83779
|
+
const t = text.trimStart();
|
|
83780
|
+
if (t[0] !== "/" || t[1] === "/" || t[1] === "*")
|
|
83781
|
+
return false;
|
|
83782
|
+
const end = regexLiteralEnd4(t, 0);
|
|
83783
|
+
if (end === -1)
|
|
83784
|
+
return false;
|
|
83785
|
+
let i = end;
|
|
83786
|
+
while (i < t.length && /[a-z]/.test(t[i]))
|
|
83787
|
+
i++;
|
|
83788
|
+
while (i < t.length && /\s/.test(t[i]))
|
|
83789
|
+
i++;
|
|
83790
|
+
return i >= t.length || t[i] === ",";
|
|
83791
|
+
}
|
|
83792
|
+
function regexDeclaredNames(code) {
|
|
83793
|
+
const names = /* @__PURE__ */ new Set();
|
|
83794
|
+
const decl = /\b(?:const|let|var)\s{1,20}([A-Za-z_$][\w$]{0,80})\s{0,20}=\s{0,20}(?:\/(?![/*])|new\s{1,20}RegExp\b)/g;
|
|
83795
|
+
let m;
|
|
83796
|
+
while ((m = decl.exec(code)) !== null)
|
|
83797
|
+
names.add(m[1]);
|
|
83798
|
+
return names;
|
|
83799
|
+
}
|
|
83800
|
+
function afterFirstArg(args) {
|
|
83801
|
+
let depth = 0;
|
|
83802
|
+
let quote = null;
|
|
83803
|
+
for (let i = 0; i < args.length; i++) {
|
|
83804
|
+
const ch = args[i];
|
|
83805
|
+
if (quote) {
|
|
83806
|
+
if (ch === "\\") {
|
|
83807
|
+
i++;
|
|
83808
|
+
continue;
|
|
83809
|
+
}
|
|
83810
|
+
if (ch === quote)
|
|
83811
|
+
quote = null;
|
|
83812
|
+
continue;
|
|
83813
|
+
}
|
|
83814
|
+
if (ch === '"' || ch === "'" || ch === "`") {
|
|
83815
|
+
quote = ch;
|
|
83816
|
+
continue;
|
|
83817
|
+
}
|
|
83818
|
+
if (ch === "(" || ch === "[" || ch === "{")
|
|
83819
|
+
depth++;
|
|
83820
|
+
else if (ch === ")" || ch === "]" || ch === "}")
|
|
83821
|
+
depth--;
|
|
83822
|
+
else if (ch === "," && depth === 0)
|
|
83823
|
+
return args.slice(i + 1);
|
|
83824
|
+
}
|
|
83825
|
+
return "";
|
|
83826
|
+
}
|
|
83827
|
+
function analyzeRegexMatchers(rawCode) {
|
|
83828
|
+
if (!rawCode || typeof rawCode !== "string")
|
|
83829
|
+
return [];
|
|
83830
|
+
const code = stripComments2(rawCode.slice(0, MAX_LINT_INPUT));
|
|
83831
|
+
const out = [];
|
|
83832
|
+
const re = /\bexpect(?:\.soft)?\s{0,20}\(/g;
|
|
83833
|
+
let m;
|
|
83834
|
+
let examined = 0;
|
|
83835
|
+
let line = 1;
|
|
83836
|
+
let lineAt2 = 0;
|
|
83837
|
+
let regexNames;
|
|
83838
|
+
while ((m = re.exec(code)) !== null && examined++ < MAX_CALLS && out.length < MAX_REGEX_MATCHER_FINDINGS) {
|
|
83839
|
+
const subj = readBalanced(code, m.index + m[0].length);
|
|
83840
|
+
if (!subj)
|
|
83841
|
+
continue;
|
|
83842
|
+
const mm = /^\s{0,20}(\.\s{0,20}not)?\s{0,20}\.\s{0,20}(\w{1,40})\s{0,20}\(/.exec(code.slice(subj.end + 1, subj.end + 1 + 80));
|
|
83843
|
+
if (!mm || !REGEX_EQUALITY_MATCHERS.has(mm[2]))
|
|
83844
|
+
continue;
|
|
83845
|
+
const args = readBalanced(code, subj.end + 1 + mm[0].length);
|
|
83846
|
+
if (!args)
|
|
83847
|
+
continue;
|
|
83848
|
+
const expected = mm[2] === "toHaveJSProperty" ? afterFirstArg(args.text) : args.text;
|
|
83849
|
+
if (!isBareRegexLiteral(expected))
|
|
83850
|
+
continue;
|
|
83851
|
+
if (mm[2] !== "toHaveJSProperty" && mm[2] !== "toContain") {
|
|
83852
|
+
const subject = subj.text.trim();
|
|
83853
|
+
if (startsWithRegexLiteral(subject) || /^new\s+RegExp\b/.test(subject))
|
|
83854
|
+
continue;
|
|
83855
|
+
if (/^[A-Za-z_$][\w$]{0,80}$/.test(subject)) {
|
|
83856
|
+
regexNames ??= regexDeclaredNames(code);
|
|
83857
|
+
if (regexNames.has(subject))
|
|
83858
|
+
continue;
|
|
83859
|
+
}
|
|
83860
|
+
}
|
|
83861
|
+
for (let i = code.indexOf("\n", lineAt2); i !== -1 && i < m.index; i = code.indexOf("\n", i + 1)) {
|
|
83862
|
+
line++;
|
|
83863
|
+
lineAt2 = i + 1;
|
|
83864
|
+
}
|
|
83865
|
+
out.push({ line, matcher: mm[2], negated: mm[1] !== void 0 });
|
|
83866
|
+
}
|
|
83867
|
+
return out;
|
|
83868
|
+
}
|
|
83869
|
+
function formatRegexMatcherNote(findings) {
|
|
83870
|
+
const lines = findings.map((f) => {
|
|
83871
|
+
const negated = f.matcher === "toContain" ? "throws on a string and otherwise always passes (a regex never equals an item), so it checks nothing" : "always passes (a regex never equals the value), so it checks nothing";
|
|
83872
|
+
return `Line ${f.line}: .${f.negated ? "not." : ""}${f.matcher}(\u2026 /regex/ \u2026) ${f.negated ? negated : "can never pass: this matcher compares by equality and a regex never equals a value"}.`;
|
|
83873
|
+
});
|
|
83874
|
+
return `${lines.join("\n")}
|
|
83875
|
+
A regex only works in toMatch, toHaveText, toContainText, toHaveValue and similar text matchers. For the \`value\` of an input, textarea or select, use await expect(loc).toHaveValue(/re/). For any other DOM property (or element), poll it so the check still retries: await expect.poll(() => loc.evaluate((n) => n.<prop>)).toMatch(/re/). Never read it once with expect(await loc.evaluate(\u2026)), which sees the value before the page updates it. Or give toHaveJSProperty the exact string (or boolean) the page shows. Keep every other line as-is.`;
|
|
83876
|
+
}
|
|
82912
83877
|
function lintTestQuality(rawCode, opts = {}) {
|
|
82913
83878
|
if (!rawCode || typeof rawCode !== "string")
|
|
82914
83879
|
return [];
|
|
@@ -82916,6 +83881,10 @@ function lintTestQuality(rawCode, opts = {}) {
|
|
|
82916
83881
|
return lintTestData(rawCode, { pageContacts: opts.pageContacts });
|
|
82917
83882
|
if (opts.only === "test-data-blocking")
|
|
82918
83883
|
return analyzeTestData(rawCode, { pageContacts: opts.pageContacts }).blocking;
|
|
83884
|
+
if (opts.only === "regex-matcher") {
|
|
83885
|
+
const found = analyzeRegexMatchers(rawCode);
|
|
83886
|
+
return found.length > 0 ? [formatRegexMatcherNote(found)] : [];
|
|
83887
|
+
}
|
|
82919
83888
|
const warnings = [];
|
|
82920
83889
|
if (rawCode.length > MAX_LINT_INPUT) {
|
|
82921
83890
|
warnings.push(`The code is ${Math.round(rawCode.length / 1024)} KB; the quality lint checked only the first ${MAX_LINT_INPUT / 1e3} KB. Split it into smaller tests (one behaviour per test).`);
|
|
@@ -83190,7 +84159,7 @@ function specItemsFromTestPlans(testPlans) {
|
|
|
83190
84159
|
}
|
|
83191
84160
|
return [...new Set(out)].slice(0, 200);
|
|
83192
84161
|
}
|
|
83193
|
-
var READ_ONLY_TAGS, PRODUCTION_READ_ONLY_GUARD_TEMPLATE, HOST_AGNOSTIC_URL_TEMPLATE, TEST_QUALITY_CONVENTIONS, NON_PROD_HOST_LABEL, NON_PROD_HOST_TOKEN, TRANSIENT_TEXT, STRING_LITERAL, FIRST_LITERAL, GET_BY_TEXT_LITERAL2, ROLE_NAME_LITERAL2, MAX_LINT_INPUT, MAX_BALANCED_SCAN, MAX_CALLS, MAX_SEEN_SCAN, ACTION_CALL, BY_NAME_LOCATOR, ACTION_AFTER, MAX_CONTACTS, MAX_SNAPSHOT_SCAN, PHONE_IN_TEXT, EMAIL_IN_TEXT, TEL_HREF, MAILTO_HREF, FIELD_LINE, INBOX_EMAIL_READ, MAIL_READ_CALL, RESERVED_EMAIL_TLD, PHONE_LABEL, NON_PHONE_NUMBER_LABEL, IDENTITY_LABEL, LOOKUP_LABEL, NON_NAME_SUFFIX_LABEL, DATE_LIKE, SIGNUP_ACTION_NAME, SIGNUP_SUBMIT_NAME, LOGIN_ACTION_NAME, SIGNUP_GOTO, LOGIN_GOTO, MINTED_INBOX_ALIAS, STAMP_EVAL, RECORDING_VALUE_PLACEHOLDERS, NEGATIVE_TEST_TITLE, NEGATIVE_SIGNUP_ASSERT, STORED_LOGIN_RE, CONFIRM_CLICK_RE, SAVE_UPDATE_RE, NOT_A_CONFIRM_RE, ENTITY_WORDS, CREATE_ENTITY_CLICK_RE, RESTORE_CLICK_RE, MAX_ACCOUNT_ACTIONS, MAX_TRY_BLOCKS, MAX_STATEMENT_LOOKBACK, MAX_FINDINGS5, MAX_TRY_BODY, AUTH_REGION_START, AUTH_REGION_END, INBOX_REGION_START, INBOX_REGION_END, ACCOUNT_ROUTE_RE, ENTITY_WORD_RES, PERSIST_CALL_RE, FILL_IDENT_ARG_RE, PERSIST_ARGS_RE, HOST_IN_URL_ARG, URL_WAIT_TOKEN, GLOB_ESCAPED, URL_WAIT_MAX_PATH, URL_WAIT_MAX_GLOB_STARS, UNREACHED_MAX_PATHS, UNREACHED_MATCH_BUDGET, STALE_TOKEN, RESULT_WAIT, WRITE_CALL_PRESENT, SUBMIT_CALL_PRESENT, TEST_CALL, VALUE_WRITE_CALLS, SUBMIT_CALLS, DISTINCT_PAGE_CALLS, OWN_CONTROL_MATCHERS, OUTCOME_CONTENT_MATCHERS, OUTCOME_STATE_MATCHERS, ANY_CONTENT_ARG, ROOT_SUBJECT, LITERAL_SUBJECT, MATCHER_AFTER_EXPECT, STALE_MAX_EVENTS, CHECKED, UNCHECKED, squash, NOT_JUDGED, STALE_REASON_TEXT, LIVE_WRITE_NAME, BUNDLED_CHECKS_BEFORE_WRITE, STOP, SYNONYMS, AREA_TOKENS;
|
|
84162
|
+
var READ_ONLY_TAGS, PRODUCTION_READ_ONLY_GUARD_TEMPLATE, HOST_AGNOSTIC_URL_TEMPLATE, TEST_QUALITY_CONVENTIONS, NON_PROD_HOST_LABEL, NON_PROD_HOST_TOKEN, TRANSIENT_TEXT, STRING_LITERAL, FIRST_LITERAL, GET_BY_TEXT_LITERAL2, ROLE_NAME_LITERAL2, MAX_LINT_INPUT, MAX_BALANCED_SCAN, MAX_CALLS, MAX_SEEN_SCAN, ACTION_CALL, BY_NAME_LOCATOR, ACTION_AFTER, MAX_CONTACTS, MAX_SNAPSHOT_SCAN, PHONE_IN_TEXT, EMAIL_IN_TEXT, TEL_HREF, MAILTO_HREF, FIELD_LINE, INBOX_EMAIL_READ, MAIL_READ_CALL, RESERVED_EMAIL_TLD, PHONE_LABEL, NON_PHONE_NUMBER_LABEL, IDENTITY_LABEL, LOOKUP_LABEL, NON_NAME_SUFFIX_LABEL, DATE_LIKE, SIGNUP_ACTION_NAME, SIGNUP_SUBMIT_NAME, LOGIN_ACTION_NAME, SIGNUP_GOTO, LOGIN_GOTO, MINTED_INBOX_ALIAS, STAMP_EVAL, RECORDING_VALUE_PLACEHOLDERS, NEGATIVE_TEST_TITLE, NEGATIVE_SIGNUP_ASSERT, STORED_LOGIN_RE, CONFIRM_CLICK_RE, SAVE_UPDATE_RE, NOT_A_CONFIRM_RE, ENTITY_WORDS, CREATE_ENTITY_CLICK_RE, RESTORE_CLICK_RE, MAX_ACCOUNT_ACTIONS, MAX_TRY_BLOCKS, MAX_STATEMENT_LOOKBACK, MAX_FINDINGS5, MAX_TRY_BODY, AUTH_REGION_START, AUTH_REGION_END, INBOX_REGION_START, INBOX_REGION_END, ACCOUNT_ROUTE_RE, ENTITY_WORD_RES, PERSIST_CALL_RE, FILL_IDENT_ARG_RE, PERSIST_ARGS_RE, HOST_IN_URL_ARG, URL_WAIT_TOKEN, GLOB_ESCAPED, URL_WAIT_MAX_PATH, URL_WAIT_MAX_GLOB_STARS, UNREACHED_MAX_PATHS, UNREACHED_MATCH_BUDGET, STALE_TOKEN, RESULT_WAIT, WRITE_CALL_PRESENT, SUBMIT_CALL_PRESENT, TEST_CALL, VALUE_WRITE_CALLS, SUBMIT_CALLS, DISTINCT_PAGE_CALLS, OWN_CONTROL_MATCHERS, OUTCOME_CONTENT_MATCHERS, OUTCOME_STATE_MATCHERS, ANY_CONTENT_ARG, ROOT_SUBJECT, LITERAL_SUBJECT, MATCHER_AFTER_EXPECT, STALE_MAX_EVENTS, CHECKED, UNCHECKED, squash, NOT_JUDGED, STALE_REASON_TEXT, LIVE_WRITE_NAME, BUNDLED_CHECKS_BEFORE_WRITE, MAX_REGEX_MATCHER_FINDINGS, REGEX_EQUALITY_MATCHERS, STOP, SYNONYMS, AREA_TOKENS;
|
|
83194
84163
|
var init_test_authoring_quality = __esm({
|
|
83195
84164
|
"../shared/dist/test-authoring-quality.js"() {
|
|
83196
84165
|
"use strict";
|
|
@@ -83422,6 +84391,8 @@ var init_test_authoring_quality = __esm({
|
|
|
83422
84391
|
};
|
|
83423
84392
|
LIVE_WRITE_NAME = /\b(?:submit|place|book|reserve|confirm|pay|send|checkout|order|register|sign\s?up|create account)\b/i;
|
|
83424
84393
|
BUNDLED_CHECKS_BEFORE_WRITE = 5;
|
|
84394
|
+
MAX_REGEX_MATCHER_FINDINGS = 10;
|
|
84395
|
+
REGEX_EQUALITY_MATCHERS = /* @__PURE__ */ new Set(["toBe", "toEqual", "toStrictEqual", "toContain", "toHaveJSProperty"]);
|
|
83425
84396
|
STOP = /* @__PURE__ */ new Set([
|
|
83426
84397
|
"a",
|
|
83427
84398
|
"an",
|
|
@@ -83660,7 +84631,7 @@ function normalizeBugPath(route) {
|
|
|
83660
84631
|
if (hash >= 0 && path[hash + 1] !== "/")
|
|
83661
84632
|
path = path.slice(0, hash);
|
|
83662
84633
|
const segments = path.toLowerCase().split("/").map((segment) => /\d/.test(segment) ? ":id" : segment);
|
|
83663
|
-
const joined = segments.join("/")
|
|
84634
|
+
const joined = stripTrailingSlashes(segments.join("/"));
|
|
83664
84635
|
return joined || (path.startsWith("/") ? "/" : "");
|
|
83665
84636
|
}
|
|
83666
84637
|
function isGenericConsoleMessage(message) {
|
|
@@ -83673,14 +84644,17 @@ function requestSignatures(text) {
|
|
|
83673
84644
|
const statuses = [...text.matchAll(HTTP_STATUS)].map((m) => ({ status: m[1], at: m.index ?? 0, end: (m.index ?? 0) + m[0].length }));
|
|
83674
84645
|
if (statuses.length === 0)
|
|
83675
84646
|
return [];
|
|
83676
|
-
const paths = [...text.matchAll(PATH_IN_TEXT)].map((m) =>
|
|
83677
|
-
|
|
83678
|
-
|
|
83679
|
-
|
|
83680
|
-
|
|
83681
|
-
|
|
83682
|
-
|
|
83683
|
-
|
|
84647
|
+
const paths = [...text.matchAll(PATH_IN_TEXT)].map((m) => {
|
|
84648
|
+
const rawPath = stripTrailingChars(m[2] ?? m[3] ?? "", PATH_TRAILING_PUNCTUATION);
|
|
84649
|
+
return {
|
|
84650
|
+
method: m[1] ?? null,
|
|
84651
|
+
path: normalizeBugPath(rawPath),
|
|
84652
|
+
// Before normalisation, which turns a segment with a digit (favicon-32x32.png) into :id.
|
|
84653
|
+
incidental: isIncidentalAssetPath(rawPath.split(/[?#]/, 1)[0].toLowerCase()),
|
|
84654
|
+
at: m.index ?? 0,
|
|
84655
|
+
end: (m.index ?? 0) + m[0].length
|
|
84656
|
+
};
|
|
84657
|
+
}).filter((p) => p.path.length > 1);
|
|
83684
84658
|
const out = /* @__PURE__ */ new Map();
|
|
83685
84659
|
for (const { status, at, end } of statuses) {
|
|
83686
84660
|
const lead = STATUS_TO_PATH.exec(text.slice(end, end + 40));
|
|
@@ -83790,10 +84764,12 @@ function dedupeSiteWideSuspectedBugs(drafts) {
|
|
|
83790
84764
|
delete plans.suspectedBugs;
|
|
83791
84765
|
}
|
|
83792
84766
|
}
|
|
83793
|
-
var SIGNATURE_SOURCE_MAX_CHARS, UUID, PREFIXED_ID, HEX_RUN, NUMBER_RUN, GENERIC_JS_MESSAGES, GENERIC_JS_PREFIXES, JS_ERROR, MESSAGE_CLAUSE_END, HTTP_STATUS, PATH_IN_TEXT, STATUS_TO_PATH, INCIDENTAL_ASSET;
|
|
84767
|
+
var PATH_TRAILING_PUNCTUATION, SIGNATURE_SOURCE_MAX_CHARS, UUID, PREFIXED_ID, HEX_RUN, NUMBER_RUN, GENERIC_JS_MESSAGES, GENERIC_JS_PREFIXES, JS_ERROR, MESSAGE_CLAUSE_END, HTTP_STATUS, PATH_IN_TEXT, STATUS_TO_PATH, INCIDENTAL_ASSET;
|
|
83794
84768
|
var init_survey_bug_signature = __esm({
|
|
83795
84769
|
"../shared/dist/survey-bug-signature.js"() {
|
|
83796
84770
|
"use strict";
|
|
84771
|
+
init_trailing_slashes();
|
|
84772
|
+
PATH_TRAILING_PUNCTUATION = /[.,;:]/;
|
|
83797
84773
|
SIGNATURE_SOURCE_MAX_CHARS = 800;
|
|
83798
84774
|
UUID = /\b[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\b/g;
|
|
83799
84775
|
PREFIXED_ID = /\b[a-z]{1,8}[-_]\d+\b/g;
|
|
@@ -85074,9 +86050,9 @@ function lastLocatorLabels(chain) {
|
|
|
85074
86050
|
if (t)
|
|
85075
86051
|
labels.push(t[1]);
|
|
85076
86052
|
}
|
|
85077
|
-
const
|
|
85078
|
-
if (
|
|
85079
|
-
labels.push(
|
|
86053
|
+
const has2 = optionText(last.args, HAS_TEXT_OPTION_RE);
|
|
86054
|
+
if (has2 !== null)
|
|
86055
|
+
labels.push(has2);
|
|
85080
86056
|
}
|
|
85081
86057
|
return labels.map((l) => l.replace(/^[\s^(?:]+/, "").trim());
|
|
85082
86058
|
}
|
|
@@ -85124,7 +86100,7 @@ function pathIdsIn(text) {
|
|
|
85124
86100
|
function findCounterIdPins(code) {
|
|
85125
86101
|
if (code.length > CLOCK_MAX_CODE_CHARS)
|
|
85126
86102
|
return [];
|
|
85127
|
-
const
|
|
86103
|
+
const clean3 = stripLineComments(blankBlockComments3(code));
|
|
85128
86104
|
const fillValues = [];
|
|
85129
86105
|
const candidates = [];
|
|
85130
86106
|
let seenWrite = false;
|
|
@@ -85132,24 +86108,24 @@ function findCounterIdPins(code) {
|
|
|
85132
86108
|
CALL_RE.lastIndex = 0;
|
|
85133
86109
|
let m;
|
|
85134
86110
|
let calls = 0;
|
|
85135
|
-
while (calls++ < MAX_CALLS2 && (m = CALL_RE.exec(
|
|
86111
|
+
while (calls++ < MAX_CALLS2 && (m = CALL_RE.exec(clean3)) !== null) {
|
|
85136
86112
|
const name = m[1];
|
|
85137
86113
|
const open = m.index + m[0].length - 1;
|
|
85138
86114
|
if (VALUE_WRITES.has(name)) {
|
|
85139
86115
|
seenWrite = true;
|
|
85140
|
-
const args2 = argsAt(
|
|
86116
|
+
const args2 = argsAt(clean3, open);
|
|
85141
86117
|
if (args2 !== null)
|
|
85142
86118
|
fillValues.push(...staticStrings(args2));
|
|
85143
86119
|
continue;
|
|
85144
86120
|
}
|
|
85145
86121
|
if (createIndex === -1) {
|
|
85146
|
-
if (name === "click" && seenWrite && isCreateClick(
|
|
86122
|
+
if (name === "click" && seenWrite && isCreateClick(clean3, m.index))
|
|
85147
86123
|
createIndex = m.index;
|
|
85148
86124
|
continue;
|
|
85149
86125
|
}
|
|
85150
86126
|
if (name === "click")
|
|
85151
86127
|
continue;
|
|
85152
|
-
const args = argsAt(
|
|
86128
|
+
const args = argsAt(clean3, open);
|
|
85153
86129
|
if (args === null)
|
|
85154
86130
|
continue;
|
|
85155
86131
|
const isUrl = URL_SINKS.has(name);
|
|
@@ -85168,7 +86144,7 @@ function findCounterIdPins(code) {
|
|
|
85168
86144
|
}
|
|
85169
86145
|
if (createIndex === -1)
|
|
85170
86146
|
return [];
|
|
85171
|
-
const before =
|
|
86147
|
+
const before = clean3.slice(0, createIndex);
|
|
85172
86148
|
let pathIdsBefore = null;
|
|
85173
86149
|
const findings = [];
|
|
85174
86150
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -85192,7 +86168,7 @@ function findCounterIdPins(code) {
|
|
|
85192
86168
|
continue;
|
|
85193
86169
|
}
|
|
85194
86170
|
}
|
|
85195
|
-
findings.push({ kind: c.kind, literal: c.literal, line: lineAt(
|
|
86171
|
+
findings.push({ kind: c.kind, literal: c.literal, line: lineAt(clean3, c.index) });
|
|
85196
86172
|
}
|
|
85197
86173
|
return findings;
|
|
85198
86174
|
}
|
|
@@ -85487,7 +86463,7 @@ var init_suspicious_expectation = __esm({
|
|
|
85487
86463
|
NOT_STUCK_RE = /\b(?:not|never|no longer|isn't|doesn't|don't|without)\s+(?:\w+\s+){0,2}?(?:stuck|hang|hangs|hung|freeze|freezes|frozen|spin|spins|spinning)\b/i;
|
|
85488
86464
|
LISTS_STUCK_RE = /\b(?:appears? in (?:the )?[\w ]{0,25}(?:report|list|dashboard|queue)|(?:lists?|monitors?|shows?|reports?) (?:\w+ ){0,2}(?:that|which|whose) (?:are |is )?(?:stuck|hangs?|hung|frozen)|can (?:retry|re-?run) (?:\w+ ){0,2}(?:that (?:are )?)?stuck)\b/i;
|
|
85489
86465
|
STUCK_VETO_RE = new RegExp(`${NOT_STUCK_RE.source}|${LISTS_STUCK_RE.source}`, "i");
|
|
85490
|
-
NOT_SILENT_RE = /\b(?:not|never|\w+n't|instead of|rather than|avoids?|prevents?)\s+(?:\w+\s+){0,1}?(?:fail(?:s|ing|ed)?|ignor\w*)
|
|
86466
|
+
NOT_SILENT_RE = /\b(?:not|never|\w+n't|instead of|rather than|avoids?|prevents?)\s+(?:\w+\s+){0,1}?(?:(?:fail(?:s|ing|ed)?|ignor\w*)\s*)?silent(?:ly)?\b/i;
|
|
85491
86467
|
PENDING_WORD = "(?:sending|loading|saving|searching|checking(?!\\s+(?:account|balance|out|in)\\b)|syncing|refreshing|fetching|validating|processing|submitting|uploading|posting|publishing|creating|updating|deleting|connecting|verifying|signing in|logging in)";
|
|
85492
86468
|
ELLIPSIS = "(?:\\.{3}|\u2026)";
|
|
85493
86469
|
NOT_STAY_RE = /\b(?:not|never|no longer|without|n't|cannot)\s+(?:\w+\s+){0,2}?(?:stay|stays|stayed|remain|remains|remained|leave|leaves|left)\b/i;
|
|
@@ -85643,7 +86619,7 @@ function outcomeNamedByAssertion(outcome, code) {
|
|
|
85643
86619
|
function namedByStatements(outcome, statements) {
|
|
85644
86620
|
const text = outcomeText(outcome);
|
|
85645
86621
|
if (outcome.type === "url") {
|
|
85646
|
-
const routes = (text.match(ROUTE_TERM) ?? []).map((r) => r
|
|
86622
|
+
const routes = (text.match(ROUTE_TERM) ?? []).map((r) => stripTrailingChars(r, ROUTE_TRAILING_PUNCTUATION)).filter((r) => r.length > 1);
|
|
85647
86623
|
return statements.some((stmt) => {
|
|
85648
86624
|
if (!/\.(?:waitForURL|toHaveURL)\s{0,20}\(/.test(stmt))
|
|
85649
86625
|
return false;
|
|
@@ -85815,7 +86791,7 @@ function evaluatePromotionGate(input, checks = PROMOTION_QUALITY_CHECKS) {
|
|
|
85815
86791
|
...suspiciousTagged ? { suspiciousPass: { mode: suspicious, covered: suspiciousCovered, wouldHold: suspiciousHold } } : {}
|
|
85816
86792
|
};
|
|
85817
86793
|
}
|
|
85818
|
-
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, 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_TAG, count2, RECHECKED_NOTES, EVIDENCE_NOTE_PREFIXES, PENDING_RECHECK_NOTE_PREFIXES, STRENGTH_RANK;
|
|
86794
|
+
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_TAG, count2, RECHECKED_NOTES, EVIDENCE_NOTE_PREFIXES, PENDING_RECHECK_NOTE_PREFIXES, STRENGTH_RANK;
|
|
85819
86795
|
var init_promotion_quality_gate = __esm({
|
|
85820
86796
|
"../shared/dist/promotion-quality-gate.js"() {
|
|
85821
86797
|
"use strict";
|
|
@@ -85830,17 +86806,21 @@ var init_promotion_quality_gate = __esm({
|
|
|
85830
86806
|
init_run_classification();
|
|
85831
86807
|
init_expected_outcome_coverage();
|
|
85832
86808
|
init_expect_call();
|
|
86809
|
+
init_trailing_slashes();
|
|
85833
86810
|
SOURCE_RANK = { generator: 0, classifier: 0, healer: 1, human: 2 };
|
|
85834
86811
|
strengthCheck = {
|
|
85835
86812
|
id: "assertion-strength",
|
|
85836
|
-
run({ code, strengthGate, flagContradictedAdditions }) {
|
|
85837
|
-
const verdict = validateAssertionStrength(code, { flagContradictedAdditions: flagContradictedAdditions === true });
|
|
86813
|
+
run({ code, tags, strengthGate, flagContradictedAdditions, lastActionProof }) {
|
|
86814
|
+
const verdict = validateAssertionStrength(code, { flagContradictedAdditions: flagContradictedAdditions === true, lastActionProof });
|
|
85838
86815
|
if (verdict.severity === "route-bug")
|
|
85839
86816
|
return [{ check: "route-bug" }];
|
|
85840
|
-
|
|
86817
|
+
const authDowngrade = verdict.severity === "downgrade" && tags.some((t) => t.toLowerCase() === "@auth");
|
|
86818
|
+
if (verdict.severity !== "block" && !authDowngrade)
|
|
85841
86819
|
return [];
|
|
85842
86820
|
const revealed = strengthGate?.severity === "none" && strengthGate.revealEvidence === "revealed" && strengthGate.source !== "heal";
|
|
85843
|
-
|
|
86821
|
+
if (revealed)
|
|
86822
|
+
return [];
|
|
86823
|
+
return [{ check: authDowngrade ? "strength-downgrade-auth" : "strength-block" }];
|
|
85844
86824
|
}
|
|
85845
86825
|
};
|
|
85846
86826
|
STRING_CONST = /\b(?:const|let|var)\s{1,20}([A-Za-z_$][\w$]{0,60})\s{0,20}=\s{0,20}(?:'([^'\\\n]{0,300})'|"([^"\\\n]{0,300})"|`([^`\\$\n]{0,300})`)\s{0,20}[;\n]/g;
|
|
@@ -85849,7 +86829,7 @@ var init_promotion_quality_gate = __esm({
|
|
|
85849
86829
|
MAX_STATEMENTS = 500;
|
|
85850
86830
|
MAX_STATEMENT_CHARS = 400;
|
|
85851
86831
|
LITERAL_OR_IDENTIFIER = /'(?:[^'\\\n]|\\.){0,500}'|"(?:[^"\\\n]|\\.){0,500}"|`(?:[^`\\]|\\.){0,2000}`|(?<![\w$.])[A-Za-z_$][\w$]{0,60}/g;
|
|
85852
|
-
MUTATING_ACTION = /\.(?:click|dblclick|tap|fill|type|pressSequentially|press|check|uncheck|selectOption|setInputFiles|dragTo|clear)\s{0,20}\(|\brequest\s{0,20}\.\s{0,20}(?:post|put|patch|delete|fetch)\s{0,20}\(/;
|
|
86832
|
+
MUTATING_ACTION = /\.(?:click|dblclick|tap|fill|type|pressSequentially|press|check|uncheck|setChecked|selectOption|setInputFiles|dragTo|dragAndDrop|clear)\s{0,20}\(|\brequest\s{0,20}\.\s{0,20}(?:post|put|patch|delete|fetch)\s{0,20}\(/;
|
|
85853
86833
|
FEEDBACK_REGION = /getByRole\s{0,20}\(\s{0,20}['"`](?:alert|status)['"`]|\baria-live\b|\btoast|\bsnackbar\b|\bflash.?message\b/i;
|
|
85854
86834
|
ONE_SHOT_MESSAGE_REASON = "one-shot success/error banner text";
|
|
85855
86835
|
FEEDBACK_REGION_ALL = /getByRole\s{0,20}\(\s{0,20}['"`](?:alert|status)['"`]|\baria-live\b|\btoast|\bsnackbar\b|\bflash.?message\b/gi;
|
|
@@ -85908,6 +86888,7 @@ var init_promotion_quality_gate = __esm({
|
|
|
85908
86888
|
"element-hidden": /\.(?:toBeHidden|not\s{0,20}\.\s{0,20}toBeVisible|not\s{0,20}\.\s{0,20}toBeAttached|not\s{0,20}\.\s{0,20}toContainText)\s{0,20}\(|\.toHaveCount\s{0,20}\(\s{0,20}0\s{0,20}\)/
|
|
85909
86889
|
};
|
|
85910
86890
|
ROUTE_TERM = /\/[A-Za-z0-9_./?&=#-]{1,200}/g;
|
|
86891
|
+
ROUTE_TRAILING_PUNCTUATION = /[.,;:!?)]/;
|
|
85911
86892
|
QUOTED_LITERAL = /'([^'\\\n]{3,200})'|"([^"\\\n]{3,200})"|`([^`\\$\n]{3,200})`/g;
|
|
85912
86893
|
GENERIC_LITERAL = /^(?:true|false|button|link|heading|dialog|alertdialog|article|main|region|status|alert|textbox|combobox|checkbox|radio|tab|tabpanel|option|list|listitem|row|cell|img|navigation|banner|complementary|contentinfo|form|search|menu|menuitem|visible|hidden|attached|detached|domcontentloaded|load|networkidle)$/i;
|
|
85913
86894
|
MAX_OUTCOME_STATEMENTS = 300;
|
|
@@ -86027,8 +87008,8 @@ ${goalText}`);
|
|
|
86027
87008
|
return count3 > 0 ? [{ check: "locator-fragment", detail: String(count3), soft: true }] : [];
|
|
86028
87009
|
}
|
|
86029
87010
|
};
|
|
86030
|
-
FILTER_STEP = /\.(?:getByLabel|getByPlaceholder|getByRole|getByTitle)\s*\([^)\n]{0,200}?\b(?:filter|sort|search|status|delete|remove|dismiss|archive|clear)\b[^)\n]{0,200}\)[^\n]{0,200}\.(?:selectOption|fill|type|pressSequentially|click|check|uncheck|press)\s*\(/i;
|
|
86031
|
-
NEXT_ACTION = /\.(?:goto|reload|click|dblclick|tap|fill|type|pressSequentially|press|check|uncheck|selectOption|setInputFiles|dragTo|clear)\s*\(/;
|
|
87011
|
+
FILTER_STEP = /\.(?:getByLabel|getByPlaceholder|getByRole|getByTitle)\s*\([^)\n]{0,200}?\b(?:filter|sort|search|status|delete|remove|dismiss|archive|clear)\b[^)\n]{0,200}\)[^\n]{0,200}\.(?:selectOption|fill|type|pressSequentially|click|check|uncheck|setChecked|press)\s*\(/i;
|
|
87012
|
+
NEXT_ACTION = /\.(?:goto|reload|click|dblclick|tap|fill|type|pressSequentially|press|check|uncheck|setChecked|selectOption|setInputFiles|dragTo|dragAndDrop|clear)\s*\(/;
|
|
86032
87013
|
REDUCTION_PROOF = /\.toHaveCount\s*\(|\.not\s*\.\s*(?:toBeVisible|toBeAttached|toContainText|toHaveText)\s*\(|\.toBeHidden\s*\(|\bShowing\b|\bof \d+\b|\b\d+ (?:results?|rows?|items?|candidates?|entries|matches|records)\b|\bNo (?:[\w'-]+ ){0,3}(?:match|matches|results?|found|left|remain|yet)\b|\bNothing (?:to show|found|matches)\b|\bis empty\b|\btoHaveURL\b/i;
|
|
86033
87014
|
MAX_FILTER_LINES = 2e3;
|
|
86034
87015
|
MAX_FILTER_LINE_CHARS = 600;
|
|
@@ -86143,7 +87124,7 @@ ${goalText}`);
|
|
|
86143
87124
|
});
|
|
86144
87125
|
|
|
86145
87126
|
// ../shared/dist/regex-alternation.js
|
|
86146
|
-
function
|
|
87127
|
+
function closingParens2(source) {
|
|
86147
87128
|
const close = new Int32Array(source.length).fill(-1);
|
|
86148
87129
|
const open = [];
|
|
86149
87130
|
let inClass = false;
|
|
@@ -86168,7 +87149,7 @@ function closingParens(source) {
|
|
|
86168
87149
|
return close;
|
|
86169
87150
|
}
|
|
86170
87151
|
function alternatesAtTop(source) {
|
|
86171
|
-
const close =
|
|
87152
|
+
const close = closingParens2(source);
|
|
86172
87153
|
let start = source.startsWith("^") ? 1 : 0;
|
|
86173
87154
|
let end = source.endsWith("$") ? source.length - 1 : source.length;
|
|
86174
87155
|
while (start < end && source[start] === "(" && close[start] === end - 1) {
|
|
@@ -86217,6 +87198,124 @@ var init_page_evidence = __esm({
|
|
|
86217
87198
|
}
|
|
86218
87199
|
});
|
|
86219
87200
|
|
|
87201
|
+
// ../shared/dist/stated-limits.js
|
|
87202
|
+
function validDate(v) {
|
|
87203
|
+
const [y, m, d] = v.split("-").map(Number);
|
|
87204
|
+
const t = new Date(Date.UTC(y, m - 1, d));
|
|
87205
|
+
return t.getUTCFullYear() === y && t.getUTCMonth() === m - 1 && t.getUTCDate() === d;
|
|
87206
|
+
}
|
|
87207
|
+
function isoFor(type, v) {
|
|
87208
|
+
const re = DATE_RE[type];
|
|
87209
|
+
if (!re || !re.test(v))
|
|
87210
|
+
return false;
|
|
87211
|
+
if (type === "date")
|
|
87212
|
+
return validDate(v);
|
|
87213
|
+
if (type === "datetime-local")
|
|
87214
|
+
return validDate(v.slice(0, 10)) && Number(v.slice(11, 13)) < 24 && Number(v.slice(14, 16)) < 60;
|
|
87215
|
+
if (type === "time")
|
|
87216
|
+
return Number(v.slice(0, 2)) < 24 && Number(v.slice(3, 5)) < 60;
|
|
87217
|
+
if (type === "month")
|
|
87218
|
+
return Number(v.slice(5, 7)) >= 1 && Number(v.slice(5, 7)) <= 12;
|
|
87219
|
+
return Number(v.slice(6, 8)) >= 1 && Number(v.slice(6, 8)) <= 53;
|
|
87220
|
+
}
|
|
87221
|
+
function clean2(raw) {
|
|
87222
|
+
return typeof raw === "string" ? raw.trim() : "";
|
|
87223
|
+
}
|
|
87224
|
+
function statedLimitsFromAttrs(attrs, inputType) {
|
|
87225
|
+
const type = (inputType ?? "").trim().toLowerCase();
|
|
87226
|
+
const limits = [];
|
|
87227
|
+
const add = (k, v) => {
|
|
87228
|
+
limits.push({ k, v });
|
|
87229
|
+
};
|
|
87230
|
+
if (NUMBER_TYPES.has(type)) {
|
|
87231
|
+
for (const [attr, k] of [["min", "min"], ["max", "max"]]) {
|
|
87232
|
+
const v = clean2(attrs[attr]);
|
|
87233
|
+
if (NUMBER_RE.test(v))
|
|
87234
|
+
add(k, v);
|
|
87235
|
+
}
|
|
87236
|
+
const step = clean2(attrs.step);
|
|
87237
|
+
if (NUMBER_RE.test(step) && Number(step) > 0)
|
|
87238
|
+
add("step", step);
|
|
87239
|
+
} else if (type in DATE_RE) {
|
|
87240
|
+
for (const [attr, k] of [["min", "min"], ["max", "max"]]) {
|
|
87241
|
+
const v = clean2(attrs[attr]);
|
|
87242
|
+
if (isoFor(type, v))
|
|
87243
|
+
add(k, v);
|
|
87244
|
+
}
|
|
87245
|
+
} else if (TEXT_TYPES.has(type)) {
|
|
87246
|
+
for (const [attr, k] of [["minlength", "minLength"], ["maxlength", "maxLength"]]) {
|
|
87247
|
+
const v = clean2(attrs[attr]);
|
|
87248
|
+
if (LENGTH_RE.test(v))
|
|
87249
|
+
add(k, String(Number(v)));
|
|
87250
|
+
}
|
|
87251
|
+
const pattern = cleanPattern(clean2(attrs.pattern).slice(0, STATED_PATTERN_MAX));
|
|
87252
|
+
if (pattern)
|
|
87253
|
+
add("pattern", pattern);
|
|
87254
|
+
}
|
|
87255
|
+
return limits.length > 0 ? { v: STATED_LIMITS_VERSION, limits } : null;
|
|
87256
|
+
}
|
|
87257
|
+
function cleanPattern(text) {
|
|
87258
|
+
return text.replace(/[\u0000-\u001f\u007f]/g, "").replace(/[\ud800-\udbff](?![\udc00-\udfff])|(?<![\ud800-\udbff])[\udc00-\udfff]/g, "");
|
|
87259
|
+
}
|
|
87260
|
+
function readStatedLimits(stored) {
|
|
87261
|
+
if (!stored || typeof stored !== "object" || Array.isArray(stored))
|
|
87262
|
+
return [];
|
|
87263
|
+
const rec = stored;
|
|
87264
|
+
if (rec.v !== STATED_LIMITS_VERSION || !Array.isArray(rec.limits))
|
|
87265
|
+
return [];
|
|
87266
|
+
const out = [];
|
|
87267
|
+
const seen = /* @__PURE__ */ new Set();
|
|
87268
|
+
for (const item of rec.limits.slice(0, MAX_LIMITS * 2)) {
|
|
87269
|
+
if (!item || typeof item !== "object")
|
|
87270
|
+
continue;
|
|
87271
|
+
const { k, v } = item;
|
|
87272
|
+
if (typeof k !== "string" || typeof v !== "string" || !KINDS.includes(k) || seen.has(k))
|
|
87273
|
+
continue;
|
|
87274
|
+
if (v.length === 0 || v.length > STATED_PATTERN_MAX)
|
|
87275
|
+
continue;
|
|
87276
|
+
const text = k === "pattern" ? cleanPattern(v) : v;
|
|
87277
|
+
if (text === "")
|
|
87278
|
+
continue;
|
|
87279
|
+
if (k === "minLength" || k === "maxLength") {
|
|
87280
|
+
if (!LENGTH_RE.test(v))
|
|
87281
|
+
continue;
|
|
87282
|
+
} else if (k === "step") {
|
|
87283
|
+
if (!NUMBER_RE.test(v))
|
|
87284
|
+
continue;
|
|
87285
|
+
} else if (k === "min" || k === "max") {
|
|
87286
|
+
if (!NUMBER_RE.test(v) && !Object.values(DATE_RE).some((re) => re.test(v)))
|
|
87287
|
+
continue;
|
|
87288
|
+
}
|
|
87289
|
+
seen.add(k);
|
|
87290
|
+
out.push({ k, v: text });
|
|
87291
|
+
}
|
|
87292
|
+
return out;
|
|
87293
|
+
}
|
|
87294
|
+
function statedLimitsRecord(limits) {
|
|
87295
|
+
return limits.length > 0 ? { v: STATED_LIMITS_VERSION, limits } : null;
|
|
87296
|
+
}
|
|
87297
|
+
var STATED_LIMITS_VERSION, STATED_PATTERN_MAX, KINDS, MAX_LIMITS, TEXT_TYPES, NUMBER_TYPES, DATE_RE, NUMBER_RE, LENGTH_RE;
|
|
87298
|
+
var init_stated_limits = __esm({
|
|
87299
|
+
"../shared/dist/stated-limits.js"() {
|
|
87300
|
+
"use strict";
|
|
87301
|
+
STATED_LIMITS_VERSION = 1;
|
|
87302
|
+
STATED_PATTERN_MAX = 200;
|
|
87303
|
+
KINDS = ["min", "max", "minLength", "maxLength", "step", "pattern"];
|
|
87304
|
+
MAX_LIMITS = KINDS.length;
|
|
87305
|
+
TEXT_TYPES = /* @__PURE__ */ new Set(["text", "search", "email", "url", "tel", "password", "textarea", ""]);
|
|
87306
|
+
NUMBER_TYPES = /* @__PURE__ */ new Set(["number", "range"]);
|
|
87307
|
+
DATE_RE = {
|
|
87308
|
+
date: /^\d{4}-\d{2}-\d{2}$/,
|
|
87309
|
+
"datetime-local": /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2})?$/,
|
|
87310
|
+
time: /^\d{2}:\d{2}(?::\d{2})?$/,
|
|
87311
|
+
month: /^\d{4}-\d{2}$/,
|
|
87312
|
+
week: /^\d{4}-W\d{2}$/
|
|
87313
|
+
};
|
|
87314
|
+
NUMBER_RE = /^-?\d{1,15}(?:\.\d{1,10})?$/;
|
|
87315
|
+
LENGTH_RE = /^\d{1,7}$/;
|
|
87316
|
+
}
|
|
87317
|
+
});
|
|
87318
|
+
|
|
86220
87319
|
// ../shared/dist/index.js
|
|
86221
87320
|
var dist_exports = {};
|
|
86222
87321
|
__export(dist_exports, {
|
|
@@ -86224,9 +87323,11 @@ __export(dist_exports, {
|
|
|
86224
87323
|
ACTION_BATCH_MAX_SIZE: () => ACTION_BATCH_MAX_SIZE,
|
|
86225
87324
|
ADDON_DEFINITIONS: () => ADDON_DEFINITIONS,
|
|
86226
87325
|
ADMIN_EMAIL_LIMITS: () => ADMIN_EMAIL_LIMITS,
|
|
87326
|
+
ADMIN_FORCE_CANCELLED_RUN_ERROR: () => ADMIN_FORCE_CANCELLED_RUN_ERROR,
|
|
86227
87327
|
ADMIN_VIEW_DEFAULT_RETURN_TO: () => ADMIN_VIEW_DEFAULT_RETURN_TO,
|
|
86228
87328
|
AGENT_AI_PROVIDER_PREFIXES: () => AGENT_AI_PROVIDER_PREFIXES,
|
|
86229
87329
|
AI_CREDIT_MARGIN: () => AI_CREDIT_MARGIN,
|
|
87330
|
+
ALLOWED_PROVIDER_CHAIN_HOPS: () => ALLOWED_PROVIDER_CHAIN_HOPS,
|
|
86230
87331
|
API_AUTH_HEADERS_ENV_KEY: () => API_AUTH_HEADERS_ENV_KEY,
|
|
86231
87332
|
API_MODEL_CATALOG: () => API_MODEL_CATALOG,
|
|
86232
87333
|
API_MODEL_FIELDS: () => API_MODEL_FIELDS,
|
|
@@ -86247,6 +87348,7 @@ __export(dist_exports, {
|
|
|
86247
87348
|
AUDIO_CHUNK_DURATION_MS: () => AUDIO_CHUNK_DURATION_MS,
|
|
86248
87349
|
AUTH_PATH_SIGNATURE: () => AUTH_PATH_SIGNATURE,
|
|
86249
87350
|
AUTH_PROVIDER_HOST_SIGNATURES: () => AUTH_PROVIDER_HOST_SIGNATURES,
|
|
87351
|
+
AUTH_SESSION_GENERATION_RE: () => AUTH_SESSION_GENERATION_RE,
|
|
86250
87352
|
AUTH_STATE_EXPIRY_SKEW_MS: () => AUTH_STATE_EXPIRY_SKEW_MS,
|
|
86251
87353
|
AUTH_TAG_COOKIE_STATE: () => AUTH_TAG_COOKIE_STATE,
|
|
86252
87354
|
AUTH_TAG_LOGIN_BEARER: () => AUTH_TAG_LOGIN_BEARER,
|
|
@@ -86265,12 +87367,14 @@ __export(dist_exports, {
|
|
|
86265
87367
|
BUG_TEST_BROKEN_REASON: () => BUG_TEST_BROKEN_REASON,
|
|
86266
87368
|
BUG_TEST_BROKEN_TAG: () => BUG_TEST_BROKEN_TAG,
|
|
86267
87369
|
CACHE_PRICE_PER_M: () => CACHE_PRICE_PER_M,
|
|
87370
|
+
CANCELLED_REASON_PREFIXES: () => CANCELLED_REASON_PREFIXES,
|
|
86268
87371
|
CANVAS_UNSUPPORTED_BODY: () => CANVAS_UNSUPPORTED_BODY,
|
|
86269
87372
|
CANVAS_UNSUPPORTED_CODE: () => CANVAS_UNSUPPORTED_CODE,
|
|
86270
87373
|
CANVAS_UNSUPPORTED_NOT_CHARGED: () => CANVAS_UNSUPPORTED_NOT_CHARGED,
|
|
86271
87374
|
CANVAS_UNSUPPORTED_OVERRIDE_HINT: () => CANVAS_UNSUPPORTED_OVERRIDE_HINT,
|
|
86272
87375
|
CANVAS_UNSUPPORTED_TITLE: () => CANVAS_UNSUPPORTED_TITLE,
|
|
86273
87376
|
CAPTURE_JSON_STRUCTURE_LIMITS: () => CAPTURE_JSON_STRUCTURE_LIMITS,
|
|
87377
|
+
CHAIN_CANCELLED_RUN_ERROR: () => CHAIN_CANCELLED_RUN_ERROR,
|
|
86274
87378
|
CHAT_FAILOVER_KEY: () => CHAT_FAILOVER_KEY,
|
|
86275
87379
|
CLAUDE_CLI_DEFAULT_EFFORT: () => CLAUDE_CLI_DEFAULT_EFFORT,
|
|
86276
87380
|
CLAUDE_CLI_DEFAULT_MODEL: () => CLAUDE_CLI_DEFAULT_MODEL,
|
|
@@ -86307,6 +87411,7 @@ __export(dist_exports, {
|
|
|
86307
87411
|
DEFAULT_GEMINI_SCREEN_MODEL: () => DEFAULT_GEMINI_SCREEN_MODEL,
|
|
86308
87412
|
DEFAULT_JSON_STRUCTURE_LIMITS: () => DEFAULT_JSON_STRUCTURE_LIMITS,
|
|
86309
87413
|
DEFAULT_PLATFORM_DB_POOL_SIZE: () => DEFAULT_PLATFORM_DB_POOL_SIZE,
|
|
87414
|
+
DEFAULT_PROVIDER_ACCOUNT_ID: () => DEFAULT_PROVIDER_ACCOUNT_ID,
|
|
86310
87415
|
DEFAULT_SHARED_DB_POOL_SIZE: () => DEFAULT_SHARED_DB_POOL_SIZE,
|
|
86311
87416
|
DEFAULT_STT_MODEL: () => DEFAULT_STT_MODEL,
|
|
86312
87417
|
DEFAULT_STT_MODEL_BY_PROVIDER: () => DEFAULT_STT_MODEL_BY_PROVIDER,
|
|
@@ -86323,6 +87428,7 @@ __export(dist_exports, {
|
|
|
86323
87428
|
ENVIRONMENTAL_ERROR_STORED_PREFIXES: () => ENVIRONMENTAL_ERROR_STORED_PREFIXES,
|
|
86324
87429
|
EVIDENCE_NOTE_PREFIXES: () => EVIDENCE_NOTE_PREFIXES,
|
|
86325
87430
|
EXPECT_CALL_RE: () => EXPECT_CALL_RE,
|
|
87431
|
+
FEATURE_ROW_RUN_WINDOW: () => FEATURE_ROW_RUN_WINDOW,
|
|
86326
87432
|
FLOW_PHASE_LABELS: () => FLOW_PHASE_LABELS,
|
|
86327
87433
|
FLOW_PHASE_TYPES: () => FLOW_PHASE_TYPES,
|
|
86328
87434
|
FLOW_SERVER_TYPES: () => FLOW_SERVER_TYPES,
|
|
@@ -86379,6 +87485,8 @@ __export(dist_exports, {
|
|
|
86379
87485
|
LIVE_FRAME_STALE_MS: () => LIVE_FRAME_STALE_MS,
|
|
86380
87486
|
LIVE_FRAME_UNFOCUSED_INTERVAL_MS: () => LIVE_FRAME_UNFOCUSED_INTERVAL_MS,
|
|
86381
87487
|
LIVE_THUMBNAIL_MAX_BASE64_BYTES: () => LIVE_THUMBNAIL_MAX_BASE64_BYTES,
|
|
87488
|
+
MAX_BALANCED_SCAN: () => MAX_BALANCED_SCAN,
|
|
87489
|
+
MAX_CALLS: () => MAX_CALLS,
|
|
86382
87490
|
MAX_CREDIT_TOPUP_CENTS: () => MAX_CREDIT_TOPUP_CENTS,
|
|
86383
87491
|
MAX_DEEPLINK_LENGTH: () => MAX_DEEPLINK_LENGTH,
|
|
86384
87492
|
MAX_EMAIL_ADDRESS_LENGTH: () => MAX_EMAIL_ADDRESS_LENGTH,
|
|
@@ -86388,6 +87496,8 @@ __export(dist_exports, {
|
|
|
86388
87496
|
MAX_ORG_NAME_LENGTH: () => MAX_ORG_NAME_LENGTH,
|
|
86389
87497
|
MAX_PASSWORD_BYTES: () => MAX_PASSWORD_BYTES,
|
|
86390
87498
|
MAX_PLAYWRIGHT_CODE_LENGTH: () => MAX_PLAYWRIGHT_CODE_LENGTH,
|
|
87499
|
+
MAX_PROVIDER_ACCOUNTS: () => MAX_PROVIDER_ACCOUNTS,
|
|
87500
|
+
MAX_PROVIDER_ACCOUNT_MODELS: () => MAX_PROVIDER_ACCOUNT_MODELS,
|
|
86391
87501
|
MAX_SURVEY_ENTRY_URLS: () => MAX_SURVEY_ENTRY_URLS,
|
|
86392
87502
|
MAX_SURVEY_ENTRY_URL_LENGTH: () => MAX_SURVEY_ENTRY_URL_LENGTH,
|
|
86393
87503
|
MCP_ARMY_LIMITS: () => MCP_ARMY_LIMITS,
|
|
@@ -86423,6 +87533,7 @@ __export(dist_exports, {
|
|
|
86423
87533
|
MUSE_ENGINE_DEFAULT_MODEL: () => MUSE_ENGINE_DEFAULT_MODEL,
|
|
86424
87534
|
MUSE_ENGINE_MODELS: () => MUSE_ENGINE_MODELS,
|
|
86425
87535
|
NOREPLY_EMAIL: () => NOREPLY_EMAIL,
|
|
87536
|
+
OPENCODE_GO_DEEPSEEK_GLM_MODELS: () => OPENCODE_GO_DEEPSEEK_GLM_MODELS,
|
|
86426
87537
|
OPENCODE_GO_MODEL_PATTERN: () => OPENCODE_GO_MODEL_PATTERN,
|
|
86427
87538
|
OPENCODE_GO_PREFIX: () => OPENCODE_GO_PREFIX,
|
|
86428
87539
|
OPENROUTER_MAX_CALL_COST_USD: () => OPENROUTER_MAX_CALL_COST_USD,
|
|
@@ -86442,10 +87553,12 @@ __export(dist_exports, {
|
|
|
86442
87553
|
PLAN_FEATURES: () => PLAN_FEATURES,
|
|
86443
87554
|
PLAN_FEATURE_LOCKED_CODE: () => PLAN_FEATURE_LOCKED_CODE,
|
|
86444
87555
|
PLAN_ORDER: () => PLAN_ORDER,
|
|
87556
|
+
PLATFORM_ADMIN_CANCELLED_RUN_ERROR: () => PLATFORM_ADMIN_CANCELLED_RUN_ERROR,
|
|
86445
87557
|
PLATFORM_ADMIN_EMAIL: () => PLATFORM_ADMIN_EMAIL,
|
|
86446
87558
|
PLATFORM_DEFAULT_PROVIDER: () => PLATFORM_DEFAULT_PROVIDER,
|
|
86447
87559
|
PLATFORM_PLAN_BILLING: () => PLATFORM_PLAN_BILLING,
|
|
86448
87560
|
PLATFORM_SERVER_APPLICATION_NAME: () => PLATFORM_SERVER_APPLICATION_NAME,
|
|
87561
|
+
PLATFORM_SUPPORT_CANCELLED_RUN_ERROR: () => PLATFORM_SUPPORT_CANCELLED_RUN_ERROR,
|
|
86449
87562
|
POST_SPECIAL_TRIAL_DAYS: () => POST_SPECIAL_TRIAL_DAYS,
|
|
86450
87563
|
PRESET_DIRECT_FALLBACK: () => PRESET_DIRECT_FALLBACK,
|
|
86451
87564
|
PRODUCTION_READ_ONLY_GUARD_TEMPLATE: () => PRODUCTION_READ_ONLY_GUARD_TEMPLATE,
|
|
@@ -86457,17 +87570,25 @@ __export(dist_exports, {
|
|
|
86457
87570
|
PROJECT_OVERRIDE_FIELDS: () => PROJECT_OVERRIDE_FIELDS,
|
|
86458
87571
|
PROMOTION_GATE_MAX_CODE_CHARS: () => PROMOTION_GATE_MAX_CODE_CHARS,
|
|
86459
87572
|
PROMOTION_QUALITY_CHECKS: () => PROMOTION_QUALITY_CHECKS,
|
|
87573
|
+
PROVIDER_ACCOUNT_ID_PATTERN: () => PROVIDER_ACCOUNT_ID_PATTERN,
|
|
87574
|
+
PROVIDER_ACCOUNT_MODEL_PATTERN: () => PROVIDER_ACCOUNT_MODEL_PATTERN,
|
|
86460
87575
|
PROVIDER_CHAINS: () => PROVIDER_CHAINS,
|
|
87576
|
+
PROVIDER_CHAINS_SETTING_MAX_CHARS: () => PROVIDER_CHAINS_SETTING_MAX_CHARS,
|
|
87577
|
+
PROVIDER_CHAIN_LEADS: () => PROVIDER_CHAIN_LEADS,
|
|
87578
|
+
PROVIDER_CHAIN_MAX_ENTRIES: () => PROVIDER_CHAIN_MAX_ENTRIES,
|
|
87579
|
+
PROVIDER_HOST_NOT_OFFERED: () => PROVIDER_HOST_NOT_OFFERED,
|
|
86461
87580
|
PUBLIC_PLANS: () => PUBLIC_PLANS,
|
|
86462
87581
|
QUARANTINE_CLOSE_TAGS: () => QUARANTINE_CLOSE_TAGS,
|
|
86463
87582
|
READINESS_POLL_MAX_CODE_CHARS: () => READINESS_POLL_MAX_CODE_CHARS,
|
|
86464
87583
|
READ_ONLY_TAGS: () => READ_ONLY_TAGS,
|
|
86465
87584
|
RECHECKED_NOTES: () => RECHECKED_NOTES,
|
|
86466
87585
|
RECORDING_VALUE_PLACEHOLDERS: () => RECORDING_VALUE_PLACEHOLDERS,
|
|
87586
|
+
RENDER_IDENTITY_MAX_LENGTH: () => RENDER_IDENTITY_MAX_LENGTH,
|
|
86467
87587
|
REPOSITORY_CLIS: () => REPOSITORY_CLIS,
|
|
86468
87588
|
RESERVED_PROJECT_KEYS: () => RESERVED_PROJECT_KEYS,
|
|
86469
87589
|
RESULT_STRUCTURE_TOO_COSTLY_CODE: () => RESULT_STRUCTURE_TOO_COSTLY_CODE,
|
|
86470
87590
|
RETRIED_ATTEMPTS_KEY: () => RETRIED_ATTEMPTS_KEY,
|
|
87591
|
+
RETRY_HELD_RUN_ERROR: () => RETRY_HELD_RUN_ERROR,
|
|
86471
87592
|
RUNNER_INTERRUPT_ERROR_PREFIX: () => RUNNER_INTERRUPT_ERROR_PREFIX,
|
|
86472
87593
|
RUN_INTERRUPTED_ERROR_PREFIXES: () => RUN_INTERRUPTED_ERROR_PREFIXES,
|
|
86473
87594
|
RUN_INTERRUPTION_NOT_RETRIED_MARKERS: () => RUN_INTERRUPTION_NOT_RETRIED_MARKERS,
|
|
@@ -86480,6 +87601,8 @@ __export(dist_exports, {
|
|
|
86480
87601
|
SHARED_SERVER_APPLICATION_NAME: () => SHARED_SERVER_APPLICATION_NAME,
|
|
86481
87602
|
SPEND_SOURCE_KEY: () => SPEND_SOURCE_KEY,
|
|
86482
87603
|
SPEND_SOURCE_SERVER: () => SPEND_SOURCE_SERVER,
|
|
87604
|
+
STATED_LIMITS_VERSION: () => STATED_LIMITS_VERSION,
|
|
87605
|
+
STATED_PATTERN_MAX: () => STATED_PATTERN_MAX,
|
|
86483
87606
|
STATIC_STANDARD_MIN_INTERACTIVE: () => STATIC_STANDARD_MIN_INTERACTIVE,
|
|
86484
87607
|
STT_MODEL_OPTIONS: () => STT_MODEL_OPTIONS,
|
|
86485
87608
|
SUCCESS_NOTICE_TEXT: () => SUCCESS_NOTICE_TEXT,
|
|
@@ -86496,6 +87619,7 @@ __export(dist_exports, {
|
|
|
86496
87619
|
SURVEY_NOTES_RENDER_MAX_CHARS: () => SURVEY_NOTES_RENDER_MAX_CHARS,
|
|
86497
87620
|
SURVEY_NOTE_KEYS: () => SURVEY_NOTE_KEYS,
|
|
86498
87621
|
SUSPICIOUS_PASS_TAG: () => SUSPICIOUS_PASS_TAG,
|
|
87622
|
+
TEST_DID_NOT_RUN_ERROR: () => TEST_DID_NOT_RUN_ERROR,
|
|
86499
87623
|
TEST_QUALITY_CONVENTIONS: () => TEST_QUALITY_CONVENTIONS,
|
|
86500
87624
|
TEST_USER_ENV_KEYS: () => TEST_USER_ENV_KEYS,
|
|
86501
87625
|
TEST_VARIABLE_SECRET_KEY_PATTERN: () => TEST_VARIABLE_SECRET_KEY_PATTERN,
|
|
@@ -86508,23 +87632,33 @@ __export(dist_exports, {
|
|
|
86508
87632
|
UI_VARIANTS: () => UI_VARIANTS,
|
|
86509
87633
|
UNEXPECTED_PASS_ERROR_PREFIX: () => UNEXPECTED_PASS_ERROR_PREFIX,
|
|
86510
87634
|
USER_CANCELLED_RUN_ERROR: () => USER_CANCELLED_RUN_ERROR,
|
|
87635
|
+
VISUAL_MASK_SELECTORS_MAX: () => VISUAL_MASK_SELECTORS_MAX,
|
|
87636
|
+
VISUAL_MASK_SELECTOR_FORBIDDEN: () => VISUAL_MASK_SELECTOR_FORBIDDEN,
|
|
87637
|
+
VISUAL_MASK_SELECTOR_MAX_LENGTH: () => VISUAL_MASK_SELECTOR_MAX_LENGTH,
|
|
87638
|
+
VISUAL_V1_IDENTITY: () => VISUAL_V1_IDENTITY,
|
|
86511
87639
|
VOICE_PREVIEW_SAMPLE: () => VOICE_PREVIEW_SAMPLE,
|
|
86512
87640
|
WEB_PROXY_CHAIN_HEADER: () => WEB_PROXY_CHAIN_HEADER,
|
|
86513
87641
|
WITHHELD_CREDENTIAL_TEXT: () => WITHHELD_CREDENTIAL_TEXT,
|
|
87642
|
+
ZAI_MODEL_PATTERN: () => ZAI_MODEL_PATTERN,
|
|
87643
|
+
ZAI_PREFIX: () => ZAI_PREFIX,
|
|
87644
|
+
accountServesModel: () => accountServesModel,
|
|
86514
87645
|
accumulateStatements: () => accumulateStatements,
|
|
86515
87646
|
adoptBrokerFailover: () => adoptBrokerFailover,
|
|
86516
87647
|
aiCostToCreditCents: () => aiCostToCreditCents,
|
|
87648
|
+
allowedProviderChainHosts: () => allowedProviderChainHosts,
|
|
86517
87649
|
alternatesAtTop: () => alternatesAtTop,
|
|
86518
87650
|
analyzeDerivedValues: () => analyzeDerivedValues,
|
|
86519
87651
|
analyzeMobileSelectorQuality: () => analyzeMobileSelectorQuality,
|
|
86520
87652
|
analyzePersistenceReread: () => analyzePersistenceReread,
|
|
86521
87653
|
analyzeReadinessPolling: () => analyzeReadinessPolling,
|
|
87654
|
+
analyzeRegexMatchers: () => analyzeRegexMatchers,
|
|
86522
87655
|
analyzeSharedAccountUse: () => analyzeSharedAccountUse,
|
|
86523
87656
|
analyzeStaleAfterSubmit: () => analyzeStaleAfterSubmit,
|
|
86524
87657
|
analyzeTestData: () => analyzeTestData,
|
|
86525
87658
|
analyzeUnreachedUrlWaits: () => analyzeUnreachedUrlWaits,
|
|
86526
87659
|
analyzeUrlWaits: () => analyzeUrlWaits,
|
|
86527
87660
|
analyzeWriteResponse: () => analyzeWriteResponse,
|
|
87661
|
+
androidResourceOwners: () => androidResourceOwners,
|
|
86528
87662
|
apiModelCardsFromConfig: () => apiModelCardsFromConfig,
|
|
86529
87663
|
apiModelsForProvider: () => apiModelsForProvider,
|
|
86530
87664
|
apiProviderModelLabel: () => apiProviderModelLabel,
|
|
@@ -86535,6 +87669,7 @@ __export(dist_exports, {
|
|
|
86535
87669
|
applyLaunchSpecialPlan: () => applyLaunchSpecialPlan,
|
|
86536
87670
|
asPlainExpect: () => asPlainExpect,
|
|
86537
87671
|
assertionOnlyCode: () => assertionOnlyCode,
|
|
87672
|
+
assertionStrengthHoistedReadsOn: () => assertionStrengthHoistedReadsOn,
|
|
86538
87673
|
assertionsReadVisibleContent: () => assertionsReadVisibleContent,
|
|
86539
87674
|
assessCodeOutcomeCoverage: () => assessCodeOutcomeCoverage,
|
|
86540
87675
|
assessTitleCoverage: () => assessTitleCoverage,
|
|
@@ -86618,6 +87753,7 @@ __export(dist_exports, {
|
|
|
86618
87753
|
deepgramSpeak: () => deepgramSpeak,
|
|
86619
87754
|
deepgramTranscribe: () => deepgramTranscribe,
|
|
86620
87755
|
defaultConfirmModel: () => defaultConfirmModel,
|
|
87756
|
+
defaultProviderChainEntries: () => defaultProviderChainEntries,
|
|
86621
87757
|
defaultScreenModel: () => defaultScreenModel,
|
|
86622
87758
|
defaultVoiceForTtsModel: () => defaultVoiceForTtsModel,
|
|
86623
87759
|
deriveAuthPlan: () => deriveAuthPlan,
|
|
@@ -86660,6 +87796,7 @@ __export(dist_exports, {
|
|
|
86660
87796
|
extractOutcomeSearchTerms: () => extractOutcomeSearchTerms,
|
|
86661
87797
|
featureForAiCallType: () => featureForAiCallType,
|
|
86662
87798
|
featureForMcpTool: () => featureForMcpTool,
|
|
87799
|
+
featureRowRunStatus: () => featureRowRunStatus,
|
|
86663
87800
|
findBracedClause: () => findBracedClause,
|
|
86664
87801
|
findCounterIdPins: () => findCounterIdPins,
|
|
86665
87802
|
findCredentialTextLeftover: () => findCredentialTextLeftover,
|
|
@@ -86682,6 +87819,7 @@ __export(dist_exports, {
|
|
|
86682
87819
|
formatPersistenceRereadAdvisory: () => formatPersistenceRereadAdvisory,
|
|
86683
87820
|
formatPoolBudgetLine: () => formatPoolBudgetLine,
|
|
86684
87821
|
formatReadinessPollAdvisory: () => formatReadinessPollAdvisory,
|
|
87822
|
+
formatRegexMatcherNote: () => formatRegexMatcherNote,
|
|
86685
87823
|
formatStaleAfterSubmitAdvisory: () => formatStaleAfterSubmitAdvisory,
|
|
86686
87824
|
formatSuspiciousExpectation: () => formatSuspiciousExpectation,
|
|
86687
87825
|
formatUrlWaitAdvisory: () => formatUrlWaitAdvisory,
|
|
@@ -86707,6 +87845,7 @@ __export(dist_exports, {
|
|
|
86707
87845
|
getPlanChangeType: () => getPlanChangeType,
|
|
86708
87846
|
getPlanDefinition: () => getPlanDefinition,
|
|
86709
87847
|
getPlanLabel: () => getPlanLabel,
|
|
87848
|
+
getProviderChainOverrides: () => getProviderChainOverrides,
|
|
86710
87849
|
getTrialDaysRemaining: () => getTrialDaysRemaining,
|
|
86711
87850
|
googleBrokerNavigationUrl: () => googleBrokerNavigationUrl,
|
|
86712
87851
|
googleBrokerUnavailableLine: () => googleBrokerUnavailableLine,
|
|
@@ -86723,9 +87862,11 @@ __export(dist_exports, {
|
|
|
86723
87862
|
hasOpenCodeGoPrefix: () => hasOpenCodeGoPrefix,
|
|
86724
87863
|
hasOpenRouterPrefix: () => hasOpenRouterPrefix,
|
|
86725
87864
|
hasPlatformLocator: () => hasPlatformLocator,
|
|
87865
|
+
hasProviderChainLeadsByDefault: () => hasProviderChainLeadsByDefault,
|
|
86726
87866
|
hasReadOnlyMarker: () => hasReadOnlyMarker,
|
|
86727
87867
|
hasSurveyNotes: () => hasSurveyNotes,
|
|
86728
87868
|
hasTestFailContract: () => hasTestFailContract,
|
|
87869
|
+
hasZaiPrefix: () => hasZaiPrefix,
|
|
86729
87870
|
healMobileTestSteps: () => healMobileTestSteps,
|
|
86730
87871
|
healthRunWhere: () => healthRunWhere,
|
|
86731
87872
|
heldCodeRecord: () => heldCodeRecord,
|
|
@@ -86747,8 +87888,11 @@ __export(dist_exports, {
|
|
|
86747
87888
|
isAuthTokenName: () => isAuthTokenName,
|
|
86748
87889
|
isBlockedEnvVar: () => isBlockedEnvVar,
|
|
86749
87890
|
isBrowserCliEngine: () => isBrowserCliEngine,
|
|
87891
|
+
isBrowserVersion: () => isBrowserVersion,
|
|
86750
87892
|
isBugTestBrokenError: () => isBugTestBrokenError,
|
|
87893
|
+
isCancelledReason: () => isCancelledReason,
|
|
86751
87894
|
isCanvasUnsupportedMessage: () => isCanvasUnsupportedMessage,
|
|
87895
|
+
isChainablePrimary: () => isChainablePrimary,
|
|
86752
87896
|
isCliEngineModelId: () => isCliEngineModelId,
|
|
86753
87897
|
isCliEngineSpec: () => isCliEngineSpec,
|
|
86754
87898
|
isCodeFactNote: () => isCodeFactNote,
|
|
@@ -86772,6 +87916,7 @@ __export(dist_exports, {
|
|
|
86772
87916
|
isIdentityMobileXpath: () => isIdentityMobileXpath,
|
|
86773
87917
|
isIdentityProviderSurface: () => isIdentityProviderSurface,
|
|
86774
87918
|
isIncidentalAssetPath: () => isIncidentalAssetPath,
|
|
87919
|
+
isIntentionalNegativeAuthTest: () => isIntentionalNegativeAuthTest,
|
|
86775
87920
|
isIpOrLocalhost: () => isIpOrLocalhost,
|
|
86776
87921
|
isKnownPageType: () => isKnownPageType,
|
|
86777
87922
|
isLaunchSpecialActive: () => isLaunchSpecialActive,
|
|
@@ -86799,6 +87944,7 @@ __export(dist_exports, {
|
|
|
86799
87944
|
isRunInterruptedError: () => isRunInterruptedError,
|
|
86800
87945
|
isRunnableStep: () => isRunnableStep,
|
|
86801
87946
|
isSafeDeepLink: () => isSafeDeepLink,
|
|
87947
|
+
isSafeMaskSelector: () => isSafeMaskSelector,
|
|
86802
87948
|
isSameRegistrableDomainHost: () => isSameRegistrableDomainHost,
|
|
86803
87949
|
isSelectableApiModel: () => isSelectableApiModel,
|
|
86804
87950
|
isSelfServePlan: () => isSelfServePlan,
|
|
@@ -86829,6 +87975,7 @@ __export(dist_exports, {
|
|
|
86829
87975
|
isValidSttProvider: () => isValidSttProvider,
|
|
86830
87976
|
isValidTtsModel: () => isValidTtsModel,
|
|
86831
87977
|
isValidTtsVoiceId: () => isValidTtsVoiceId,
|
|
87978
|
+
isZaiModelId: () => isZaiModelId,
|
|
86832
87979
|
jsEscapedForms: () => jsEscapedForms,
|
|
86833
87980
|
jsonStructureRefusalOf: () => jsonStructureRefusalOf,
|
|
86834
87981
|
jsonStructureVerify: () => jsonStructureVerify,
|
|
@@ -86861,6 +88008,7 @@ __export(dist_exports, {
|
|
|
86861
88008
|
normalizeFinishReason: () => normalizeFinishReason,
|
|
86862
88009
|
normalizeNoteText: () => normalizeNoteText,
|
|
86863
88010
|
normalizePageType: () => normalizePageType,
|
|
88011
|
+
normalizeProviderAccountModels: () => normalizeProviderAccountModels,
|
|
86864
88012
|
normalizeTtsModel: () => normalizeTtsModel,
|
|
86865
88013
|
normalizeTtsVoiceId: () => normalizeTtsVoiceId,
|
|
86866
88014
|
noteChatFailover: () => noteChatFailover,
|
|
@@ -86877,6 +88025,7 @@ __export(dist_exports, {
|
|
|
86877
88025
|
parseApiCardModelUpdate: () => parseApiCardModelUpdate,
|
|
86878
88026
|
parseAppTimezone: () => parseAppTimezone,
|
|
86879
88027
|
parseAuditGroupScopeId: () => parseAuditGroupScopeId,
|
|
88028
|
+
parseAuthSessionStamp: () => parseAuthSessionStamp,
|
|
86880
88029
|
parseBoolFlag: () => parseBoolFlag,
|
|
86881
88030
|
parseDbPoolSize: () => parseDbPoolSize,
|
|
86882
88031
|
parseDeepgramListenResponse: () => parseDeepgramListenResponse,
|
|
@@ -86884,13 +88033,18 @@ __export(dist_exports, {
|
|
|
86884
88033
|
parseGeminiModelsPayload: () => parseGeminiModelsPayload,
|
|
86885
88034
|
parseGoogleAuthorizeUrl: () => parseGoogleAuthorizeUrl,
|
|
86886
88035
|
parseGoogleGisRequestUrl: () => parseGoogleGisRequestUrl,
|
|
88036
|
+
parseLastActionProofMode: () => parseLastActionProofMode,
|
|
86887
88037
|
parseLimitParam: () => parseLimitParam,
|
|
86888
88038
|
parseOffsetParam: () => parseOffsetParam,
|
|
86889
88039
|
parsePageParam: () => parsePageParam,
|
|
86890
88040
|
parsePgIntSetting: () => parsePgIntSetting,
|
|
86891
88041
|
parseProjectEngineOverrides: () => parseProjectEngineOverrides,
|
|
86892
88042
|
parsePromotionGateMode: () => parsePromotionGateMode,
|
|
88043
|
+
parseProviderAccountLists: () => parseProviderAccountLists,
|
|
88044
|
+
parseProviderChainOverrides: () => parseProviderChainOverrides,
|
|
86893
88045
|
parseRecheckClearMode: () => parseRecheckClearMode,
|
|
88046
|
+
parseRenderIdentity: () => parseRenderIdentity,
|
|
88047
|
+
parseStoredProviderChainOverrides: () => parseStoredProviderChainOverrides,
|
|
86894
88048
|
parseSurveyEntryUrls: () => parseSurveyEntryUrls,
|
|
86895
88049
|
parseSuspiciousPassMode: () => parseSuspiciousPassMode,
|
|
86896
88050
|
parseTaskModelUpdate: () => parseTaskModelUpdate,
|
|
@@ -86920,13 +88074,20 @@ __export(dist_exports, {
|
|
|
86920
88074
|
profileKeyRoute: () => profileKeyRoute,
|
|
86921
88075
|
projectAppHosts: () => projectAppHosts,
|
|
86922
88076
|
providerChainFor: () => providerChainFor,
|
|
88077
|
+
providerChainHostOf: () => providerChainHostOf,
|
|
88078
|
+
providerChainHostProvider: () => providerChainHostProvider,
|
|
88079
|
+
providerChainLeadsFor: () => providerChainLeadsFor,
|
|
88080
|
+
providerChainModelKey: () => providerChainModelKey,
|
|
86923
88081
|
providerChainPrimariesForHop: () => providerChainPrimariesForHop,
|
|
88082
|
+
providerHostPlan: () => providerHostPlan,
|
|
88083
|
+
readBalanced: () => readBalanced,
|
|
86924
88084
|
readChatFailover: () => readChatFailover,
|
|
86925
88085
|
readChatReasoningTokens: () => readChatReasoningTokens,
|
|
86926
88086
|
readChatUsage: () => readChatUsage,
|
|
86927
88087
|
readEnabledEngines: () => readEnabledEngines,
|
|
86928
88088
|
readProjectEngineOverrides: () => readProjectEngineOverrides,
|
|
86929
88089
|
readRetriedAttempts: () => readRetriedAttempts,
|
|
88090
|
+
readStatedLimits: () => readStatedLimits,
|
|
86930
88091
|
readStaticPageCanvasSignals: () => readStaticPageCanvasSignals,
|
|
86931
88092
|
readSurveyEntryUrls: () => readSurveyEntryUrls,
|
|
86932
88093
|
readSurveyNotes: () => readSurveyNotes,
|
|
@@ -86939,6 +88100,7 @@ __export(dist_exports, {
|
|
|
86939
88100
|
regexLiteralEnd: () => regexLiteralEnd2,
|
|
86940
88101
|
regexOpensAfter: () => regexOpensAfter,
|
|
86941
88102
|
registrableDomain: () => registrableDomain,
|
|
88103
|
+
renderIdentity: () => renderIdentity,
|
|
86942
88104
|
renderSurveyNotesForPrompt: () => renderSurveyNotesForPrompt,
|
|
86943
88105
|
repairPageType: () => repairPageType,
|
|
86944
88106
|
replaceBlockComments: () => replaceBlockComments,
|
|
@@ -86986,11 +88148,14 @@ __export(dist_exports, {
|
|
|
86986
88148
|
selectorCandidatesForStep: () => selectorCandidatesForStep,
|
|
86987
88149
|
selectorForValue: () => selectorForValue,
|
|
86988
88150
|
setAgenticCliRuntime: () => setAgenticCliRuntime,
|
|
88151
|
+
setProviderChainOverrides: () => setProviderChainOverrides,
|
|
86989
88152
|
signupPlanFor: () => signupPlanFor,
|
|
86990
88153
|
simplifyMobileWanderingInPlace: () => simplifyMobileWanderingInPlace,
|
|
86991
88154
|
siteOf: () => siteOf,
|
|
86992
88155
|
specItemsFromTestPlans: () => specItemsFromTestPlans,
|
|
86993
88156
|
splitAnswerLines: () => splitAnswerLines,
|
|
88157
|
+
statedLimitsFromAttrs: () => statedLimitsFromAttrs,
|
|
88158
|
+
statedLimitsRecord: () => statedLimitsRecord,
|
|
86994
88159
|
stepAppliesToPlatform: () => stepAppliesToPlatform,
|
|
86995
88160
|
stepConsoleLines: () => stepConsoleLines,
|
|
86996
88161
|
stepIsDivergentForPlatform: () => stepIsDivergentForPlatform,
|
|
@@ -87002,7 +88167,11 @@ __export(dist_exports, {
|
|
|
87002
88167
|
stripCodeFactPrefix: () => stripCodeFactPrefix,
|
|
87003
88168
|
stripCoverageComments: () => stripCoverageComments,
|
|
87004
88169
|
stripEnvironmentalPrefix: () => stripEnvironmentalPrefix,
|
|
88170
|
+
stripFractionZeros: () => stripFractionZeros,
|
|
88171
|
+
stripLineComment: () => stripLineComment,
|
|
87005
88172
|
stripLoginScaffolding: () => stripLoginScaffolding,
|
|
88173
|
+
stripTrailingChars: () => stripTrailingChars,
|
|
88174
|
+
stripTrailingSlashes: () => stripTrailingSlashes,
|
|
87006
88175
|
strongerNeedsReviewSource: () => strongerNeedsReviewSource,
|
|
87007
88176
|
sttModelsForProvider: () => sttModelsForProvider,
|
|
87008
88177
|
summarizeHealth: () => summarizeHealth,
|
|
@@ -87019,10 +88188,14 @@ __export(dist_exports, {
|
|
|
87019
88188
|
ttsFallbackModel: () => ttsFallbackModel,
|
|
87020
88189
|
ttsProviderForModel: () => ttsProviderForModel,
|
|
87021
88190
|
unexpectedPassError: () => unexpectedPassError,
|
|
88191
|
+
v1RenderIdentity: () => v1RenderIdentity,
|
|
87022
88192
|
validateAppMapDocument: () => validateAppMapDocument,
|
|
87023
88193
|
validateAssertionStrength: () => validateAssertionStrength,
|
|
87024
88194
|
validateEngineSpec: () => validateEngineSpec,
|
|
88195
|
+
validateProviderChainEntries: () => validateProviderChainEntries,
|
|
88196
|
+
validateProviderChainsSetting: () => validateProviderChainsSetting,
|
|
87025
88197
|
validateTaskModelId: () => validateTaskModelId,
|
|
88198
|
+
visualBaselinesEnabled: () => visualBaselinesEnabled,
|
|
87026
88199
|
visualProDailyBudget: () => visualProDailyBudget,
|
|
87027
88200
|
voiceMatchesTtsModel: () => voiceMatchesTtsModel,
|
|
87028
88201
|
voicesForTtsModel: () => voicesForTtsModel,
|
|
@@ -87030,7 +88203,8 @@ __export(dist_exports, {
|
|
|
87030
88203
|
withReviewSource: () => withReviewSource,
|
|
87031
88204
|
withoutNotChargedClaim: () => withoutNotChargedClaim,
|
|
87032
88205
|
withoutServerOnlySpendFields: () => withoutServerOnlySpendFields,
|
|
87033
|
-
withoutSurveyNotes: () => withoutSurveyNotes
|
|
88206
|
+
withoutSurveyNotes: () => withoutSurveyNotes,
|
|
88207
|
+
zaiWireModel: () => zaiWireModel
|
|
87034
88208
|
});
|
|
87035
88209
|
var init_dist = __esm({
|
|
87036
88210
|
"../shared/dist/index.js"() {
|
|
@@ -87072,6 +88246,7 @@ var init_dist = __esm({
|
|
|
87072
88246
|
init_admin_view_return_to();
|
|
87073
88247
|
init_auth_plan();
|
|
87074
88248
|
init_auth_block_detector();
|
|
88249
|
+
init_auth_session_stamp();
|
|
87075
88250
|
init_auth_state_freshness();
|
|
87076
88251
|
init_skip_coverage_detector();
|
|
87077
88252
|
init_feature_coverage();
|
|
@@ -87083,11 +88258,14 @@ var init_dist = __esm({
|
|
|
87083
88258
|
init_deepgram_voices();
|
|
87084
88259
|
init_feature_flags();
|
|
87085
88260
|
init_env_flags();
|
|
88261
|
+
init_visual_compare_limits();
|
|
88262
|
+
init_visual_baseline_identity();
|
|
87086
88263
|
init_analytics_url();
|
|
87087
88264
|
init_agentic_cli_runtime();
|
|
87088
88265
|
init_api_model_catalog();
|
|
87089
88266
|
init_engine_spec();
|
|
87090
88267
|
init_provider_chains();
|
|
88268
|
+
init_provider_accounts();
|
|
87091
88269
|
init_project_engine_overrides();
|
|
87092
88270
|
init_ai_profiles();
|
|
87093
88271
|
init_openrouter_usage();
|
|
@@ -87128,6 +88306,225 @@ var init_dist = __esm({
|
|
|
87128
88306
|
init_promotion_quality_gate();
|
|
87129
88307
|
init_regex_alternation();
|
|
87130
88308
|
init_page_evidence();
|
|
88309
|
+
init_trailing_slashes();
|
|
88310
|
+
init_stated_limits();
|
|
88311
|
+
}
|
|
88312
|
+
});
|
|
88313
|
+
|
|
88314
|
+
// ../runner-core/dist/services/harness-init-script.js
|
|
88315
|
+
var require_harness_init_script = __commonJS({
|
|
88316
|
+
"../runner-core/dist/services/harness-init-script.js"(exports2) {
|
|
88317
|
+
"use strict";
|
|
88318
|
+
Object.defineProperty(exports2, "__esModule", { value: true });
|
|
88319
|
+
exports2.HARNESS_INIT_SOURCE_URL = void 0;
|
|
88320
|
+
exports2.withHarnessSourceUrl = withHarnessSourceUrl;
|
|
88321
|
+
exports2.buildAnimationDisablingSource = buildAnimationDisablingSource;
|
|
88322
|
+
exports2.isHarnessInitLocation = isHarnessInitLocation;
|
|
88323
|
+
exports2.isHarnessInitErrorStack = isHarnessInitErrorStack;
|
|
88324
|
+
exports2.isHarnessInitConsoleLine = isHarnessInitConsoleLine;
|
|
88325
|
+
exports2.stripHarnessConsoleEntries = stripHarnessConsoleEntries;
|
|
88326
|
+
var node_crypto_1 = require("crypto");
|
|
88327
|
+
var shared_1 = (init_dist(), __toCommonJS(dist_exports));
|
|
88328
|
+
exports2.HARNESS_INIT_SOURCE_URL = `vqa-harness-init-${(0, node_crypto_1.randomBytes)(4).toString("hex")}.js`;
|
|
88329
|
+
var TRANSITION_LOOP_LIMIT = 8;
|
|
88330
|
+
var TRANSITION_LOOP_WINDOW_MS = 1e3;
|
|
88331
|
+
function withHarnessSourceUrl(content) {
|
|
88332
|
+
return `${content}
|
|
88333
|
+
//# sourceURL=${exports2.HARNESS_INIT_SOURCE_URL}`;
|
|
88334
|
+
}
|
|
88335
|
+
function buildAnimationDisablingSource(opts) {
|
|
88336
|
+
const finishTransitions = opts.finishTransitions ?? (0, shared_1.parseBoolFlag)(process.env.HARNESS_FINISH_CSS_TRANSITIONS);
|
|
88337
|
+
const css = finishTransitions ? "*, *::before, *::after { animation-duration: 0s !important; animation-delay: 0s !important; }" : "*, *::before, *::after { transition-duration: 0s !important; animation-duration: 0s !important; transition-delay: 0s !important; animation-delay: 0s !important; }";
|
|
88338
|
+
return withHarnessSourceUrl(`(() => {
|
|
88339
|
+
// Layer 1: CSS transitions and animations - instant, not removed
|
|
88340
|
+
// (duration 0s preserves final state; 'none' would prevent keyframes from completing)
|
|
88341
|
+
// The rule goes in a constructed stylesheet on document.adoptedStyleSheets, which adds no node to the DOM:
|
|
88342
|
+
// a <style> element changed what the test sees (locator('style') and 'head > *' counts, document.styleSheets,
|
|
88343
|
+
// an iframe's empty head), so a spec stock Playwright passes failed. The <style> is the fallback for a
|
|
88344
|
+
// browser with no constructable stylesheets.
|
|
88345
|
+
let adopted = false;
|
|
88346
|
+
try {
|
|
88347
|
+
if (typeof CSSStyleSheet === 'function' && typeof Document === 'function' && 'adoptedStyleSheets' in Document.prototype) {
|
|
88348
|
+
const sheet = new CSSStyleSheet();
|
|
88349
|
+
sheet.replaceSync(${JSON.stringify(css)});
|
|
88350
|
+
document.adoptedStyleSheets = [...document.adoptedStyleSheets, sheet];
|
|
88351
|
+
adopted = true;
|
|
88352
|
+
}
|
|
88353
|
+
} catch (e) {}
|
|
88354
|
+
if (!adopted) try {
|
|
88355
|
+
let applied = false;
|
|
88356
|
+
const apply = () => {
|
|
88357
|
+
if (applied) return true;
|
|
88358
|
+
const root = document.head || document.documentElement;
|
|
88359
|
+
if (!root) return false;
|
|
88360
|
+
const style = document.createElement('style');
|
|
88361
|
+
style.textContent = ${JSON.stringify(css)};
|
|
88362
|
+
root.appendChild(style);
|
|
88363
|
+
applied = true;
|
|
88364
|
+
return true;
|
|
88365
|
+
};
|
|
88366
|
+
if (!apply()) {
|
|
88367
|
+
// The document has no root element yet (iframe, about:blank, empty document): wait for it.
|
|
88368
|
+
let observer = null;
|
|
88369
|
+
const stop = () => { try { if (observer) observer.disconnect(); } catch (e) {} };
|
|
88370
|
+
const retry = () => { try { if (apply()) stop(); } catch (e) { stop(); } };
|
|
88371
|
+
try {
|
|
88372
|
+
observer = new MutationObserver(retry);
|
|
88373
|
+
observer.observe(document, { childList: true });
|
|
88374
|
+
} catch (e) {}
|
|
88375
|
+
document.addEventListener('readystatechange', retry);
|
|
88376
|
+
document.addEventListener('DOMContentLoaded', () => { retry(); stop(); }, { once: true });
|
|
88377
|
+
}
|
|
88378
|
+
} catch (e) {}
|
|
88379
|
+
${opts.hideWebdriver ? `
|
|
88380
|
+
try {
|
|
88381
|
+
Object.defineProperty(navigator, 'webdriver', { get: () => undefined });
|
|
88382
|
+
} catch (e) {}
|
|
88383
|
+
` : ""}
|
|
88384
|
+
${finishTransitions ? `
|
|
88385
|
+
// Layer 1b: CSS transitions run, and are finished as they start, so transitionend fires.
|
|
88386
|
+
// - finish() is deferred to a task: called inside the transitionrun dispatch (or a microtask of it) after a
|
|
88387
|
+
// real input event, Chromium finishes the transition but never fires its transitionstart/transitionend.
|
|
88388
|
+
// - setTimeout and performance.now are the ones present when this script runs, before the page's own
|
|
88389
|
+
// scripts: fake timers the page installs later cannot hold a finish back.
|
|
88390
|
+
// - The subtree is walked only for a pseudo-element's transition (its animations hang off the element).
|
|
88391
|
+
// - An element whose same transition restarts more than ${TRANSITION_LOOP_LIMIT} times within ${TRANSITION_LOOP_WINDOW_MS} ms (an app that starts it again on
|
|
88392
|
+
// each transitionend: carousel, pulse) is left to run at its own pace from then on, instead of cycling at
|
|
88393
|
+
// frame rate for the rest of the run.
|
|
88394
|
+
try {
|
|
88395
|
+
const st = setTimeout;
|
|
88396
|
+
const perf = typeof performance === 'object' && performance && typeof performance.now === 'function' ? performance : null;
|
|
88397
|
+
const now = perf ? perf.now.bind(perf) : Date.now;
|
|
88398
|
+
const seen = new WeakMap();
|
|
88399
|
+
const looping = (el, key) => {
|
|
88400
|
+
let byKey = seen.get(el);
|
|
88401
|
+
if (!byKey) { byKey = new Map(); seen.set(el, byKey); }
|
|
88402
|
+
const t = now();
|
|
88403
|
+
let s = byKey.get(key);
|
|
88404
|
+
if (s && s.loop) return true;
|
|
88405
|
+
if (!s || t - s.since > ${TRANSITION_LOOP_WINDOW_MS}) { s = { n: 0, since: t, loop: false }; byKey.set(key, s); }
|
|
88406
|
+
s.n += 1;
|
|
88407
|
+
if (s.n > ${TRANSITION_LOOP_LIMIT}) s.loop = true;
|
|
88408
|
+
return s.loop;
|
|
88409
|
+
};
|
|
88410
|
+
window.addEventListener('transitionrun', (ev) => {
|
|
88411
|
+
try {
|
|
88412
|
+
const el = ev && ev.target;
|
|
88413
|
+
if (!el || typeof el.getAnimations !== 'function' || typeof CSSTransition !== 'function') return;
|
|
88414
|
+
const pseudo = ev.pseudoElement || '';
|
|
88415
|
+
if (looping(el, ev.propertyName + '|' + pseudo)) return;
|
|
88416
|
+
for (const a of (pseudo ? el.getAnimations({ subtree: true }) : el.getAnimations())) {
|
|
88417
|
+
if (a instanceof CSSTransition && a.transitionProperty === ev.propertyName && a.effect
|
|
88418
|
+
&& a.effect.target === el && (a.effect.pseudoElement || '') === pseudo) {
|
|
88419
|
+
st(() => { try { a.finish(); } catch (e) {} }, 0);
|
|
88420
|
+
}
|
|
88421
|
+
}
|
|
88422
|
+
} catch (e) {}
|
|
88423
|
+
}, true);
|
|
88424
|
+
} catch (e) {}
|
|
88425
|
+
` : ""}
|
|
88426
|
+
// Layer 2: Web Animations API - make instant instead of no-op
|
|
88427
|
+
// (preserves animation completion callbacks that app code may depend on)
|
|
88428
|
+
try {
|
|
88429
|
+
const origAnimate = Element.prototype.animate;
|
|
88430
|
+
if (typeof origAnimate === 'function') {
|
|
88431
|
+
Element.prototype.animate = function (keyframes, options) {
|
|
88432
|
+
if (typeof options === 'object' && options !== null) {
|
|
88433
|
+
options = Object.assign({}, options, { duration: 0, delay: 0 });
|
|
88434
|
+
} else {
|
|
88435
|
+
options = 0; // covers number, undefined, and any other type
|
|
88436
|
+
}
|
|
88437
|
+
return origAnimate.call(this, keyframes, options);
|
|
88438
|
+
};
|
|
88439
|
+
}
|
|
88440
|
+
} catch (e) {}
|
|
88441
|
+
})();`);
|
|
88442
|
+
}
|
|
88443
|
+
function isHarnessInitLocation(url) {
|
|
88444
|
+
return url === exports2.HARNESS_INIT_SOURCE_URL;
|
|
88445
|
+
}
|
|
88446
|
+
var MAX_MATCHED_LINE_CHARS = 2048;
|
|
88447
|
+
var MAX_SCANNED_LINES = 200;
|
|
88448
|
+
var STACK_FRAME_RE = /^\s*at\s+(?:[^()\s][^()]*\()?([^()\s]+):\d+:\d+\)?\s*$/;
|
|
88449
|
+
function isHarnessInitErrorStack(stack) {
|
|
88450
|
+
if (!stack)
|
|
88451
|
+
return false;
|
|
88452
|
+
const lines = stack.split("\n", MAX_SCANNED_LINES);
|
|
88453
|
+
for (const line of lines) {
|
|
88454
|
+
if (line.length > MAX_MATCHED_LINE_CHARS)
|
|
88455
|
+
continue;
|
|
88456
|
+
const match = STACK_FRAME_RE.exec(line);
|
|
88457
|
+
if (match)
|
|
88458
|
+
return match[1] === exports2.HARNESS_INIT_SOURCE_URL;
|
|
88459
|
+
}
|
|
88460
|
+
return false;
|
|
88461
|
+
}
|
|
88462
|
+
var MCP_CONSOLE_LINE_LOCATION_RE = / @ ([^\s@]+):\d+$/;
|
|
88463
|
+
function isHarnessInitConsoleLine(line) {
|
|
88464
|
+
const trimmed = line.trim();
|
|
88465
|
+
if (trimmed.length > MAX_MATCHED_LINE_CHARS)
|
|
88466
|
+
return false;
|
|
88467
|
+
const match = MCP_CONSOLE_LINE_LOCATION_RE.exec(trimmed);
|
|
88468
|
+
return match !== null && match[1] === exports2.HARNESS_INIT_SOURCE_URL;
|
|
88469
|
+
}
|
|
88470
|
+
var MCP_LEVEL_LINE_RE = /^\s*(?:-\s+)?\[([A-Za-z]+)\]/;
|
|
88471
|
+
var MCP_FRAME_LINE_RE = /^\s+at\s/;
|
|
88472
|
+
var MCP_TOTALS_RE = /^(\s*Total messages:\s*)(\d+)(\s*\(Errors:\s*)(\d+)(,\s*Warnings:\s*)(\d+)(\).*)$/;
|
|
88473
|
+
var MCP_RETURNING_RE = /^(\s*Returning\s+)(\d+)(\s+messages\b.*)$/;
|
|
88474
|
+
function stripHarnessConsoleEntries(text) {
|
|
88475
|
+
if (!text.includes(exports2.HARNESS_INIT_SOURCE_URL))
|
|
88476
|
+
return text;
|
|
88477
|
+
const lines = text.split("\n");
|
|
88478
|
+
const out = [];
|
|
88479
|
+
let removed = 0;
|
|
88480
|
+
let removedErrors = 0;
|
|
88481
|
+
let removedWarnings = 0;
|
|
88482
|
+
let i = 0;
|
|
88483
|
+
while (i < lines.length) {
|
|
88484
|
+
const line = lines[i];
|
|
88485
|
+
const level = MCP_LEVEL_LINE_RE.exec(line);
|
|
88486
|
+
if (level && isHarnessInitConsoleLine(line.replace(/^\s*-\s+/, ""))) {
|
|
88487
|
+
removed++;
|
|
88488
|
+
const kind = level[1].toLowerCase();
|
|
88489
|
+
if (kind === "error")
|
|
88490
|
+
removedErrors++;
|
|
88491
|
+
else if (kind === "warning" || kind === "warn")
|
|
88492
|
+
removedWarnings++;
|
|
88493
|
+
i++;
|
|
88494
|
+
continue;
|
|
88495
|
+
}
|
|
88496
|
+
if (MCP_FRAME_LINE_RE.test(line)) {
|
|
88497
|
+
let end = i;
|
|
88498
|
+
while (end < lines.length && MCP_FRAME_LINE_RE.test(lines[end]))
|
|
88499
|
+
end++;
|
|
88500
|
+
const frames = lines.slice(i, end);
|
|
88501
|
+
if (isHarnessInitErrorStack(frames.join("\n"))) {
|
|
88502
|
+
const previous = out[out.length - 1];
|
|
88503
|
+
if (previous !== void 0 && previous.trim() !== "" && !/^\s*(?:#|Total messages|Returning)/.test(previous) && !MCP_LEVEL_LINE_RE.test(previous))
|
|
88504
|
+
out.pop();
|
|
88505
|
+
removed++;
|
|
88506
|
+
removedErrors++;
|
|
88507
|
+
} else {
|
|
88508
|
+
out.push(...frames);
|
|
88509
|
+
}
|
|
88510
|
+
i = end;
|
|
88511
|
+
continue;
|
|
88512
|
+
}
|
|
88513
|
+
out.push(line);
|
|
88514
|
+
i++;
|
|
88515
|
+
}
|
|
88516
|
+
if (removed === 0)
|
|
88517
|
+
return text;
|
|
88518
|
+
return out.map((line) => {
|
|
88519
|
+
const totals = MCP_TOTALS_RE.exec(line);
|
|
88520
|
+
if (totals) {
|
|
88521
|
+
const [, a, total, b, errors2, c, warnings, d] = totals;
|
|
88522
|
+
return `${a}${Math.max(0, +total - removed)}${b}${Math.max(0, +errors2 - removedErrors)}${c}${Math.max(0, +warnings - removedWarnings)}${d}`;
|
|
88523
|
+
}
|
|
88524
|
+
const returning = MCP_RETURNING_RE.exec(line);
|
|
88525
|
+
return returning ? `${returning[1]}${Math.max(0, +returning[2] - removed)}${returning[3]}` : line;
|
|
88526
|
+
}).join("\n");
|
|
88527
|
+
}
|
|
87131
88528
|
}
|
|
87132
88529
|
});
|
|
87133
88530
|
|