@validate.qa/runner 1.0.72 → 1.0.73
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/dist/cli.js +156 -45
- package/dist/cli.mjs +156 -45
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -5854,6 +5854,29 @@ function normalizeTtsVoiceId(voiceId) {
|
|
|
5854
5854
|
return null;
|
|
5855
5855
|
return LEGACY_TTS_VOICE_ID_MAP[trimmed] ?? trimmed;
|
|
5856
5856
|
}
|
|
5857
|
+
function normalizeTtsModel(model) {
|
|
5858
|
+
if (!model)
|
|
5859
|
+
return null;
|
|
5860
|
+
const trimmed = model.trim();
|
|
5861
|
+
if (!trimmed)
|
|
5862
|
+
return null;
|
|
5863
|
+
return LEGACY_TTS_MODEL_MAP[trimmed] ?? trimmed;
|
|
5864
|
+
}
|
|
5865
|
+
function ttsFallbackModel(primary) {
|
|
5866
|
+
const normalized = normalizeTtsModel(primary);
|
|
5867
|
+
if (!normalized)
|
|
5868
|
+
return null;
|
|
5869
|
+
return TTS_FALLBACK_MODEL_MAP[normalized] ?? null;
|
|
5870
|
+
}
|
|
5871
|
+
function resolveTtsModelChain(model) {
|
|
5872
|
+
const normalized = normalizeTtsModel(model);
|
|
5873
|
+
const primary = normalized && normalized in TTS_FALLBACK_MODEL_MAP ? normalized : DEFAULT_TTS_MODEL;
|
|
5874
|
+
const chain = [primary];
|
|
5875
|
+
const fallback = TTS_FALLBACK_MODEL_MAP[primary];
|
|
5876
|
+
if (fallback && fallback !== primary)
|
|
5877
|
+
chain.push(fallback);
|
|
5878
|
+
return chain;
|
|
5879
|
+
}
|
|
5857
5880
|
function sttModelsForProvider(provider) {
|
|
5858
5881
|
if (provider === "openai") {
|
|
5859
5882
|
return STT_MODEL_OPTIONS.filter((m) => m.provider === "openai");
|
|
@@ -5901,16 +5924,18 @@ function isValidTtsVoiceId(value) {
|
|
|
5901
5924
|
return TTS_VOICE_OPTIONS.some((v) => v.id === normalized);
|
|
5902
5925
|
}
|
|
5903
5926
|
function isValidTtsModel(value) {
|
|
5904
|
-
|
|
5927
|
+
const normalized = normalizeTtsModel(value);
|
|
5928
|
+
if (!normalized)
|
|
5905
5929
|
return false;
|
|
5906
|
-
return TTS_MODEL_OPTIONS.some((m) => m.id ===
|
|
5930
|
+
return TTS_MODEL_OPTIONS.some((m) => m.id === normalized);
|
|
5907
5931
|
}
|
|
5908
|
-
var VOICE_PREVIEW_SAMPLE, DEFAULT_TTS_MODEL, DEFAULT_TTS_VOICE_ID, DEFAULT_TTS_SPEED, LEGACY_TTS_VOICE_ID_MAP, DEFAULT_STT_MODEL_BY_PROVIDER, STT_PROVIDER_OPTIONS, STT_MODEL_OPTIONS, TTS_MODEL_OPTIONS, TTS_VOICE_OPTIONS;
|
|
5932
|
+
var VOICE_PREVIEW_SAMPLE, DEFAULT_TTS_MODEL, DEFAULT_TTS_TURBO_MODEL, DEFAULT_TTS_VOICE_ID, DEFAULT_TTS_SPEED, LEGACY_TTS_VOICE_ID_MAP, LEGACY_TTS_MODEL_MAP, TTS_FALLBACK_MODEL_MAP, DEFAULT_STT_MODEL_BY_PROVIDER, STT_PROVIDER_OPTIONS, STT_MODEL_OPTIONS, TTS_MODEL_OPTIONS, TTS_VOICE_OPTIONS;
|
|
5909
5933
|
var init_voice_config = __esm({
|
|
5910
5934
|
"../shared/dist/voice-config.js"() {
|
|
5911
5935
|
"use strict";
|
|
5912
5936
|
VOICE_PREVIEW_SAMPLE = "Hello! I am your Validate Copilot assistant. I can help you run tests, review failures, and generate new coverage for your project.";
|
|
5913
|
-
DEFAULT_TTS_MODEL = "speech-2.
|
|
5937
|
+
DEFAULT_TTS_MODEL = "speech-2.8-hd";
|
|
5938
|
+
DEFAULT_TTS_TURBO_MODEL = "speech-2.8-turbo";
|
|
5914
5939
|
DEFAULT_TTS_VOICE_ID = "English_Graceful_Lady";
|
|
5915
5940
|
DEFAULT_TTS_SPEED = 1;
|
|
5916
5941
|
LEGACY_TTS_VOICE_ID_MAP = {
|
|
@@ -5919,6 +5944,18 @@ var init_voice_config = __esm({
|
|
|
5919
5944
|
English_Deep_Voice_Man: "English_ManWithDeepVoice",
|
|
5920
5945
|
English_CasualMan: "English_Jovialman"
|
|
5921
5946
|
};
|
|
5947
|
+
LEGACY_TTS_MODEL_MAP = {
|
|
5948
|
+
"speech-2.6-hd": "speech-2.8-hd",
|
|
5949
|
+
"speech-2.6-turbo": "speech-2.8-turbo",
|
|
5950
|
+
"speech-02-hd": "speech-2.8-hd",
|
|
5951
|
+
"speech-02-turbo": "speech-2.8-turbo",
|
|
5952
|
+
"speech-01-hd": "speech-2.8-hd",
|
|
5953
|
+
"speech-01-turbo": "speech-2.8-turbo"
|
|
5954
|
+
};
|
|
5955
|
+
TTS_FALLBACK_MODEL_MAP = {
|
|
5956
|
+
"speech-2.8-hd": "speech-2.6-hd",
|
|
5957
|
+
"speech-2.8-turbo": "speech-2.6-turbo"
|
|
5958
|
+
};
|
|
5922
5959
|
DEFAULT_STT_MODEL_BY_PROVIDER = {
|
|
5923
5960
|
groq: "whisper-large-v3-turbo",
|
|
5924
5961
|
openai: "whisper-1"
|
|
@@ -5971,49 +6008,13 @@ var init_voice_config = __esm({
|
|
|
5971
6008
|
id: "speech-2.8-hd",
|
|
5972
6009
|
label: "Speech 2.8 HD",
|
|
5973
6010
|
provider: "minimax",
|
|
5974
|
-
description: "
|
|
6011
|
+
description: "High-definition quality (default). Auto-falls back to Speech 2.6 HD."
|
|
5975
6012
|
},
|
|
5976
6013
|
{
|
|
5977
6014
|
id: "speech-2.8-turbo",
|
|
5978
6015
|
label: "Speech 2.8 Turbo",
|
|
5979
6016
|
provider: "minimax",
|
|
5980
|
-
description: "
|
|
5981
|
-
},
|
|
5982
|
-
{
|
|
5983
|
-
id: "speech-2.6-hd",
|
|
5984
|
-
label: "Speech 2.6 HD",
|
|
5985
|
-
provider: "minimax",
|
|
5986
|
-
description: "High-definition MiniMax voice model."
|
|
5987
|
-
},
|
|
5988
|
-
{
|
|
5989
|
-
id: "speech-2.6-turbo",
|
|
5990
|
-
label: "Speech 2.6 Turbo",
|
|
5991
|
-
provider: "minimax",
|
|
5992
|
-
description: "Lower-latency Speech 2.6 variant."
|
|
5993
|
-
},
|
|
5994
|
-
{
|
|
5995
|
-
id: "speech-02-hd",
|
|
5996
|
-
label: "Speech 02 HD",
|
|
5997
|
-
provider: "minimax",
|
|
5998
|
-
description: "Previous-generation HD model."
|
|
5999
|
-
},
|
|
6000
|
-
{
|
|
6001
|
-
id: "speech-02-turbo",
|
|
6002
|
-
label: "Speech 02 Turbo",
|
|
6003
|
-
provider: "minimax",
|
|
6004
|
-
description: "Lower-latency Speech 02 variant."
|
|
6005
|
-
},
|
|
6006
|
-
{
|
|
6007
|
-
id: "speech-01-hd",
|
|
6008
|
-
label: "Speech 01 HD",
|
|
6009
|
-
provider: "minimax",
|
|
6010
|
-
description: "Legacy HD model."
|
|
6011
|
-
},
|
|
6012
|
-
{
|
|
6013
|
-
id: "speech-01-turbo",
|
|
6014
|
-
label: "Speech 01 Turbo",
|
|
6015
|
-
provider: "minimax",
|
|
6016
|
-
description: "Legacy fast model."
|
|
6017
|
+
description: "Lower latency. Auto-falls back to Speech 2.6 Turbo."
|
|
6017
6018
|
}
|
|
6018
6019
|
];
|
|
6019
6020
|
TTS_VOICE_OPTIONS = [
|
|
@@ -6297,6 +6298,7 @@ __export(dist_exports, {
|
|
|
6297
6298
|
DEFAULT_STT_MODEL_BY_PROVIDER: () => DEFAULT_STT_MODEL_BY_PROVIDER,
|
|
6298
6299
|
DEFAULT_TTS_MODEL: () => DEFAULT_TTS_MODEL,
|
|
6299
6300
|
DEFAULT_TTS_SPEED: () => DEFAULT_TTS_SPEED,
|
|
6301
|
+
DEFAULT_TTS_TURBO_MODEL: () => DEFAULT_TTS_TURBO_MODEL,
|
|
6300
6302
|
DEFAULT_TTS_VOICE_ID: () => DEFAULT_TTS_VOICE_ID,
|
|
6301
6303
|
DEFAULT_UI_VARIANT: () => DEFAULT_UI_VARIANT,
|
|
6302
6304
|
EMAIL_FROM_IDENTITIES: () => EMAIL_FROM_IDENTITIES,
|
|
@@ -6306,6 +6308,7 @@ __export(dist_exports, {
|
|
|
6306
6308
|
FLOW_SERVER_TYPES: () => FLOW_SERVER_TYPES,
|
|
6307
6309
|
GROUPABLE_CALL_TYPES: () => GROUPABLE_CALL_TYPES,
|
|
6308
6310
|
GROUP_LABELS: () => GROUP_LABELS,
|
|
6311
|
+
LEGACY_TTS_MODEL_MAP: () => LEGACY_TTS_MODEL_MAP,
|
|
6309
6312
|
LEGACY_TTS_VOICE_ID_MAP: () => LEGACY_TTS_VOICE_ID_MAP,
|
|
6310
6313
|
MAX_CREDIT_TOPUP_CENTS: () => MAX_CREDIT_TOPUP_CENTS,
|
|
6311
6314
|
MAX_DEEPLINK_LENGTH: () => MAX_DEEPLINK_LENGTH,
|
|
@@ -6339,6 +6342,7 @@ __export(dist_exports, {
|
|
|
6339
6342
|
TEST_USER_ENV_KEYS: () => TEST_USER_ENV_KEYS,
|
|
6340
6343
|
TRANSIENT_CONTROL_ROLES: () => TRANSIENT_CONTROL_ROLES,
|
|
6341
6344
|
TRIAL_DURATION_DAYS: () => TRIAL_DURATION_DAYS,
|
|
6345
|
+
TTS_FALLBACK_MODEL_MAP: () => TTS_FALLBACK_MODEL_MAP,
|
|
6342
6346
|
TTS_MODEL_OPTIONS: () => TTS_MODEL_OPTIONS,
|
|
6343
6347
|
TTS_VOICE_OPTIONS: () => TTS_VOICE_OPTIONS,
|
|
6344
6348
|
UI_VARIANTS: () => UI_VARIANTS,
|
|
@@ -6441,6 +6445,7 @@ __export(dist_exports, {
|
|
|
6441
6445
|
mobilePlatformFromMedium: () => mobilePlatformFromMedium,
|
|
6442
6446
|
mobileWanderTraceEnabled: () => mobileWanderTraceEnabled,
|
|
6443
6447
|
normalizeControlName: () => normalizeControlName,
|
|
6448
|
+
normalizeTtsModel: () => normalizeTtsModel,
|
|
6444
6449
|
normalizeTtsVoiceId: () => normalizeTtsVoiceId,
|
|
6445
6450
|
otherMobilePlatform: () => otherMobilePlatform,
|
|
6446
6451
|
parenDepthDelta: () => parenDepthDelta,
|
|
@@ -6459,6 +6464,7 @@ __export(dist_exports, {
|
|
|
6459
6464
|
resolveMobileStepValuePlaceholders: () => resolveMobileStepValuePlaceholders,
|
|
6460
6465
|
resolvePlatformLocatorBundle: () => resolvePlatformLocatorBundle,
|
|
6461
6466
|
resolveSttModelForProvider: () => resolveSttModelForProvider,
|
|
6467
|
+
resolveTtsModelChain: () => resolveTtsModelChain,
|
|
6462
6468
|
safeCurrentUrl: () => safeCurrentUrl,
|
|
6463
6469
|
safeOrigin: () => safeOrigin,
|
|
6464
6470
|
sanitizeSttErrorMessage: () => sanitizeSttErrorMessage,
|
|
@@ -6481,6 +6487,7 @@ __export(dist_exports, {
|
|
|
6481
6487
|
summarizeMobileReadiness: () => summarizeMobileReadiness,
|
|
6482
6488
|
summarizeRunHealth: () => summarizeRunHealth,
|
|
6483
6489
|
toDbPricingPlan: () => toDbPricingPlan,
|
|
6490
|
+
ttsFallbackModel: () => ttsFallbackModel,
|
|
6484
6491
|
validateAssertionStrength: () => validateAssertionStrength
|
|
6485
6492
|
});
|
|
6486
6493
|
var init_dist = __esm({
|
|
@@ -353007,7 +353014,7 @@ var require_package4 = __commonJS({
|
|
|
353007
353014
|
"package.json"(exports2, module2) {
|
|
353008
353015
|
module2.exports = {
|
|
353009
353016
|
name: "@validate.qa/runner",
|
|
353010
|
-
version: "1.0.
|
|
353017
|
+
version: "1.0.73",
|
|
353011
353018
|
description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
|
|
353012
353019
|
bin: {
|
|
353013
353020
|
"validate-runner": "dist/cli.js"
|
|
@@ -354671,6 +354678,27 @@ async function clickCssInCurrentContext(sessionPath, css) {
|
|
|
354671
354678
|
body: "{}"
|
|
354672
354679
|
});
|
|
354673
354680
|
}
|
|
354681
|
+
async function clickByVisibleTextInCurrentContext(sessionPath, text) {
|
|
354682
|
+
const script = `
|
|
354683
|
+
var t = String(arguments[0]).trim().replace(/\\s+/g, ' ');
|
|
354684
|
+
var sel = 'button, a, [role="tab"], [role="button"], [onclick], .stream-tab, .ux-interactive, input[type="submit"], input[type="button"]';
|
|
354685
|
+
var norm = function (e) { return (e.textContent || e.value || '').trim().replace(/\\s+/g, ' '); };
|
|
354686
|
+
var vis = function (e) { var r = e.getBoundingClientRect(); return r.width > 0 && r.height > 0; };
|
|
354687
|
+
var all = Array.prototype.slice.call(document.querySelectorAll(sel));
|
|
354688
|
+
var match = all.filter(function (e) { return norm(e) === t && vis(e); });
|
|
354689
|
+
if (match.length !== 1) { return match.length; }
|
|
354690
|
+
match[0].click();
|
|
354691
|
+
return 1;
|
|
354692
|
+
`;
|
|
354693
|
+
const result = await appiumRequest(`${sessionPath}/execute/sync`, {
|
|
354694
|
+
method: "POST",
|
|
354695
|
+
body: JSON.stringify({ script, args: [text] })
|
|
354696
|
+
});
|
|
354697
|
+
const count = readValue(result);
|
|
354698
|
+
if (count !== 1) {
|
|
354699
|
+
throw new Error(`WEBVIEW text click found ${count === 0 || count === void 0 ? "no" : String(count)} actionable match(es) for "${text}"`);
|
|
354700
|
+
}
|
|
354701
|
+
}
|
|
354674
354702
|
async function typeCssInCurrentContext(sessionPath, css, text) {
|
|
354675
354703
|
const elResult = await appiumRequest(`${sessionPath}/element`, {
|
|
354676
354704
|
method: "POST",
|
|
@@ -357029,6 +357057,48 @@ function stepWebViewContext(step) {
|
|
|
357029
357057
|
const meta = step.metadata && typeof step.metadata === "object" ? step.metadata : null;
|
|
357030
357058
|
return typeof meta?.webviewContext === "string" && meta.webviewContext.trim() ? meta.webviewContext.trim() : null;
|
|
357031
357059
|
}
|
|
357060
|
+
var DOM_ID_RE = /^[A-Za-z_][\w-]*$/;
|
|
357061
|
+
var SYSTEM_RESOURCE_ID_RE = /^(?:android|com\.android\.|com\.google\.android\.)/i;
|
|
357062
|
+
function webViewCssFallbackFromNativeStep(step) {
|
|
357063
|
+
if (stepWebViewCss(step)) return null;
|
|
357064
|
+
const target = step.target;
|
|
357065
|
+
if (!target) return null;
|
|
357066
|
+
const bundle = target.locatorBundle;
|
|
357067
|
+
const resourceId = typeof bundle?.resourceId === "string" ? bundle.resourceId.trim() : "";
|
|
357068
|
+
const accessibilityId = typeof bundle?.accessibilityId === "string" ? bundle.accessibilityId.trim() : "";
|
|
357069
|
+
const primary = typeof target.primary === "string" ? target.primary.trim() : "";
|
|
357070
|
+
const fromResourceId = (raw) => {
|
|
357071
|
+
if (!raw) return null;
|
|
357072
|
+
if (raw.includes(":id/")) {
|
|
357073
|
+
if (SYSTEM_RESOURCE_ID_RE.test(raw)) return null;
|
|
357074
|
+
const local = raw.slice(raw.indexOf(":id/") + 4);
|
|
357075
|
+
return DOM_ID_RE.test(local) ? local : null;
|
|
357076
|
+
}
|
|
357077
|
+
return DOM_ID_RE.test(raw) ? raw : null;
|
|
357078
|
+
};
|
|
357079
|
+
const domId = fromResourceId(resourceId) ?? fromResourceId(accessibilityId) ?? (primary && !/[=~/[\].\s]/.test(primary) && DOM_ID_RE.test(primary) ? primary : null);
|
|
357080
|
+
return domId ? `#${domId}` : null;
|
|
357081
|
+
}
|
|
357082
|
+
function webViewTextFallbackFromNativeStep(step) {
|
|
357083
|
+
if (stepWebViewCss(step)) return null;
|
|
357084
|
+
if (step.action !== "tap") return null;
|
|
357085
|
+
const target = step.target;
|
|
357086
|
+
if (!target) return null;
|
|
357087
|
+
const bundle = target.locatorBundle;
|
|
357088
|
+
const text = typeof bundle?.text === "string" && bundle.text.trim() ? bundle.text.trim() : typeof bundle?.contentDesc === "string" && bundle.contentDesc.trim() ? bundle.contentDesc.trim() : typeof target.primary === "string" && target.primary.trim() && !/[=~/[\]]|:id\//.test(target.primary) ? target.primary.trim() : "";
|
|
357089
|
+
const normalized = text.replace(/\s+/g, " ");
|
|
357090
|
+
if (!normalized || normalized.length > 40 || /[\n\r]/.test(text)) return null;
|
|
357091
|
+
if (SYSTEM_PERMISSION_BUTTON_RE.test(text)) return null;
|
|
357092
|
+
return normalized;
|
|
357093
|
+
}
|
|
357094
|
+
async function hasLiveWebViewContext(sessionId) {
|
|
357095
|
+
try {
|
|
357096
|
+
const contexts = await listAppContexts(`/session/${sessionId}`);
|
|
357097
|
+
return contexts.some((c) => /^WEBVIEW/i.test(c));
|
|
357098
|
+
} catch {
|
|
357099
|
+
return false;
|
|
357100
|
+
}
|
|
357101
|
+
}
|
|
357032
357102
|
var CONTAINER_ONLY_ENTRY_ID_RE = /(?:^|[:/])id\/(webview|content|decor|decor_content_parent|action_bar_root|statusBarBackground|navigationBarBackground)$|^(?:main-content|root|app|app-root|__next|react-root|application)$/i;
|
|
357033
357103
|
function isContainerOnlyEntryTarget(target) {
|
|
357034
357104
|
const primary = target?.primary?.trim() ?? "";
|
|
@@ -357116,6 +357186,7 @@ function isWebViewHydrationTransient(err) {
|
|
|
357116
357186
|
return /no such element|NoSuchElement|element not interactable|stale element|WEBVIEW step requires|Empty page dictionary|not connectable|no WEBVIEW context|chrome not reachable/i.test(message);
|
|
357117
357187
|
}
|
|
357118
357188
|
var WEBVIEW_HYDRATION_TIMEOUT_MS = Number(process.env.VALIDATEQA_WEBVIEW_HYDRATION_TIMEOUT_MS) || 3e4;
|
|
357189
|
+
var PERMISSION_DIALOG_TIMEOUT_MS = Number(process.env.VALIDATEQA_PERMISSION_DIALOG_TIMEOUT_MS) || 3e3;
|
|
357119
357190
|
async function executeInWebViewContextWithHydrationRetry(sessionId, step, css, body, timeoutMs) {
|
|
357120
357191
|
const deadline = Date.now() + Math.max(1e3, timeoutMs);
|
|
357121
357192
|
for (; ; ) {
|
|
@@ -357128,6 +357199,17 @@ async function executeInWebViewContextWithHydrationRetry(sessionId, step, css, b
|
|
|
357128
357199
|
}
|
|
357129
357200
|
}
|
|
357130
357201
|
}
|
|
357202
|
+
var SYSTEM_PERMISSION_BUTTON_RE = /com\.android\.permissioncontroller:id\/permission_(allow|deny)|com\.android\.packageinstaller:id\/permission_|:id\/permission_allow_(foreground_only|one_time)_button|^(?:com\.apple\.springboard|SpringBoard)/i;
|
|
357203
|
+
function isSystemPermissionButtonTarget(target) {
|
|
357204
|
+
if (!target) return false;
|
|
357205
|
+
const bundle = target.locatorBundle;
|
|
357206
|
+
const candidates = [
|
|
357207
|
+
target.primary,
|
|
357208
|
+
typeof bundle?.resourceId === "string" ? bundle.resourceId : "",
|
|
357209
|
+
typeof bundle?.xpath === "string" ? bundle.xpath : ""
|
|
357210
|
+
];
|
|
357211
|
+
return candidates.some((c) => typeof c === "string" && SYSTEM_PERMISSION_BUTTON_RE.test(c));
|
|
357212
|
+
}
|
|
357131
357213
|
async function executeTap(sessionId, step, platform3, isCrossPlatform = false) {
|
|
357132
357214
|
const webCss = stepWebViewCss(step);
|
|
357133
357215
|
if (webCss) {
|
|
@@ -357140,10 +357222,11 @@ async function executeTap(sessionId, step, platform3, isCrossPlatform = false) {
|
|
|
357140
357222
|
);
|
|
357141
357223
|
return;
|
|
357142
357224
|
}
|
|
357225
|
+
const isPermissionTap = isSystemPermissionButtonTarget(step.target);
|
|
357143
357226
|
const bounds = boundsForRun(step, platform3, isCrossPlatform);
|
|
357144
357227
|
if (step.target) {
|
|
357145
357228
|
try {
|
|
357146
|
-
const elementId = await findElement(sessionId, step.target, readStepTimeout(step), {
|
|
357229
|
+
const elementId = await findElement(sessionId, step.target, isPermissionTap ? Math.min(readStepTimeout(step) ?? DEFAULT_STEP_TIMEOUT_MS, PERMISSION_DIALOG_TIMEOUT_MS) : readStepTimeout(step), {
|
|
357147
357230
|
platform: platform3,
|
|
357148
357231
|
recordedBounds: bounds
|
|
357149
357232
|
});
|
|
@@ -357153,7 +357236,23 @@ async function executeTap(sessionId, step, platform3, isCrossPlatform = false) {
|
|
|
357153
357236
|
});
|
|
357154
357237
|
return;
|
|
357155
357238
|
} catch (error2) {
|
|
357156
|
-
if (isTransportError(error2) ||
|
|
357239
|
+
if (isTransportError(error2) || error2 instanceof MobileAmbiguousMatchError) throw error2;
|
|
357240
|
+
if (isPermissionTap) return;
|
|
357241
|
+
const cssFallback = webViewCssFallbackFromNativeStep(step);
|
|
357242
|
+
const textFallback = cssFallback ? null : webViewTextFallbackFromNativeStep(step);
|
|
357243
|
+
if ((cssFallback || textFallback) && await hasLiveWebViewContext(sessionId)) {
|
|
357244
|
+
try {
|
|
357245
|
+
if (cssFallback) {
|
|
357246
|
+
await executeInWebViewContext(sessionId, step, cssFallback, (sessionPath, css) => clickCssInCurrentContext(sessionPath, css));
|
|
357247
|
+
} else if (textFallback) {
|
|
357248
|
+
await executeInWebViewContext(sessionId, step, textFallback, (sessionPath) => clickByVisibleTextInCurrentContext(sessionPath, textFallback));
|
|
357249
|
+
}
|
|
357250
|
+
return;
|
|
357251
|
+
} catch (webErr) {
|
|
357252
|
+
if (isTransportError(webErr)) throw webErr;
|
|
357253
|
+
}
|
|
357254
|
+
}
|
|
357255
|
+
if (!bounds || buildLocatorStrategies(step.target, platform3).length > 0) throw error2;
|
|
357157
357256
|
}
|
|
357158
357257
|
}
|
|
357159
357258
|
if (!bounds) {
|
|
@@ -357211,6 +357310,18 @@ async function executeType(sessionId, step, context) {
|
|
|
357211
357310
|
return;
|
|
357212
357311
|
} catch (error2) {
|
|
357213
357312
|
if (isTransportError(error2)) throw error2;
|
|
357313
|
+
if (!focusEstablished && !keyboardSubmitOnly) {
|
|
357314
|
+
const cssFallback = webViewCssFallbackFromNativeStep(step);
|
|
357315
|
+
if (cssFallback && await hasLiveWebViewContext(sessionId)) {
|
|
357316
|
+
try {
|
|
357317
|
+
context.log?.(` Native locate failed; retrying as WebView ${cssFallback} (hybrid mirror fallback)`);
|
|
357318
|
+
await executeInWebViewContext(sessionId, step, cssFallback, (sessionPath2, css) => typeCssInCurrentContext(sessionPath2, css, value));
|
|
357319
|
+
return;
|
|
357320
|
+
} catch (webErr) {
|
|
357321
|
+
if (isTransportError(webErr)) throw webErr;
|
|
357322
|
+
}
|
|
357323
|
+
}
|
|
357324
|
+
}
|
|
357214
357325
|
if (context.platform === "ANDROID" && focusEstablished) {
|
|
357215
357326
|
try {
|
|
357216
357327
|
context.log?.(" Appium active-element send failed; using Android focused-keyboard input fallback");
|
package/dist/cli.mjs
CHANGED
|
@@ -5859,6 +5859,29 @@ function normalizeTtsVoiceId(voiceId) {
|
|
|
5859
5859
|
return null;
|
|
5860
5860
|
return LEGACY_TTS_VOICE_ID_MAP[trimmed] ?? trimmed;
|
|
5861
5861
|
}
|
|
5862
|
+
function normalizeTtsModel(model) {
|
|
5863
|
+
if (!model)
|
|
5864
|
+
return null;
|
|
5865
|
+
const trimmed = model.trim();
|
|
5866
|
+
if (!trimmed)
|
|
5867
|
+
return null;
|
|
5868
|
+
return LEGACY_TTS_MODEL_MAP[trimmed] ?? trimmed;
|
|
5869
|
+
}
|
|
5870
|
+
function ttsFallbackModel(primary) {
|
|
5871
|
+
const normalized = normalizeTtsModel(primary);
|
|
5872
|
+
if (!normalized)
|
|
5873
|
+
return null;
|
|
5874
|
+
return TTS_FALLBACK_MODEL_MAP[normalized] ?? null;
|
|
5875
|
+
}
|
|
5876
|
+
function resolveTtsModelChain(model) {
|
|
5877
|
+
const normalized = normalizeTtsModel(model);
|
|
5878
|
+
const primary = normalized && normalized in TTS_FALLBACK_MODEL_MAP ? normalized : DEFAULT_TTS_MODEL;
|
|
5879
|
+
const chain = [primary];
|
|
5880
|
+
const fallback = TTS_FALLBACK_MODEL_MAP[primary];
|
|
5881
|
+
if (fallback && fallback !== primary)
|
|
5882
|
+
chain.push(fallback);
|
|
5883
|
+
return chain;
|
|
5884
|
+
}
|
|
5862
5885
|
function sttModelsForProvider(provider) {
|
|
5863
5886
|
if (provider === "openai") {
|
|
5864
5887
|
return STT_MODEL_OPTIONS.filter((m) => m.provider === "openai");
|
|
@@ -5906,16 +5929,18 @@ function isValidTtsVoiceId(value) {
|
|
|
5906
5929
|
return TTS_VOICE_OPTIONS.some((v) => v.id === normalized);
|
|
5907
5930
|
}
|
|
5908
5931
|
function isValidTtsModel(value) {
|
|
5909
|
-
|
|
5932
|
+
const normalized = normalizeTtsModel(value);
|
|
5933
|
+
if (!normalized)
|
|
5910
5934
|
return false;
|
|
5911
|
-
return TTS_MODEL_OPTIONS.some((m) => m.id ===
|
|
5935
|
+
return TTS_MODEL_OPTIONS.some((m) => m.id === normalized);
|
|
5912
5936
|
}
|
|
5913
|
-
var VOICE_PREVIEW_SAMPLE, DEFAULT_TTS_MODEL, DEFAULT_TTS_VOICE_ID, DEFAULT_TTS_SPEED, LEGACY_TTS_VOICE_ID_MAP, DEFAULT_STT_MODEL_BY_PROVIDER, STT_PROVIDER_OPTIONS, STT_MODEL_OPTIONS, TTS_MODEL_OPTIONS, TTS_VOICE_OPTIONS;
|
|
5937
|
+
var VOICE_PREVIEW_SAMPLE, DEFAULT_TTS_MODEL, DEFAULT_TTS_TURBO_MODEL, DEFAULT_TTS_VOICE_ID, DEFAULT_TTS_SPEED, LEGACY_TTS_VOICE_ID_MAP, LEGACY_TTS_MODEL_MAP, TTS_FALLBACK_MODEL_MAP, DEFAULT_STT_MODEL_BY_PROVIDER, STT_PROVIDER_OPTIONS, STT_MODEL_OPTIONS, TTS_MODEL_OPTIONS, TTS_VOICE_OPTIONS;
|
|
5914
5938
|
var init_voice_config = __esm({
|
|
5915
5939
|
"../shared/dist/voice-config.js"() {
|
|
5916
5940
|
"use strict";
|
|
5917
5941
|
VOICE_PREVIEW_SAMPLE = "Hello! I am your Validate Copilot assistant. I can help you run tests, review failures, and generate new coverage for your project.";
|
|
5918
|
-
DEFAULT_TTS_MODEL = "speech-2.
|
|
5942
|
+
DEFAULT_TTS_MODEL = "speech-2.8-hd";
|
|
5943
|
+
DEFAULT_TTS_TURBO_MODEL = "speech-2.8-turbo";
|
|
5919
5944
|
DEFAULT_TTS_VOICE_ID = "English_Graceful_Lady";
|
|
5920
5945
|
DEFAULT_TTS_SPEED = 1;
|
|
5921
5946
|
LEGACY_TTS_VOICE_ID_MAP = {
|
|
@@ -5924,6 +5949,18 @@ var init_voice_config = __esm({
|
|
|
5924
5949
|
English_Deep_Voice_Man: "English_ManWithDeepVoice",
|
|
5925
5950
|
English_CasualMan: "English_Jovialman"
|
|
5926
5951
|
};
|
|
5952
|
+
LEGACY_TTS_MODEL_MAP = {
|
|
5953
|
+
"speech-2.6-hd": "speech-2.8-hd",
|
|
5954
|
+
"speech-2.6-turbo": "speech-2.8-turbo",
|
|
5955
|
+
"speech-02-hd": "speech-2.8-hd",
|
|
5956
|
+
"speech-02-turbo": "speech-2.8-turbo",
|
|
5957
|
+
"speech-01-hd": "speech-2.8-hd",
|
|
5958
|
+
"speech-01-turbo": "speech-2.8-turbo"
|
|
5959
|
+
};
|
|
5960
|
+
TTS_FALLBACK_MODEL_MAP = {
|
|
5961
|
+
"speech-2.8-hd": "speech-2.6-hd",
|
|
5962
|
+
"speech-2.8-turbo": "speech-2.6-turbo"
|
|
5963
|
+
};
|
|
5927
5964
|
DEFAULT_STT_MODEL_BY_PROVIDER = {
|
|
5928
5965
|
groq: "whisper-large-v3-turbo",
|
|
5929
5966
|
openai: "whisper-1"
|
|
@@ -5976,49 +6013,13 @@ var init_voice_config = __esm({
|
|
|
5976
6013
|
id: "speech-2.8-hd",
|
|
5977
6014
|
label: "Speech 2.8 HD",
|
|
5978
6015
|
provider: "minimax",
|
|
5979
|
-
description: "
|
|
6016
|
+
description: "High-definition quality (default). Auto-falls back to Speech 2.6 HD."
|
|
5980
6017
|
},
|
|
5981
6018
|
{
|
|
5982
6019
|
id: "speech-2.8-turbo",
|
|
5983
6020
|
label: "Speech 2.8 Turbo",
|
|
5984
6021
|
provider: "minimax",
|
|
5985
|
-
description: "
|
|
5986
|
-
},
|
|
5987
|
-
{
|
|
5988
|
-
id: "speech-2.6-hd",
|
|
5989
|
-
label: "Speech 2.6 HD",
|
|
5990
|
-
provider: "minimax",
|
|
5991
|
-
description: "High-definition MiniMax voice model."
|
|
5992
|
-
},
|
|
5993
|
-
{
|
|
5994
|
-
id: "speech-2.6-turbo",
|
|
5995
|
-
label: "Speech 2.6 Turbo",
|
|
5996
|
-
provider: "minimax",
|
|
5997
|
-
description: "Lower-latency Speech 2.6 variant."
|
|
5998
|
-
},
|
|
5999
|
-
{
|
|
6000
|
-
id: "speech-02-hd",
|
|
6001
|
-
label: "Speech 02 HD",
|
|
6002
|
-
provider: "minimax",
|
|
6003
|
-
description: "Previous-generation HD model."
|
|
6004
|
-
},
|
|
6005
|
-
{
|
|
6006
|
-
id: "speech-02-turbo",
|
|
6007
|
-
label: "Speech 02 Turbo",
|
|
6008
|
-
provider: "minimax",
|
|
6009
|
-
description: "Lower-latency Speech 02 variant."
|
|
6010
|
-
},
|
|
6011
|
-
{
|
|
6012
|
-
id: "speech-01-hd",
|
|
6013
|
-
label: "Speech 01 HD",
|
|
6014
|
-
provider: "minimax",
|
|
6015
|
-
description: "Legacy HD model."
|
|
6016
|
-
},
|
|
6017
|
-
{
|
|
6018
|
-
id: "speech-01-turbo",
|
|
6019
|
-
label: "Speech 01 Turbo",
|
|
6020
|
-
provider: "minimax",
|
|
6021
|
-
description: "Legacy fast model."
|
|
6022
|
+
description: "Lower latency. Auto-falls back to Speech 2.6 Turbo."
|
|
6022
6023
|
}
|
|
6023
6024
|
];
|
|
6024
6025
|
TTS_VOICE_OPTIONS = [
|
|
@@ -6302,6 +6303,7 @@ __export(dist_exports, {
|
|
|
6302
6303
|
DEFAULT_STT_MODEL_BY_PROVIDER: () => DEFAULT_STT_MODEL_BY_PROVIDER,
|
|
6303
6304
|
DEFAULT_TTS_MODEL: () => DEFAULT_TTS_MODEL,
|
|
6304
6305
|
DEFAULT_TTS_SPEED: () => DEFAULT_TTS_SPEED,
|
|
6306
|
+
DEFAULT_TTS_TURBO_MODEL: () => DEFAULT_TTS_TURBO_MODEL,
|
|
6305
6307
|
DEFAULT_TTS_VOICE_ID: () => DEFAULT_TTS_VOICE_ID,
|
|
6306
6308
|
DEFAULT_UI_VARIANT: () => DEFAULT_UI_VARIANT,
|
|
6307
6309
|
EMAIL_FROM_IDENTITIES: () => EMAIL_FROM_IDENTITIES,
|
|
@@ -6311,6 +6313,7 @@ __export(dist_exports, {
|
|
|
6311
6313
|
FLOW_SERVER_TYPES: () => FLOW_SERVER_TYPES,
|
|
6312
6314
|
GROUPABLE_CALL_TYPES: () => GROUPABLE_CALL_TYPES,
|
|
6313
6315
|
GROUP_LABELS: () => GROUP_LABELS,
|
|
6316
|
+
LEGACY_TTS_MODEL_MAP: () => LEGACY_TTS_MODEL_MAP,
|
|
6314
6317
|
LEGACY_TTS_VOICE_ID_MAP: () => LEGACY_TTS_VOICE_ID_MAP,
|
|
6315
6318
|
MAX_CREDIT_TOPUP_CENTS: () => MAX_CREDIT_TOPUP_CENTS,
|
|
6316
6319
|
MAX_DEEPLINK_LENGTH: () => MAX_DEEPLINK_LENGTH,
|
|
@@ -6344,6 +6347,7 @@ __export(dist_exports, {
|
|
|
6344
6347
|
TEST_USER_ENV_KEYS: () => TEST_USER_ENV_KEYS,
|
|
6345
6348
|
TRANSIENT_CONTROL_ROLES: () => TRANSIENT_CONTROL_ROLES,
|
|
6346
6349
|
TRIAL_DURATION_DAYS: () => TRIAL_DURATION_DAYS,
|
|
6350
|
+
TTS_FALLBACK_MODEL_MAP: () => TTS_FALLBACK_MODEL_MAP,
|
|
6347
6351
|
TTS_MODEL_OPTIONS: () => TTS_MODEL_OPTIONS,
|
|
6348
6352
|
TTS_VOICE_OPTIONS: () => TTS_VOICE_OPTIONS,
|
|
6349
6353
|
UI_VARIANTS: () => UI_VARIANTS,
|
|
@@ -6446,6 +6450,7 @@ __export(dist_exports, {
|
|
|
6446
6450
|
mobilePlatformFromMedium: () => mobilePlatformFromMedium,
|
|
6447
6451
|
mobileWanderTraceEnabled: () => mobileWanderTraceEnabled,
|
|
6448
6452
|
normalizeControlName: () => normalizeControlName,
|
|
6453
|
+
normalizeTtsModel: () => normalizeTtsModel,
|
|
6449
6454
|
normalizeTtsVoiceId: () => normalizeTtsVoiceId,
|
|
6450
6455
|
otherMobilePlatform: () => otherMobilePlatform,
|
|
6451
6456
|
parenDepthDelta: () => parenDepthDelta,
|
|
@@ -6464,6 +6469,7 @@ __export(dist_exports, {
|
|
|
6464
6469
|
resolveMobileStepValuePlaceholders: () => resolveMobileStepValuePlaceholders,
|
|
6465
6470
|
resolvePlatformLocatorBundle: () => resolvePlatformLocatorBundle,
|
|
6466
6471
|
resolveSttModelForProvider: () => resolveSttModelForProvider,
|
|
6472
|
+
resolveTtsModelChain: () => resolveTtsModelChain,
|
|
6467
6473
|
safeCurrentUrl: () => safeCurrentUrl,
|
|
6468
6474
|
safeOrigin: () => safeOrigin,
|
|
6469
6475
|
sanitizeSttErrorMessage: () => sanitizeSttErrorMessage,
|
|
@@ -6486,6 +6492,7 @@ __export(dist_exports, {
|
|
|
6486
6492
|
summarizeMobileReadiness: () => summarizeMobileReadiness,
|
|
6487
6493
|
summarizeRunHealth: () => summarizeRunHealth,
|
|
6488
6494
|
toDbPricingPlan: () => toDbPricingPlan,
|
|
6495
|
+
ttsFallbackModel: () => ttsFallbackModel,
|
|
6489
6496
|
validateAssertionStrength: () => validateAssertionStrength
|
|
6490
6497
|
});
|
|
6491
6498
|
var init_dist = __esm({
|
|
@@ -353012,7 +353019,7 @@ var require_package4 = __commonJS({
|
|
|
353012
353019
|
"package.json"(exports, module) {
|
|
353013
353020
|
module.exports = {
|
|
353014
353021
|
name: "@validate.qa/runner",
|
|
353015
|
-
version: "1.0.
|
|
353022
|
+
version: "1.0.73",
|
|
353016
353023
|
description: "validate local test runner - execute Playwright tests on your machine, connected to validate.qa cloud.",
|
|
353017
353024
|
bin: {
|
|
353018
353025
|
"validate-runner": "dist/cli.js"
|
|
@@ -354676,6 +354683,27 @@ async function clickCssInCurrentContext(sessionPath, css) {
|
|
|
354676
354683
|
body: "{}"
|
|
354677
354684
|
});
|
|
354678
354685
|
}
|
|
354686
|
+
async function clickByVisibleTextInCurrentContext(sessionPath, text) {
|
|
354687
|
+
const script = `
|
|
354688
|
+
var t = String(arguments[0]).trim().replace(/\\s+/g, ' ');
|
|
354689
|
+
var sel = 'button, a, [role="tab"], [role="button"], [onclick], .stream-tab, .ux-interactive, input[type="submit"], input[type="button"]';
|
|
354690
|
+
var norm = function (e) { return (e.textContent || e.value || '').trim().replace(/\\s+/g, ' '); };
|
|
354691
|
+
var vis = function (e) { var r = e.getBoundingClientRect(); return r.width > 0 && r.height > 0; };
|
|
354692
|
+
var all = Array.prototype.slice.call(document.querySelectorAll(sel));
|
|
354693
|
+
var match = all.filter(function (e) { return norm(e) === t && vis(e); });
|
|
354694
|
+
if (match.length !== 1) { return match.length; }
|
|
354695
|
+
match[0].click();
|
|
354696
|
+
return 1;
|
|
354697
|
+
`;
|
|
354698
|
+
const result = await appiumRequest(`${sessionPath}/execute/sync`, {
|
|
354699
|
+
method: "POST",
|
|
354700
|
+
body: JSON.stringify({ script, args: [text] })
|
|
354701
|
+
});
|
|
354702
|
+
const count = readValue(result);
|
|
354703
|
+
if (count !== 1) {
|
|
354704
|
+
throw new Error(`WEBVIEW text click found ${count === 0 || count === void 0 ? "no" : String(count)} actionable match(es) for "${text}"`);
|
|
354705
|
+
}
|
|
354706
|
+
}
|
|
354679
354707
|
async function typeCssInCurrentContext(sessionPath, css, text) {
|
|
354680
354708
|
const elResult = await appiumRequest(`${sessionPath}/element`, {
|
|
354681
354709
|
method: "POST",
|
|
@@ -357037,6 +357065,48 @@ function stepWebViewContext(step) {
|
|
|
357037
357065
|
const meta = step.metadata && typeof step.metadata === "object" ? step.metadata : null;
|
|
357038
357066
|
return typeof meta?.webviewContext === "string" && meta.webviewContext.trim() ? meta.webviewContext.trim() : null;
|
|
357039
357067
|
}
|
|
357068
|
+
var DOM_ID_RE = /^[A-Za-z_][\w-]*$/;
|
|
357069
|
+
var SYSTEM_RESOURCE_ID_RE = /^(?:android|com\.android\.|com\.google\.android\.)/i;
|
|
357070
|
+
function webViewCssFallbackFromNativeStep(step) {
|
|
357071
|
+
if (stepWebViewCss(step)) return null;
|
|
357072
|
+
const target = step.target;
|
|
357073
|
+
if (!target) return null;
|
|
357074
|
+
const bundle = target.locatorBundle;
|
|
357075
|
+
const resourceId = typeof bundle?.resourceId === "string" ? bundle.resourceId.trim() : "";
|
|
357076
|
+
const accessibilityId = typeof bundle?.accessibilityId === "string" ? bundle.accessibilityId.trim() : "";
|
|
357077
|
+
const primary = typeof target.primary === "string" ? target.primary.trim() : "";
|
|
357078
|
+
const fromResourceId = (raw) => {
|
|
357079
|
+
if (!raw) return null;
|
|
357080
|
+
if (raw.includes(":id/")) {
|
|
357081
|
+
if (SYSTEM_RESOURCE_ID_RE.test(raw)) return null;
|
|
357082
|
+
const local = raw.slice(raw.indexOf(":id/") + 4);
|
|
357083
|
+
return DOM_ID_RE.test(local) ? local : null;
|
|
357084
|
+
}
|
|
357085
|
+
return DOM_ID_RE.test(raw) ? raw : null;
|
|
357086
|
+
};
|
|
357087
|
+
const domId = fromResourceId(resourceId) ?? fromResourceId(accessibilityId) ?? (primary && !/[=~/[\].\s]/.test(primary) && DOM_ID_RE.test(primary) ? primary : null);
|
|
357088
|
+
return domId ? `#${domId}` : null;
|
|
357089
|
+
}
|
|
357090
|
+
function webViewTextFallbackFromNativeStep(step) {
|
|
357091
|
+
if (stepWebViewCss(step)) return null;
|
|
357092
|
+
if (step.action !== "tap") return null;
|
|
357093
|
+
const target = step.target;
|
|
357094
|
+
if (!target) return null;
|
|
357095
|
+
const bundle = target.locatorBundle;
|
|
357096
|
+
const text = typeof bundle?.text === "string" && bundle.text.trim() ? bundle.text.trim() : typeof bundle?.contentDesc === "string" && bundle.contentDesc.trim() ? bundle.contentDesc.trim() : typeof target.primary === "string" && target.primary.trim() && !/[=~/[\]]|:id\//.test(target.primary) ? target.primary.trim() : "";
|
|
357097
|
+
const normalized = text.replace(/\s+/g, " ");
|
|
357098
|
+
if (!normalized || normalized.length > 40 || /[\n\r]/.test(text)) return null;
|
|
357099
|
+
if (SYSTEM_PERMISSION_BUTTON_RE.test(text)) return null;
|
|
357100
|
+
return normalized;
|
|
357101
|
+
}
|
|
357102
|
+
async function hasLiveWebViewContext(sessionId) {
|
|
357103
|
+
try {
|
|
357104
|
+
const contexts = await listAppContexts(`/session/${sessionId}`);
|
|
357105
|
+
return contexts.some((c) => /^WEBVIEW/i.test(c));
|
|
357106
|
+
} catch {
|
|
357107
|
+
return false;
|
|
357108
|
+
}
|
|
357109
|
+
}
|
|
357040
357110
|
var CONTAINER_ONLY_ENTRY_ID_RE = /(?:^|[:/])id\/(webview|content|decor|decor_content_parent|action_bar_root|statusBarBackground|navigationBarBackground)$|^(?:main-content|root|app|app-root|__next|react-root|application)$/i;
|
|
357041
357111
|
function isContainerOnlyEntryTarget(target) {
|
|
357042
357112
|
const primary = target?.primary?.trim() ?? "";
|
|
@@ -357124,6 +357194,7 @@ function isWebViewHydrationTransient(err) {
|
|
|
357124
357194
|
return /no such element|NoSuchElement|element not interactable|stale element|WEBVIEW step requires|Empty page dictionary|not connectable|no WEBVIEW context|chrome not reachable/i.test(message);
|
|
357125
357195
|
}
|
|
357126
357196
|
var WEBVIEW_HYDRATION_TIMEOUT_MS = Number(process.env.VALIDATEQA_WEBVIEW_HYDRATION_TIMEOUT_MS) || 3e4;
|
|
357197
|
+
var PERMISSION_DIALOG_TIMEOUT_MS = Number(process.env.VALIDATEQA_PERMISSION_DIALOG_TIMEOUT_MS) || 3e3;
|
|
357127
357198
|
async function executeInWebViewContextWithHydrationRetry(sessionId, step, css, body, timeoutMs) {
|
|
357128
357199
|
const deadline = Date.now() + Math.max(1e3, timeoutMs);
|
|
357129
357200
|
for (; ; ) {
|
|
@@ -357136,6 +357207,17 @@ async function executeInWebViewContextWithHydrationRetry(sessionId, step, css, b
|
|
|
357136
357207
|
}
|
|
357137
357208
|
}
|
|
357138
357209
|
}
|
|
357210
|
+
var SYSTEM_PERMISSION_BUTTON_RE = /com\.android\.permissioncontroller:id\/permission_(allow|deny)|com\.android\.packageinstaller:id\/permission_|:id\/permission_allow_(foreground_only|one_time)_button|^(?:com\.apple\.springboard|SpringBoard)/i;
|
|
357211
|
+
function isSystemPermissionButtonTarget(target) {
|
|
357212
|
+
if (!target) return false;
|
|
357213
|
+
const bundle = target.locatorBundle;
|
|
357214
|
+
const candidates = [
|
|
357215
|
+
target.primary,
|
|
357216
|
+
typeof bundle?.resourceId === "string" ? bundle.resourceId : "",
|
|
357217
|
+
typeof bundle?.xpath === "string" ? bundle.xpath : ""
|
|
357218
|
+
];
|
|
357219
|
+
return candidates.some((c) => typeof c === "string" && SYSTEM_PERMISSION_BUTTON_RE.test(c));
|
|
357220
|
+
}
|
|
357139
357221
|
async function executeTap(sessionId, step, platform3, isCrossPlatform = false) {
|
|
357140
357222
|
const webCss = stepWebViewCss(step);
|
|
357141
357223
|
if (webCss) {
|
|
@@ -357148,10 +357230,11 @@ async function executeTap(sessionId, step, platform3, isCrossPlatform = false) {
|
|
|
357148
357230
|
);
|
|
357149
357231
|
return;
|
|
357150
357232
|
}
|
|
357233
|
+
const isPermissionTap = isSystemPermissionButtonTarget(step.target);
|
|
357151
357234
|
const bounds = boundsForRun(step, platform3, isCrossPlatform);
|
|
357152
357235
|
if (step.target) {
|
|
357153
357236
|
try {
|
|
357154
|
-
const elementId = await findElement(sessionId, step.target, readStepTimeout(step), {
|
|
357237
|
+
const elementId = await findElement(sessionId, step.target, isPermissionTap ? Math.min(readStepTimeout(step) ?? DEFAULT_STEP_TIMEOUT_MS, PERMISSION_DIALOG_TIMEOUT_MS) : readStepTimeout(step), {
|
|
357155
357238
|
platform: platform3,
|
|
357156
357239
|
recordedBounds: bounds
|
|
357157
357240
|
});
|
|
@@ -357161,7 +357244,23 @@ async function executeTap(sessionId, step, platform3, isCrossPlatform = false) {
|
|
|
357161
357244
|
});
|
|
357162
357245
|
return;
|
|
357163
357246
|
} catch (error2) {
|
|
357164
|
-
if (isTransportError(error2) ||
|
|
357247
|
+
if (isTransportError(error2) || error2 instanceof MobileAmbiguousMatchError) throw error2;
|
|
357248
|
+
if (isPermissionTap) return;
|
|
357249
|
+
const cssFallback = webViewCssFallbackFromNativeStep(step);
|
|
357250
|
+
const textFallback = cssFallback ? null : webViewTextFallbackFromNativeStep(step);
|
|
357251
|
+
if ((cssFallback || textFallback) && await hasLiveWebViewContext(sessionId)) {
|
|
357252
|
+
try {
|
|
357253
|
+
if (cssFallback) {
|
|
357254
|
+
await executeInWebViewContext(sessionId, step, cssFallback, (sessionPath, css) => clickCssInCurrentContext(sessionPath, css));
|
|
357255
|
+
} else if (textFallback) {
|
|
357256
|
+
await executeInWebViewContext(sessionId, step, textFallback, (sessionPath) => clickByVisibleTextInCurrentContext(sessionPath, textFallback));
|
|
357257
|
+
}
|
|
357258
|
+
return;
|
|
357259
|
+
} catch (webErr) {
|
|
357260
|
+
if (isTransportError(webErr)) throw webErr;
|
|
357261
|
+
}
|
|
357262
|
+
}
|
|
357263
|
+
if (!bounds || buildLocatorStrategies(step.target, platform3).length > 0) throw error2;
|
|
357165
357264
|
}
|
|
357166
357265
|
}
|
|
357167
357266
|
if (!bounds) {
|
|
@@ -357219,6 +357318,18 @@ async function executeType(sessionId, step, context) {
|
|
|
357219
357318
|
return;
|
|
357220
357319
|
} catch (error2) {
|
|
357221
357320
|
if (isTransportError(error2)) throw error2;
|
|
357321
|
+
if (!focusEstablished && !keyboardSubmitOnly) {
|
|
357322
|
+
const cssFallback = webViewCssFallbackFromNativeStep(step);
|
|
357323
|
+
if (cssFallback && await hasLiveWebViewContext(sessionId)) {
|
|
357324
|
+
try {
|
|
357325
|
+
context.log?.(` Native locate failed; retrying as WebView ${cssFallback} (hybrid mirror fallback)`);
|
|
357326
|
+
await executeInWebViewContext(sessionId, step, cssFallback, (sessionPath2, css) => typeCssInCurrentContext(sessionPath2, css, value));
|
|
357327
|
+
return;
|
|
357328
|
+
} catch (webErr) {
|
|
357329
|
+
if (isTransportError(webErr)) throw webErr;
|
|
357330
|
+
}
|
|
357331
|
+
}
|
|
357332
|
+
}
|
|
357222
357333
|
if (context.platform === "ANDROID" && focusEstablished) {
|
|
357223
357334
|
try {
|
|
357224
357335
|
context.log?.(" Appium active-element send failed; using Android focused-keyboard input fallback");
|
package/package.json
CHANGED