From 913616f5c4c9574329557955d2320ceb7b2b3fad Mon Sep 17 00:00:00 2001 From: Karn Date: Mon, 28 Sep 2026 22:07:11 +0530 Subject: [PATCH 1/3] ci(release): install Chrome for the browser suite, as ci.yml does The release job ran pnpm test against whatever Chrome the runner had preinstalled, and failed once in the browser suite's setup hook. Use the same setup-chrome step and REINS_TEST_CHROME env as ci.yml. Co-Authored-By: Claude Opus 5.5 --- .github/workflows/release.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c4afa59..cd775c2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -26,10 +26,16 @@ jobs: steps: - uses: actions/checkout@v7.0.0 - uses: jdx/mise-action@v4.2.0 + # Same Chrome as ci.yml, so the extension's real-browser suite runs the + # same way here as it did on the PR. + - uses: browser-actions/setup-chrome@v2.2.0 + id: chrome - run: pnpm install --frozen-lockfile - run: pnpm lint - run: pnpm typecheck - run: pnpm test + env: + REINS_TEST_CHROME: ${{ steps.chrome.outputs.chrome-path }} - run: pnpm build - name: Version or publish (changesets) From 309d51b5447dd1035debd8b5313249d25c1dd7c1 Mon Sep 17 00:00:00 2001 From: Karn Date: Mon, 28 Sep 2026 22:16:34 +0530 Subject: [PATCH 2/3] fix(extension): step commands see shadow DOM and custom controls reins snapshot walked document.querySelectorAll only, so controls in web components (MDN's search button, openlibrary's Sort by menu) never got a ref. It now reuses reins do's page helpers, moved to page-dom.ts: it walks open shadow roots and names elements through aria-labelledby, labels, shadow roots and slots. Refs resolve through open shadow roots for click, type, fill, hover, select, scroll, text, wait and upload. --selector stays light-DOM CSS. "element has zero size" on the wizard's Team card and the settings switches came from stale refs: a snapshot never cleared the previous one's data-reins-ref tags, so an element hidden since (the wizard step or tab panel just left) kept e8 while the new snapshot gave e8 to the switch, and querySelector found the hidden one first. Each snapshot now clears the old tags before tagging. actionPoint also presses a stand-in for a target with no box: a 0x0 or display:none native radio/checkbox is pressed through its visible label or the custom radio/switch/checkbox/option it sits in, and a display:contents element through its first rendered child. Disabled, covered and moving checks apply to the element pressed, and disabled to the original too. The hit test now walks the flat tree (assignedSlot), so a caption slotted through two shadow roots counts as inside its button. Co-Authored-By: Claude Opus 5.5 --- .changeset/step-commands-shadow-dom.md | 6 + packages/extension/src/lib/actionability.ts | 70 ++++++- packages/extension/src/lib/cdp.test.ts | 41 +++- packages/extension/src/lib/cdp.ts | 67 ++++--- packages/extension/src/lib/jev-snapshot.ts | 139 +------------- packages/extension/src/lib/jev.ts | 7 +- .../extension/src/lib/page-actions.test.ts | 23 +++ packages/extension/src/lib/page-actions.ts | 34 +++- packages/extension/src/lib/page-dom.ts | 177 ++++++++++++++++++ .../extension/src/lib/pointer.browser.test.ts | 127 ++++++++++++- packages/extension/src/lib/snapshot.ts | 41 ++++ packages/web/src/routes/docs/commands.tsx | 3 +- skills/reins/SKILL.md | 9 +- 13 files changed, 553 insertions(+), 191 deletions(-) create mode 100644 .changeset/step-commands-shadow-dom.md create mode 100644 packages/extension/src/lib/page-dom.ts create mode 100644 packages/extension/src/lib/snapshot.ts diff --git a/.changeset/step-commands-shadow-dom.md b/.changeset/step-commands-shadow-dom.md new file mode 100644 index 0000000..6e2a5b4 --- /dev/null +++ b/.changeset/step-commands-shadow-dom.md @@ -0,0 +1,6 @@ +--- +"@karnstack/reins": patch +"@reins/extension": patch +--- + +Step commands see web components and custom controls. `reins snapshot` now lists elements inside open shadow roots (a site's search button, a `Sort by` menu built as a web component) and names them the way `reins do` does — through `aria-labelledby`, labels, shadow roots and slots — and `--ref` reaches them in `click`, `type`, `fill`, `hover`, `select` and the rest. `--selector` stays light-DOM CSS. Each snapshot now re-issues its refs, so a ref no longer lands on an element hidden since the previous snapshot (the "element has zero size" failures on wizards and tab panels). A click on a control with no box of its own — a native radio or checkbox shrunk to 0×0 under a styled card, or a `display: contents` wrapper — presses its visible label, custom radio/switch it sits in, or first rendered child instead. diff --git a/packages/extension/src/lib/actionability.ts b/packages/extension/src/lib/actionability.ts index 26fcf44..45ba446 100644 --- a/packages/extension/src/lib/actionability.ts +++ b/packages/extension/src/lib/actionability.ts @@ -35,7 +35,16 @@ export type ProbeResult = ( * reaches the element; read it back with `readProbe`. * * With `node`, the target is the Jev node cache entry (`reins do` observed it - * by id); `selector` then only names it in messages. + * by id); with `locate`, whatever that function returns (a ref looked up + * through shadow roots). `selector` then only names it in messages. + * + * A target with no box of its own is pressed where it shows: a native radio + * or checkbox shrunk to 0×0 (or display:none) under a styled card is pressed + * through its visible