@geometra/proxy 1.65.1 → 1.65.2

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.
@@ -1 +1 @@
1
- {"version":3,"file":"dom-actions.d.ts","sourceRoot":"","sources":["../src/dom-actions.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"dom-actions.d.ts","sourceRoot":"","sources":["../src/dom-actions.ts"],"names":[],"mappings":"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"}
@@ -527,6 +527,65 @@ async function assertPointMutable(page, x, y, intent, action) {
527
527
  await element.dispose();
528
528
  }
529
529
  }
530
+ async function elementOwnsPagePoint(element, x, y) {
531
+ try {
532
+ const bounds = await element.boundingBox();
533
+ if (!bounds || bounds.width <= 0 || bounds.height <= 0 ||
534
+ x < bounds.x || y < bounds.y || x >= bounds.x + bounds.width || y >= bounds.y + bounds.height) {
535
+ return false;
536
+ }
537
+ return await element.evaluate((target, payload) => {
538
+ const rect = target.getBoundingClientRect();
539
+ if (rect.width <= 0 || rect.height <= 0)
540
+ return false;
541
+ const clientX = rect.left + ((payload.x - payload.bounds.x) / payload.bounds.width) * rect.width;
542
+ const clientY = rect.top + ((payload.y - payload.bounds.y) / payload.bounds.height) * rect.height;
543
+ const hit = document.elementFromPoint(clientX, clientY);
544
+ return hit === target || (hit !== null && target.contains(hit));
545
+ }, { x, y, bounds });
546
+ }
547
+ catch {
548
+ return false;
549
+ }
550
+ }
551
+ async function frameChainOwnsPagePoint(frame, x, y) {
552
+ let current = frame;
553
+ while (true) {
554
+ const parent = current.parentFrame();
555
+ if (!parent)
556
+ return true;
557
+ let frameElement = null;
558
+ try {
559
+ frameElement = await current.frameElement();
560
+ if (!(await elementOwnsPagePoint(frameElement, x, y)))
561
+ return false;
562
+ }
563
+ catch {
564
+ return false;
565
+ }
566
+ finally {
567
+ await frameElement?.dispose();
568
+ }
569
+ current = parent;
570
+ }
571
+ }
572
+ async function nativeSelectAtPoint(page, x, y) {
573
+ for (const frame of page.frames()) {
574
+ const selects = await frame.locator('select').elementHandles();
575
+ let match = null;
576
+ for (const select of selects) {
577
+ if (!match && await elementOwnsPagePoint(select, x, y) && await frameChainOwnsPagePoint(frame, x, y)) {
578
+ match = select;
579
+ }
580
+ else {
581
+ await select.dispose();
582
+ }
583
+ }
584
+ if (match)
585
+ return match;
586
+ }
587
+ return null;
588
+ }
530
589
  async function locatorAnchorY(locator) {
531
590
  const bounds = await locator.boundingBox();
532
591
  return bounds ? bounds.y + bounds.height / 2 : undefined;
@@ -6023,52 +6082,119 @@ export async function selectNativeOption(page, x, y, opt) {
6023
6082
  if (opt.index !== undefined && (!Number.isFinite(opt.index) || !Number.isInteger(opt.index) || opt.index < 0)) {
6024
6083
  throw new Error('selectOption: index must be a non-negative integer');
6025
6084
  }
6026
- await assertPointMutable(page, x, y, 'select', 'selectOption');
6027
- await page.mouse.click(x, y);
6028
- await delay(40);
6029
- for (const frame of page.frames()) {
6030
- const applied = await frame.evaluate(async (payload) => {
6085
+ const select = await nativeSelectAtPoint(page, x, y);
6086
+ if (!select) {
6087
+ throw new Error('selectOption: supplied coordinates do not target a native <select>');
6088
+ }
6089
+ const payload = {
6090
+ value: opt.value ?? null,
6091
+ label: opt.label ?? null,
6092
+ index: typeof opt.index === 'number' && Number.isFinite(opt.index) ? opt.index : undefined,
6093
+ };
6094
+ try {
6095
+ const reason = await select.evaluate(mutationBlockReasonInPage, 'select');
6096
+ if (reason)
6097
+ throw new Error(`selectOption: matched control is not mutable (${reason})`);
6098
+ const optionReady = await select.evaluate((target, requested) => {
6099
+ if (!(target instanceof HTMLSelectElement))
6100
+ return false;
6031
6101
  const normalize = (input) => input?.replace(/\s+/g, ' ').trim().toLowerCase() ?? '';
6032
6102
  const enabled = (o) => !o.disabled && !(o.parentElement instanceof HTMLOptGroupElement && o.parentElement.disabled);
6033
6103
  const optionMatchesPayload = (o) => {
6034
6104
  if (o.disabled || (o.parentElement instanceof HTMLOptGroupElement && o.parentElement.disabled))
6035
6105
  return false;
6036
- if (payload.value !== null && normalize(o.value) !== normalize(payload.value))
6106
+ if (requested.value !== null && normalize(o.value) !== normalize(requested.value))
6037
6107
  return false;
6038
- if (payload.label !== null && normalize(o.textContent) !== normalize(payload.label))
6108
+ if (requested.label !== null && normalize(o.textContent) !== normalize(requested.label))
6039
6109
  return false;
6040
- if (payload.index !== undefined && o.index !== payload.index)
6110
+ if (requested.index !== undefined && o.index !== requested.index)
6041
6111
  return false;
6042
6112
  return true;
6043
6113
  };
6044
- const a = document.activeElement;
6045
- if (!a || a.tagName !== 'SELECT')
6114
+ const candidate = requested.index !== undefined
6115
+ ? target.options.item(requested.index)
6116
+ : Array.from(target.options).find(optionMatchesPayload) ?? null;
6117
+ return !!candidate && enabled(candidate) && optionMatchesPayload(candidate);
6118
+ }, payload);
6119
+ if (!optionReady) {
6120
+ throw new Error('selectOption: no enabled <option> matches the requested identity');
6121
+ }
6122
+ const applied = await select.evaluate(async (target, requested) => {
6123
+ if (!(target instanceof HTMLSelectElement))
6046
6124
  return false;
6047
- const sel = a;
6048
- if (sel.matches(':disabled') || sel.getAttribute('aria-disabled') === 'true' || sel.getAttribute('aria-readonly') === 'true')
6049
- return false;
6050
- if (sel.closest('[inert], [aria-disabled="true"], [aria-readonly="true"]'))
6125
+ function commitMutationBlockReason(control) {
6126
+ function composedParent(node) {
6127
+ if (node.parentElement)
6128
+ return node.parentElement;
6129
+ const root = node.getRootNode();
6130
+ return root instanceof ShadowRoot ? root.host : null;
6131
+ }
6132
+ function composedDescendantOf(node, ancestor) {
6133
+ let current = node;
6134
+ while (current) {
6135
+ if (current === ancestor)
6136
+ return true;
6137
+ current = composedParent(current);
6138
+ }
6139
+ return false;
6140
+ }
6141
+ try {
6142
+ if (control.matches(':disabled'))
6143
+ return 'disabled';
6144
+ }
6145
+ catch { /* non-HTML namespaces may reject pseudo classes */ }
6146
+ let current = control;
6147
+ while (current) {
6148
+ if (current.hasAttribute('inert'))
6149
+ return 'inert';
6150
+ if (current.getAttribute('aria-disabled')?.trim().toLowerCase() === 'true')
6151
+ return 'aria-disabled';
6152
+ if (current.getAttribute('aria-readonly')?.trim().toLowerCase() === 'true')
6153
+ return 'aria-readonly';
6154
+ if (current instanceof HTMLFieldSetElement && current.disabled) {
6155
+ const firstLegend = Array.from(current.children).find(child => child instanceof HTMLLegendElement);
6156
+ if (!(firstLegend instanceof HTMLLegendElement) || !composedDescendantOf(control, firstLegend)) {
6157
+ return 'disabled fieldset';
6158
+ }
6159
+ }
6160
+ current = composedParent(current);
6161
+ }
6162
+ return null;
6163
+ }
6164
+ if (commitMutationBlockReason(target))
6051
6165
  return false;
6052
- const candidate = payload.index !== undefined
6053
- ? sel.options.item(payload.index)
6054
- : Array.from(sel.options).find(optionMatchesPayload) ?? null;
6166
+ const normalize = (input) => input?.replace(/\s+/g, ' ').trim().toLowerCase() ?? '';
6167
+ const enabled = (o) => !o.disabled && !(o.parentElement instanceof HTMLOptGroupElement && o.parentElement.disabled);
6168
+ const optionMatchesPayload = (o) => {
6169
+ if (!enabled(o))
6170
+ return false;
6171
+ if (requested.value !== null && normalize(o.value) !== normalize(requested.value))
6172
+ return false;
6173
+ if (requested.label !== null && normalize(o.textContent) !== normalize(requested.label))
6174
+ return false;
6175
+ if (requested.index !== undefined && o.index !== requested.index)
6176
+ return false;
6177
+ return true;
6178
+ };
6179
+ const candidate = requested.index !== undefined
6180
+ ? target.options.item(requested.index)
6181
+ : Array.from(target.options).find(optionMatchesPayload) ?? null;
6055
6182
  if (!candidate || !enabled(candidate) || !optionMatchesPayload(candidate))
6056
6183
  return false;
6057
- sel.selectedIndex = candidate.index;
6058
- sel.dispatchEvent(new Event('input', { bubbles: true }));
6059
- sel.dispatchEvent(new Event('change', { bubbles: true }));
6184
+ target.selectedIndex = candidate.index;
6185
+ target.dispatchEvent(new Event('input', { bubbles: true }));
6186
+ target.dispatchEvent(new Event('change', { bubbles: true }));
6060
6187
  await new Promise(resolveTimer => setTimeout(resolveTimer, 40));
6061
- const selected = sel.selectedOptions[0];
6062
- return sel.selectedIndex === candidate.index && selected === candidate && optionMatchesPayload(selected);
6063
- }, {
6064
- value: opt.value ?? null,
6065
- label: opt.label ?? null,
6066
- index: typeof opt.index === 'number' && Number.isFinite(opt.index) ? opt.index : undefined,
6067
- });
6188
+ const selected = target.selectedOptions[0];
6189
+ return target.selectedIndex === candidate.index && selected === candidate && optionMatchesPayload(selected);
6190
+ }, payload);
6068
6191
  if (applied)
6069
6192
  return;
6070
6193
  }
6071
- throw new Error('selectOption: no focused <select> after click — use geometra_pick_listbox_option for custom dropdowns');
6194
+ finally {
6195
+ await select.dispose();
6196
+ }
6197
+ throw new Error('selectOption: native <select> or requested option changed before commit');
6072
6198
  }
6073
6199
  /**
6074
6200
  * Custom listbox / combobox (ARIA): optional click to open, then `getByRole('option')`.