diff --git a/internal/driver/chrome/driver.go b/internal/driver/chrome/driver.go index 074cae3..fac3554 100644 --- a/internal/driver/chrome/driver.go +++ b/internal/driver/chrome/driver.go @@ -393,6 +393,14 @@ func (d *Driver) Hierarchy(ctx context.Context) (string, error) { // root a full-viewport tap target here and nowhere else. const NON_TEXT_INPUT_TYPES = ['button','submit','checkbox','radio','range','color','file','image','reset']; + // The disabled property belongs to real form controls only, so it reads + // undefined on the role-based controls the tappable set now covers, and every + // one of them looked enabled however plainly it was marked otherwise. + // isEnabled in pkg/spec/src/web-runtime.ts answers the same two ways. + function isEnabled(el) { + if (el.disabled) return false; + return el.getAttribute('aria-disabled') !== 'true'; + } function isEditableElement(el) { if (el.isContentEditable) return true; const tag = el.tagName.toLowerCase(); @@ -465,7 +473,7 @@ func (d *Driver) Hierarchy(ctx context.Context) (string, error) { attributes: attrs, children: children, clickable: isClickable || null, - enabled: (!el.disabled) || null, + enabled: isEnabled(el) || null, focused: document.activeElement === el || null, checked: el.checked || null, selected: el.selected || null, diff --git a/internal/driver/chrome/testdata/fact-parity.html b/internal/driver/chrome/testdata/fact-parity.html index c29d0ed..c378ec9 100644 --- a/internal/driver/chrome/testdata/fact-parity.html +++ b/internal/driver/chrome/testdata/fact-parity.html @@ -71,6 +71,7 @@
tree item
attribute click
delegating root
diff --git a/pkg/spec/src/web-runtime.ts b/pkg/spec/src/web-runtime.ts index 5e4b89b..24deca8 100644 --- a/pkg/spec/src/web-runtime.ts +++ b/pkg/spec/src/web-runtime.ts @@ -328,6 +328,16 @@ function selectorTag(selector: unknown): string { return ""; } +// isEnabled answers the `enabled` fact. `.disabled` is a property only real form +// controls have, so it reads undefined on the role-based controls the tappable +// set now covers, and every one of them looked enabled however plainly it was +// marked otherwise. internal/driver/chrome/driver.go answers the same two ways +// for the dump the goja host reads. +function isEnabled(element: Element): boolean { + if ((element as HTMLButtonElement).disabled) return false; + return element.getAttribute("aria-disabled") !== "true"; +} + function elementHandle(element: Element, selector: unknown): Record { const rect = element.getBoundingClientRect(); const x = Math.round(rect.left + rect.width / 2); @@ -346,7 +356,7 @@ function elementHandle(element: Element, selector: unknown): Record