@geometra/proxy 1.58.0 → 1.59.1

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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"}
@@ -4,12 +4,15 @@ import { canonicalizeHtmlInputValue } from './input-canonical.js';
4
4
  export function delay(ms) {
5
5
  return new Promise(r => setTimeout(r, ms));
6
6
  }
7
- const LABELED_CONTROL_SELECTOR = 'input, select, textarea, button, [role="combobox"], [role="textbox"], [aria-haspopup="listbox"], [contenteditable="true"]';
7
+ const LABELED_CONTROL_SELECTOR = 'input, select, textarea, button, [role="combobox"], [role="textbox"], [aria-haspopup="listbox"], [aria-haspopup="menu"], [aria-haspopup="true"], [contenteditable="true"]';
8
+ const MENU_TRIGGER_SELECTOR = 'button[aria-haspopup="menu"], button[aria-haspopup="true"], [role="button"][aria-haspopup="menu"], [role="button"][aria-haspopup="true"]';
8
9
  const POPUP_CONTAINER_SELECTOR = '[role="listbox"], [role="menu"], [role="dialog"], [aria-modal="true"], [data-radix-popper-content-wrapper], [class*="menu"], [class*="option"], [class*="select"], [class*="dropdown"]';
9
10
  const POPUP_ROOT_SELECTOR = '[role="listbox"], [role="menu"], [role="dialog"], [aria-modal="true"], [data-radix-popper-content-wrapper], [class*="menu"], [class*="dropdown"], [class*="popover"], [class*="listbox"], [class*="options"]';
10
11
  const OPTION_PICKER_SELECTOR = [
11
12
  '[role="option"]',
12
13
  '[role="menuitem"]',
14
+ '[role="menuitemradio"]',
15
+ '[role="menuitemcheckbox"]',
13
16
  '[role="treeitem"]',
14
17
  'button',
15
18
  'li',
@@ -579,6 +582,121 @@ function stripTruncationEllipsis(label) {
579
582
  // optionally preceded by whitespace, anchored at the end.
580
583
  return label.replace(/\s*(?:\u2026|\.\.\.)\s*$/u, '').trimEnd();
581
584
  }
585
+ /**
586
+ * Locate a menu-trigger button whose container-level label matches `fieldLabel`.
587
+ *
588
+ * Motivating case: GitHub Primer (and similar design systems) renders a
589
+ * dropdown as `<label>Ref type</label><button aria-haspopup="menu">Branch</button>`
590
+ * where the button's accessible name is the *current value* ("Branch"), not
591
+ * the field name. Playwright's `getByRole('button', { name: 'Ref type' })`
592
+ * therefore misses the trigger, and the existing `<label>/<legend>` proximity
593
+ * scan doesn't match either because the visible label is a plain `<span>` /
594
+ * `<div>` rather than a `<label>` element.
595
+ *
596
+ * This helper broadens the label search to any visible element whose text
597
+ * (minus the button's own text) matches the field name, then returns the
598
+ * menu-trigger button inside that container. It complements `findLabeledControl`
599
+ * rather than replacing it — the scan is restricted to menu-trigger buttons
600
+ * so it can't shadow existing combobox / textbox / native-select matches.
601
+ */
602
+ async function findMenuTriggerByContainerLabel(frame, fieldLabel, exact) {
603
+ const triggers = frame.locator(MENU_TRIGGER_SELECTOR);
604
+ const count = await triggers.count();
605
+ if (count === 0)
606
+ return null;
607
+ const bestIndex = await triggers.evaluateAll((elements, payload) => {
608
+ function normalize(value) {
609
+ return value.replace(/\s+/g, ' ').trim().toLowerCase();
610
+ }
611
+ function stripTrailingColon(value) {
612
+ return value.replace(/\s*:\s*$/u, '').trim();
613
+ }
614
+ function matches(candidate) {
615
+ if (!candidate)
616
+ return false;
617
+ const normalizedCandidate = normalize(stripTrailingColon(candidate));
618
+ const normalizedExpected = normalize(payload.fieldLabel);
619
+ if (!normalizedCandidate || !normalizedExpected)
620
+ return false;
621
+ return payload.exact
622
+ ? normalizedCandidate === normalizedExpected
623
+ : normalizedCandidate.includes(normalizedExpected);
624
+ }
625
+ function visible(el) {
626
+ if (!(el instanceof HTMLElement))
627
+ return false;
628
+ const rect = el.getBoundingClientRect();
629
+ if (rect.width <= 0 || rect.height <= 0)
630
+ return false;
631
+ const style = getComputedStyle(el);
632
+ return style.display !== 'none' && style.visibility !== 'hidden' && style.opacity !== '0';
633
+ }
634
+ function containerLabelText(el) {
635
+ // Walk up a few parent levels looking for a container that holds BOTH
636
+ // the trigger and some sibling label text. The label text is the
637
+ // container's visible text minus the trigger's own text.
638
+ let container = el.parentElement;
639
+ let depth = 0;
640
+ const triggerText = el.textContent?.trim() ?? '';
641
+ while (container && depth < 4) {
642
+ const containerText = container.textContent?.trim() ?? '';
643
+ if (containerText && containerText.length < 240) {
644
+ const residual = triggerText && containerText.endsWith(triggerText)
645
+ ? containerText.slice(0, containerText.length - triggerText.length).trim()
646
+ : triggerText && containerText.includes(triggerText)
647
+ ? containerText.split(triggerText)[0]?.trim() ?? ''
648
+ : containerText;
649
+ if (residual && residual.length > 0 && residual.length < 120) {
650
+ return residual;
651
+ }
652
+ }
653
+ container = container.parentElement;
654
+ depth++;
655
+ }
656
+ return undefined;
657
+ }
658
+ let best = null;
659
+ for (let i = 0; i < elements.length; i++) {
660
+ const el = elements[i];
661
+ if (!(el instanceof HTMLElement))
662
+ continue;
663
+ if (!visible(el))
664
+ continue;
665
+ const aria = el.getAttribute('aria-label')?.trim();
666
+ if (matches(aria)) {
667
+ const score = 0;
668
+ if (!best || score < best.score)
669
+ best = { index: i, score };
670
+ continue;
671
+ }
672
+ const labelledBy = el.getAttribute('aria-labelledby');
673
+ if (labelledBy) {
674
+ const text = labelledBy
675
+ .split(/\s+/)
676
+ .map(id => document.getElementById(id)?.textContent?.trim() ?? '')
677
+ .filter(Boolean)
678
+ .join(' ')
679
+ .trim();
680
+ if (matches(text)) {
681
+ const score = 10;
682
+ if (!best || score < best.score)
683
+ best = { index: i, score };
684
+ continue;
685
+ }
686
+ }
687
+ const container = containerLabelText(el);
688
+ if (matches(container)) {
689
+ const rect = el.getBoundingClientRect();
690
+ const sizePenalty = rect.width < 48 || rect.height < 18 ? 120 : 0;
691
+ const score = 100 + sizePenalty;
692
+ if (!best || score < best.score)
693
+ best = { index: i, score };
694
+ }
695
+ }
696
+ return best?.index ?? -1;
697
+ }, { fieldLabel, exact });
698
+ return bestIndex >= 0 ? triggers.nth(bestIndex) : null;
699
+ }
582
700
  async function findLabeledControlInPage(page, fieldLabel, exact, opts) {
583
701
  const cacheable = !opts?.preferredAnchor;
584
702
  const cached = cacheable ? readCachedLocator(opts?.cache, 'control', fieldLabel, exact, opts?.fieldId) : undefined;
@@ -612,6 +730,21 @@ async function findLabeledControlInPage(page, fieldLabel, exact, opts) {
612
730
  return locator;
613
731
  }
614
732
  }
733
+ // Fallback: menu-trigger buttons whose accessible name is the CURRENT VALUE
734
+ // (e.g. "Branch" for a "Ref type: Branch" GitHub Primer dropdown) rather
735
+ // than the field name. Restricted to aria-haspopup="menu"/"true" triggers
736
+ // so it cannot shadow existing combobox/textbox/native-select matches.
737
+ const candidateLabels = [fieldLabel, stripped].filter((label, index, array) => label && label.length > 0 && array.indexOf(label) === index);
738
+ for (const candidate of candidateLabels) {
739
+ for (const frame of page.frames()) {
740
+ const locator = await findMenuTriggerByContainerLabel(frame, candidate, exact);
741
+ if (!locator)
742
+ continue;
743
+ if (cacheable)
744
+ writeCachedLocator(opts?.cache, 'control', fieldLabel, exact, opts?.fieldId, locator);
745
+ return locator;
746
+ }
747
+ }
615
748
  if (cacheable)
616
749
  writeCachedLocator(opts?.cache, 'control', fieldLabel, exact, opts?.fieldId, null);
617
750
  return null;