@geometra/proxy 1.49.0 → 1.52.0
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/diff-layout.d.ts.map +1 -1
- package/dist/diff-layout.js +13 -1
- package/dist/diff-layout.js.map +1 -1
- package/dist/dom-actions.d.ts +4 -0
- package/dist/dom-actions.d.ts.map +1 -1
- package/dist/dom-actions.js +236 -16
- package/dist/dom-actions.js.map +1 -1
- package/dist/geometry-ws.d.ts.map +1 -1
- package/dist/geometry-ws.js +2 -0
- package/dist/geometry-ws.js.map +1 -1
- package/dist/input-canonical.d.ts +10 -0
- package/dist/input-canonical.d.ts.map +1 -0
- package/dist/input-canonical.js +88 -0
- package/dist/input-canonical.js.map +1 -0
- package/dist/types.d.ts +6 -0
- package/dist/types.d.ts.map +1 -1
- package/dist/types.js.map +1 -1
- package/package.json +1 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diff-layout.d.ts","sourceRoot":"","sources":["../src/diff-layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD,2DAA2D;AAC3D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,CAAC,CAAC,EAAE,MAAM,CAAA;IACV,CAAC,CAAC,EAAE,MAAM,CAAA;IACV,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;
|
|
1
|
+
{"version":3,"file":"diff-layout.d.ts","sourceRoot":"","sources":["../src/diff-layout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD,2DAA2D;AAC3D,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,EAAE,CAAA;IACd,CAAC,CAAC,EAAE,MAAM,CAAA;IACV,CAAC,CAAC,EAAE,MAAM,CAAA;IACV,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB;AA4BD,wBAAgB,eAAe,CAAC,OAAO,EAAE,WAAW,EAAE,GAAG,WAAW,EAAE,CAsBrE;AAED,wBAAgB,UAAU,CAAC,IAAI,EAAE,cAAc,EAAE,IAAI,EAAE,cAAc,EAAE,IAAI,GAAE,MAAM,EAAO,GAAG,WAAW,EAAE,CAoCzG"}
|
package/dist/diff-layout.js
CHANGED
|
@@ -9,6 +9,18 @@ function isFinitePatchNumber(value) {
|
|
|
9
9
|
function isNonNegativePatchDimension(value) {
|
|
10
10
|
return isFinitePatchNumber(value) && value >= 0;
|
|
11
11
|
}
|
|
12
|
+
/**
|
|
13
|
+
* Stable `Map` key for patch `path` arrays. Plain `JSON.stringify([NaN])` and `JSON.stringify([null])` both
|
|
14
|
+
* yield `"[null]"`, so a replacer tags NaN segments — keep in sync with `packages/server/src/protocol.ts` `coalescePatches`.
|
|
15
|
+
*/
|
|
16
|
+
function layoutPatchPathKey(path) {
|
|
17
|
+
return JSON.stringify(path, (_key, value) => {
|
|
18
|
+
if (typeof value === 'number' && Number.isNaN(value)) {
|
|
19
|
+
return '\uFFFD__GEOM_PATH_NaN__';
|
|
20
|
+
}
|
|
21
|
+
return value;
|
|
22
|
+
});
|
|
23
|
+
}
|
|
12
24
|
export function coalescePatches(patches) {
|
|
13
25
|
const byPath = new Map();
|
|
14
26
|
const order = [];
|
|
@@ -17,7 +29,7 @@ export function coalescePatches(patches) {
|
|
|
17
29
|
continue;
|
|
18
30
|
let key;
|
|
19
31
|
try {
|
|
20
|
-
key =
|
|
32
|
+
key = layoutPatchPathKey(patch.path);
|
|
21
33
|
}
|
|
22
34
|
catch {
|
|
23
35
|
continue;
|
package/dist/diff-layout.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"diff-layout.js","sourceRoot":"","sources":["../src/diff-layout.ts"],"names":[],"mappings":"AAWA,SAAS,gBAAgB,CAAC,CAAS,EAAE,CAAS;IAC5C,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAAE,OAAO,IAAI,CAAA;IACnD,OAAO,CAAC,KAAK,CAAC,CAAA;AAChB,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAc;IACzC,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,MAAM,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAA;AAC5D,CAAC;AAED,SAAS,2BAA2B,CAAC,KAAc;IACjD,OAAO,mBAAmB,CAAC,KAAK,CAAC,IAAI,KAAK,IAAI,CAAC,CAAA;AACjD,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,OAAsB;IACpD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAuB,CAAA;IAC7C,MAAM,KAAK,GAAa,EAAE,CAAA;IAC1B,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,IAAI,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC;YAAE,SAAQ;QACzD,IAAI,GAAW,CAAA;QACf,IAAI,CAAC;YACH,GAAG,GAAG,
|
|
1
|
+
{"version":3,"file":"diff-layout.js","sourceRoot":"","sources":["../src/diff-layout.ts"],"names":[],"mappings":"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"}
|
package/dist/dom-actions.d.ts
CHANGED
|
@@ -56,6 +56,10 @@ export declare function setFieldText(page: Page, fieldLabel: string, value: stri
|
|
|
56
56
|
exact?: boolean;
|
|
57
57
|
cache?: FillLookupCache;
|
|
58
58
|
fieldId?: string;
|
|
59
|
+
/** Delay between keystrokes when using keyboard typing fallback (masked inputs). */
|
|
60
|
+
typingDelayMs?: number;
|
|
61
|
+
/** Composition events before assignment; small default key delay when typing. */
|
|
62
|
+
imeFriendly?: boolean;
|
|
59
63
|
}): Promise<void>;
|
|
60
64
|
export declare function setAutoFieldValue(page: Page, fieldLabel: string, value: string | boolean, opts?: {
|
|
61
65
|
exact?: boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dom-actions.d.ts","sourceRoot":"","sources":["../src/dom-actions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAwB,OAAO,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"dom-actions.d.ts","sourceRoot":"","sources":["../src/dom-actions.ts"],"names":[],"mappings":"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"}
|
package/dist/dom-actions.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { resolve } from 'node:path';
|
|
3
|
+
import { canonicalizeHtmlInputValue } from './input-canonical.js';
|
|
3
4
|
export function delay(ms) {
|
|
4
5
|
return new Promise(r => setTimeout(r, ms));
|
|
5
6
|
}
|
|
@@ -827,7 +828,7 @@ async function resolveOwnedPopupHandle(triggerHandle) {
|
|
|
827
828
|
return null;
|
|
828
829
|
}
|
|
829
830
|
}
|
|
830
|
-
async function typeIntoEditableLocator(page, locator, text) {
|
|
831
|
+
async function typeIntoEditableLocator(page, locator, text, opts) {
|
|
831
832
|
try {
|
|
832
833
|
await locator.fill(text);
|
|
833
834
|
return;
|
|
@@ -836,7 +837,13 @@ async function typeIntoEditableLocator(page, locator, text) {
|
|
|
836
837
|
/* fall through */
|
|
837
838
|
}
|
|
838
839
|
await locator.click();
|
|
839
|
-
|
|
840
|
+
const delay = opts?.delayMs;
|
|
841
|
+
if (delay !== undefined && delay > 0) {
|
|
842
|
+
await page.keyboard.type(text, { delay });
|
|
843
|
+
}
|
|
844
|
+
else {
|
|
845
|
+
await page.keyboard.type(text);
|
|
846
|
+
}
|
|
840
847
|
}
|
|
841
848
|
async function typeIntoActiveEditableElement(page, text) {
|
|
842
849
|
for (const frame of page.frames()) {
|
|
@@ -2901,9 +2908,11 @@ function fieldValueMatches(actual, expected) {
|
|
|
2901
2908
|
return false;
|
|
2902
2909
|
return normalizedActual === normalizedExpected || normalizedActual.includes(normalizedExpected);
|
|
2903
2910
|
}
|
|
2904
|
-
async function setLocatorTextValue(locator, value) {
|
|
2911
|
+
async function setLocatorTextValue(locator, value, opts) {
|
|
2905
2912
|
try {
|
|
2906
|
-
return await locator.evaluate((el,
|
|
2913
|
+
return await locator.evaluate((el, payload) => {
|
|
2914
|
+
const nextValue = payload.value;
|
|
2915
|
+
const imeFriendly = payload.imeFriendly;
|
|
2907
2916
|
// React Greenhouse/Workday/Lever fix: React stores the previous value on
|
|
2908
2917
|
// a hidden `_valueTracker` property that React uses to short-circuit
|
|
2909
2918
|
// onChange when the value "hasn't changed". If we set el.value through
|
|
@@ -2956,29 +2965,60 @@ async function setLocatorTextValue(locator, value) {
|
|
|
2956
2965
|
target.value = next;
|
|
2957
2966
|
}
|
|
2958
2967
|
}
|
|
2968
|
+
function dispatchImeHints(target) {
|
|
2969
|
+
if (!imeFriendly)
|
|
2970
|
+
return;
|
|
2971
|
+
try {
|
|
2972
|
+
target.dispatchEvent(new CompositionEvent('compositionstart', { bubbles: true, data: '' }));
|
|
2973
|
+
target.dispatchEvent(new CompositionEvent('compositionupdate', { bubbles: true, data: nextValue }));
|
|
2974
|
+
target.dispatchEvent(new CompositionEvent('compositionend', { bubbles: true, data: nextValue }));
|
|
2975
|
+
}
|
|
2976
|
+
catch { /* ignore */ }
|
|
2977
|
+
}
|
|
2978
|
+
/** Bulk `textContent` is unsafe for rich editors (paragraphs, mentions). */
|
|
2979
|
+
function isPlainContentEditable(host) {
|
|
2980
|
+
if (!host.isContentEditable)
|
|
2981
|
+
return true;
|
|
2982
|
+
for (const node of host.childNodes) {
|
|
2983
|
+
if (node.nodeType === Node.TEXT_NODE)
|
|
2984
|
+
continue;
|
|
2985
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
2986
|
+
const tag = node.tagName.toLowerCase();
|
|
2987
|
+
if (tag === 'br' && host.childNodes.length === 1)
|
|
2988
|
+
continue;
|
|
2989
|
+
return false;
|
|
2990
|
+
}
|
|
2991
|
+
}
|
|
2992
|
+
return true;
|
|
2993
|
+
}
|
|
2959
2994
|
if (el instanceof HTMLInputElement) {
|
|
2960
2995
|
if (['checkbox', 'radio', 'file', 'button', 'submit', 'reset', 'hidden'].includes(el.type))
|
|
2961
2996
|
return false;
|
|
2962
2997
|
el.focus();
|
|
2998
|
+
dispatchImeHints(el);
|
|
2963
2999
|
setInputLikeValue(el, nextValue);
|
|
2964
3000
|
dispatch(el);
|
|
2965
3001
|
return true;
|
|
2966
3002
|
}
|
|
2967
3003
|
if (el instanceof HTMLTextAreaElement) {
|
|
2968
3004
|
el.focus();
|
|
3005
|
+
dispatchImeHints(el);
|
|
2969
3006
|
setInputLikeValue(el, nextValue);
|
|
2970
3007
|
dispatch(el);
|
|
2971
3008
|
return true;
|
|
2972
3009
|
}
|
|
2973
3010
|
if (el instanceof HTMLElement && (el.isContentEditable || el.getAttribute('role') === 'textbox' || el.getAttribute('role') === 'combobox')) {
|
|
3011
|
+
if (el.isContentEditable && !isPlainContentEditable(el))
|
|
3012
|
+
return false;
|
|
2974
3013
|
el.focus();
|
|
2975
3014
|
clearReactTracker(el);
|
|
3015
|
+
dispatchImeHints(el);
|
|
2976
3016
|
el.textContent = nextValue;
|
|
2977
3017
|
dispatch(el);
|
|
2978
3018
|
return true;
|
|
2979
3019
|
}
|
|
2980
3020
|
return false;
|
|
2981
|
-
}, value);
|
|
3021
|
+
}, { value, imeFriendly: opts?.imeFriendly ?? false });
|
|
2982
3022
|
}
|
|
2983
3023
|
catch {
|
|
2984
3024
|
return false;
|
|
@@ -3018,6 +3058,10 @@ async function attemptNativeBatchFill(page, fields) {
|
|
|
3018
3058
|
if (labelLooksLikeOtp(field.fieldLabel) && /^\S{4,}$/.test(field.value)) {
|
|
3019
3059
|
continue;
|
|
3020
3060
|
}
|
|
3061
|
+
// Keyboard timing / IME hints need the full `setFieldText` path.
|
|
3062
|
+
if (field.typingDelayMs !== undefined || field.imeFriendly) {
|
|
3063
|
+
continue;
|
|
3064
|
+
}
|
|
3021
3065
|
pending.push({
|
|
3022
3066
|
index,
|
|
3023
3067
|
kind: 'text',
|
|
@@ -3160,8 +3204,127 @@ async function attemptNativeBatchFill(page, fields) {
|
|
|
3160
3204
|
normalized === 'prefer not' ||
|
|
3161
3205
|
normalized === 'opt out';
|
|
3162
3206
|
}
|
|
3207
|
+
/** Keep in sync with `packages/proxy/src/input-canonical.ts` `canonicalizeHtmlInputValue`. */
|
|
3208
|
+
function canonicalizeHtmlInputValueInPage(inputType, raw) {
|
|
3209
|
+
const t = (inputType || 'text').toLowerCase();
|
|
3210
|
+
if (t === ''
|
|
3211
|
+
|| t === 'text'
|
|
3212
|
+
|| t === 'search'
|
|
3213
|
+
|| t === 'url'
|
|
3214
|
+
|| t === 'tel'
|
|
3215
|
+
|| t === 'email'
|
|
3216
|
+
|| t === 'password'
|
|
3217
|
+
|| t === 'textarea'
|
|
3218
|
+
|| t === 'hidden') {
|
|
3219
|
+
return raw;
|
|
3220
|
+
}
|
|
3221
|
+
const s = raw.trim();
|
|
3222
|
+
if (!s)
|
|
3223
|
+
return raw;
|
|
3224
|
+
if (t === 'number' || t === 'range') {
|
|
3225
|
+
const cleaned = s.replace(/,/g, '').replace(/\s/g, '');
|
|
3226
|
+
const n = parseFloat(cleaned);
|
|
3227
|
+
if (Number.isFinite(n))
|
|
3228
|
+
return String(n);
|
|
3229
|
+
return raw;
|
|
3230
|
+
}
|
|
3231
|
+
if (t === 'date') {
|
|
3232
|
+
if (/^\d{4}-\d{2}-\d{2}$/.test(s))
|
|
3233
|
+
return s;
|
|
3234
|
+
const d = new Date(s);
|
|
3235
|
+
if (!Number.isNaN(d.getTime())) {
|
|
3236
|
+
const y = d.getFullYear();
|
|
3237
|
+
const m = String(d.getMonth() + 1).padStart(2, '0');
|
|
3238
|
+
const day = String(d.getDate()).padStart(2, '0');
|
|
3239
|
+
return `${y}-${m}-${day}`;
|
|
3240
|
+
}
|
|
3241
|
+
return raw;
|
|
3242
|
+
}
|
|
3243
|
+
if (t === 'datetime-local') {
|
|
3244
|
+
if (/^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/.test(s))
|
|
3245
|
+
return s.slice(0, 16);
|
|
3246
|
+
const d = new Date(s);
|
|
3247
|
+
if (!Number.isNaN(d.getTime())) {
|
|
3248
|
+
const y = d.getFullYear();
|
|
3249
|
+
const mo = String(d.getMonth() + 1).padStart(2, '0');
|
|
3250
|
+
const day = String(d.getDate()).padStart(2, '0');
|
|
3251
|
+
const h = String(d.getHours()).padStart(2, '0');
|
|
3252
|
+
const min = String(d.getMinutes()).padStart(2, '0');
|
|
3253
|
+
return `${y}-${mo}-${day}T${h}:${min}`;
|
|
3254
|
+
}
|
|
3255
|
+
return raw;
|
|
3256
|
+
}
|
|
3257
|
+
if (t === 'time') {
|
|
3258
|
+
const tm = /^(\d{1,2}):(\d{2})(?::(\d{2}))?/.exec(s);
|
|
3259
|
+
if (tm) {
|
|
3260
|
+
const hh = Math.min(23, Math.max(0, parseInt(tm[1], 10)));
|
|
3261
|
+
const mm = tm[2];
|
|
3262
|
+
const ss = tm[3];
|
|
3263
|
+
const h = String(hh).padStart(2, '0');
|
|
3264
|
+
return ss ? `${h}:${mm}:${ss}` : `${h}:${mm}`;
|
|
3265
|
+
}
|
|
3266
|
+
return s;
|
|
3267
|
+
}
|
|
3268
|
+
if (t === 'month') {
|
|
3269
|
+
if (/^\d{4}-\d{2}$/.test(s))
|
|
3270
|
+
return s;
|
|
3271
|
+
const d = new Date(s);
|
|
3272
|
+
if (!Number.isNaN(d.getTime())) {
|
|
3273
|
+
const y = d.getFullYear();
|
|
3274
|
+
const mo = String(d.getMonth() + 1).padStart(2, '0');
|
|
3275
|
+
return `${y}-${mo}`;
|
|
3276
|
+
}
|
|
3277
|
+
return raw;
|
|
3278
|
+
}
|
|
3279
|
+
if (t === 'week') {
|
|
3280
|
+
const wm = /^(\d{4})-w(\d{2})$/i.exec(s);
|
|
3281
|
+
if (wm)
|
|
3282
|
+
return `${wm[1]}-W${wm[2]}`;
|
|
3283
|
+
return raw;
|
|
3284
|
+
}
|
|
3285
|
+
return raw;
|
|
3286
|
+
}
|
|
3287
|
+
function collectTextControlsDeep() {
|
|
3288
|
+
const parts = ['input', 'textarea', '[contenteditable="true"]'];
|
|
3289
|
+
const seen = new Set();
|
|
3290
|
+
const out = [];
|
|
3291
|
+
function visit(root) {
|
|
3292
|
+
for (const part of parts) {
|
|
3293
|
+
try {
|
|
3294
|
+
root.querySelectorAll(part).forEach((el) => {
|
|
3295
|
+
if (!seen.has(el)) {
|
|
3296
|
+
seen.add(el);
|
|
3297
|
+
out.push(el);
|
|
3298
|
+
}
|
|
3299
|
+
});
|
|
3300
|
+
}
|
|
3301
|
+
catch { /* ignore */ }
|
|
3302
|
+
}
|
|
3303
|
+
root.querySelectorAll('*').forEach((host) => {
|
|
3304
|
+
if (host.shadowRoot)
|
|
3305
|
+
visit(host.shadowRoot);
|
|
3306
|
+
});
|
|
3307
|
+
}
|
|
3308
|
+
visit(document);
|
|
3309
|
+
return out;
|
|
3310
|
+
}
|
|
3311
|
+
function isPlainContentEditableBatch(host) {
|
|
3312
|
+
if (!host.isContentEditable)
|
|
3313
|
+
return true;
|
|
3314
|
+
for (const node of host.childNodes) {
|
|
3315
|
+
if (node.nodeType === Node.TEXT_NODE)
|
|
3316
|
+
continue;
|
|
3317
|
+
if (node.nodeType === Node.ELEMENT_NODE) {
|
|
3318
|
+
const tag = node.tagName.toLowerCase();
|
|
3319
|
+
if (tag === 'br' && host.childNodes.length === 1)
|
|
3320
|
+
continue;
|
|
3321
|
+
return false;
|
|
3322
|
+
}
|
|
3323
|
+
}
|
|
3324
|
+
return true;
|
|
3325
|
+
}
|
|
3163
3326
|
function setTextField(fieldLabel, value, exact) {
|
|
3164
|
-
const controls =
|
|
3327
|
+
const controls = collectTextControlsDeep();
|
|
3165
3328
|
for (const control of controls) {
|
|
3166
3329
|
if (!(control instanceof Element) || !visible(control))
|
|
3167
3330
|
continue;
|
|
@@ -3171,12 +3334,16 @@ async function attemptNativeBatchFill(page, fields) {
|
|
|
3171
3334
|
if (!matches(explicitLabelText(control), fieldLabel, exact))
|
|
3172
3335
|
continue;
|
|
3173
3336
|
if (control instanceof HTMLInputElement || control instanceof HTMLTextAreaElement) {
|
|
3337
|
+
const inputType = control instanceof HTMLInputElement ? control.type : 'textarea';
|
|
3338
|
+
const v = canonicalizeHtmlInputValueInPage(inputType, value);
|
|
3174
3339
|
control.focus();
|
|
3175
|
-
setInputLikeValue(control,
|
|
3340
|
+
setInputLikeValue(control, v);
|
|
3176
3341
|
dispatch(control);
|
|
3177
|
-
return matches(currentValue(control),
|
|
3342
|
+
return matches(currentValue(control), v, false);
|
|
3178
3343
|
}
|
|
3179
3344
|
if (control instanceof HTMLElement && control.isContentEditable) {
|
|
3345
|
+
if (!isPlainContentEditableBatch(control))
|
|
3346
|
+
return false;
|
|
3180
3347
|
control.focus();
|
|
3181
3348
|
control.textContent = value;
|
|
3182
3349
|
dispatch(control);
|
|
@@ -3826,21 +3993,31 @@ export async function setFieldText(page, fieldLabel, value, opts) {
|
|
|
3826
3993
|
throw new Error(`setFieldText: no visible editable field matching "${fieldLabel}"`);
|
|
3827
3994
|
}
|
|
3828
3995
|
await locator.scrollIntoViewIfNeeded();
|
|
3829
|
-
const
|
|
3996
|
+
const inputType = await locator.evaluate(el => {
|
|
3997
|
+
if (el instanceof HTMLInputElement)
|
|
3998
|
+
return el.type;
|
|
3999
|
+
if (el instanceof HTMLTextAreaElement)
|
|
4000
|
+
return 'textarea';
|
|
4001
|
+
return 'text';
|
|
4002
|
+
});
|
|
4003
|
+
const normalized = canonicalizeHtmlInputValue(inputType, value);
|
|
4004
|
+
const applied = await setLocatorTextValue(locator, normalized, { imeFriendly: opts?.imeFriendly });
|
|
3830
4005
|
if (!applied) {
|
|
3831
4006
|
try {
|
|
3832
|
-
await locator.fill(
|
|
4007
|
+
await locator.fill(normalized);
|
|
3833
4008
|
}
|
|
3834
4009
|
catch {
|
|
3835
4010
|
await locator.click();
|
|
3836
|
-
await typeIntoEditableLocator(page, locator,
|
|
4011
|
+
await typeIntoEditableLocator(page, locator, normalized, {
|
|
4012
|
+
delayMs: opts?.typingDelayMs ?? (opts?.imeFriendly ? 5 : undefined),
|
|
4013
|
+
});
|
|
3837
4014
|
}
|
|
3838
4015
|
}
|
|
3839
4016
|
const current = await locatorCurrentValue(locator);
|
|
3840
|
-
if (fieldValueMatches(current,
|
|
4017
|
+
if (fieldValueMatches(current, normalized))
|
|
3841
4018
|
return;
|
|
3842
4019
|
const displayed = await locatorDisplayedValues(locator);
|
|
3843
|
-
if (displayed.some(candidate => fieldValueMatches(candidate,
|
|
4020
|
+
if (displayed.some(candidate => fieldValueMatches(candidate, normalized)))
|
|
3844
4021
|
return;
|
|
3845
4022
|
throw new Error(`setFieldText: set "${fieldLabel}" but could not confirm value ${JSON.stringify(value)}`);
|
|
3846
4023
|
}
|
|
@@ -3854,6 +4031,8 @@ async function setNativeSelectByLabel(locator, value, exact) {
|
|
|
3854
4031
|
if (!expected)
|
|
3855
4032
|
return false;
|
|
3856
4033
|
const option = Array.from(el.options).find((candidate) => {
|
|
4034
|
+
if (candidate.disabled)
|
|
4035
|
+
return false;
|
|
3857
4036
|
const label = normalize(candidate.textContent);
|
|
3858
4037
|
const rawValue = normalize(candidate.value);
|
|
3859
4038
|
if (payload.exact)
|
|
@@ -4158,12 +4337,17 @@ export async function setFieldChoice(page, fieldLabel, value, opts) {
|
|
|
4158
4337
|
const locator = await findLabeledControlInPage(page, fieldLabel, exact, { cache: opts?.cache, fieldId: opts?.fieldId });
|
|
4159
4338
|
if (locator) {
|
|
4160
4339
|
await locator.scrollIntoViewIfNeeded();
|
|
4340
|
+
const isNativeSelect = await locator.evaluate(el => el instanceof HTMLSelectElement);
|
|
4161
4341
|
if (await setNativeSelectByLabel(locator, value, exact)) {
|
|
4162
4342
|
const displayed = await locatorDisplayedValues(locator);
|
|
4163
4343
|
if (displayed.some(candidate => displayedValueMatchesSelection(candidate, value, exact)))
|
|
4164
4344
|
return;
|
|
4165
4345
|
throw new Error(`setFieldChoice: selected "${value}" for field "${fieldLabel}" but could not confirm it`);
|
|
4166
4346
|
}
|
|
4347
|
+
// Avoid pickListboxOption on a real <select> — option text/value did not match.
|
|
4348
|
+
if (isNativeSelect) {
|
|
4349
|
+
throw new Error(`setFieldChoice: no enabled <option> matching "${value}" for native <select> "${fieldLabel}"`);
|
|
4350
|
+
}
|
|
4167
4351
|
}
|
|
4168
4352
|
if (opts?.choiceType === 'group') {
|
|
4169
4353
|
if (await chooseValueFromLabeledGroup(page, fieldLabel, value, exact))
|
|
@@ -4216,7 +4400,13 @@ export async function fillFields(page, fields, cache = createFillLookupCache())
|
|
|
4216
4400
|
// The choice/toggle/file loop below always runs regardless.
|
|
4217
4401
|
const textFillFailures = [];
|
|
4218
4402
|
if (textFills.length > 0) {
|
|
4219
|
-
const results = await Promise.allSettled(textFills.map(({ field }) => setFieldText(page, field.fieldLabel, field.value, {
|
|
4403
|
+
const results = await Promise.allSettled(textFills.map(({ field }) => setFieldText(page, field.fieldLabel, field.value, {
|
|
4404
|
+
fieldId: field.fieldId,
|
|
4405
|
+
exact: field.exact,
|
|
4406
|
+
cache,
|
|
4407
|
+
typingDelayMs: field.typingDelayMs,
|
|
4408
|
+
imeFriendly: field.imeFriendly,
|
|
4409
|
+
})));
|
|
4220
4410
|
for (let i = 0; i < results.length; i++) {
|
|
4221
4411
|
const result = results[i];
|
|
4222
4412
|
if (result.status === 'rejected') {
|
|
@@ -4305,6 +4495,14 @@ export async function selectNativeOption(page, x, y, opt) {
|
|
|
4305
4495
|
await delay(40);
|
|
4306
4496
|
for (const frame of page.frames()) {
|
|
4307
4497
|
const applied = await frame.evaluate((payload) => {
|
|
4498
|
+
const normalize = (input) => input?.replace(/\s+/g, ' ').trim().toLowerCase() ?? '';
|
|
4499
|
+
const optionMatchesExpected = (o, expected) => {
|
|
4500
|
+
if (o.disabled)
|
|
4501
|
+
return false;
|
|
4502
|
+
const label = normalize(o.textContent);
|
|
4503
|
+
const rawValue = normalize(o.value);
|
|
4504
|
+
return label === expected || rawValue === expected || label.includes(expected) || rawValue.includes(expected);
|
|
4505
|
+
};
|
|
4308
4506
|
const a = document.activeElement;
|
|
4309
4507
|
if (!a || a.tagName !== 'SELECT')
|
|
4310
4508
|
return false;
|
|
@@ -4313,13 +4511,35 @@ export async function selectNativeOption(page, x, y, opt) {
|
|
|
4313
4511
|
const i = Math.trunc(payload.index);
|
|
4314
4512
|
if (i < 0 || i >= sel.options.length)
|
|
4315
4513
|
return false;
|
|
4514
|
+
if (sel.options[i].disabled)
|
|
4515
|
+
return false;
|
|
4316
4516
|
sel.selectedIndex = i;
|
|
4317
4517
|
}
|
|
4318
4518
|
else if (payload.value !== null && payload.value !== undefined) {
|
|
4319
|
-
|
|
4519
|
+
const raw = String(payload.value);
|
|
4520
|
+
sel.value = raw;
|
|
4521
|
+
const expected = normalize(raw);
|
|
4522
|
+
if (!expected)
|
|
4523
|
+
return false;
|
|
4524
|
+
const selected = sel.selectedOptions[0];
|
|
4525
|
+
const ok = selected &&
|
|
4526
|
+
!selected.disabled &&
|
|
4527
|
+
(normalize(selected.value) === expected ||
|
|
4528
|
+
normalize(selected.textContent) === expected ||
|
|
4529
|
+
normalize(selected.value).includes(expected) ||
|
|
4530
|
+
normalize(selected.textContent).includes(expected));
|
|
4531
|
+
if (!ok) {
|
|
4532
|
+
const found = Array.from(sel.options).find(o => optionMatchesExpected(o, expected));
|
|
4533
|
+
if (!found)
|
|
4534
|
+
return false;
|
|
4535
|
+
sel.value = found.value;
|
|
4536
|
+
}
|
|
4320
4537
|
}
|
|
4321
4538
|
else if (payload.label !== null && payload.label !== undefined) {
|
|
4322
|
-
const
|
|
4539
|
+
const expected = normalize(payload.label);
|
|
4540
|
+
if (!expected)
|
|
4541
|
+
return false;
|
|
4542
|
+
const optEl = Array.from(sel.options).find(o => optionMatchesExpected(o, expected));
|
|
4323
4543
|
if (!optEl)
|
|
4324
4544
|
return false;
|
|
4325
4545
|
sel.value = optEl.value;
|