From 0dd230fb45c5b79100fe46c5ecc57479e737745e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Adri=C3=A0=20Arrufat?= Date: Fri, 28 Aug 2026 15:12:00 +0200 Subject: [PATCH] interactive: only fall back to text content for role-less elements The bare orelse gave text-content names to roled elements the AX tree leaves unnamed (select, textarea, details). Scope the fallback to listener/tabindex-only elements, where AccName gives nothing and the text is the agent's only handle. --- src/browser/interactive.zig | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/src/browser/interactive.zig b/src/browser/interactive.zig index 5e0b36c20..5d4ac1322 100644 --- a/src/browser/interactive.zig +++ b/src/browser/interactive.zig @@ -222,8 +222,10 @@ fn walkInteractive( if (!std.ascii.eqlIgnoreCase(r, rf)) continue; } - // Names walk labels and text; filter on role first. - const name = (try axn.getName(frame, arena, &label_index)) orelse try getTextContent(node, arena); + // Names walk labels and text; filter on role first. Role-less elements + // (listener/tabindex only) sit outside AccName; their text is the only handle. + const name = try axn.getName(frame, arena, &label_index) orelse + if (role == null) try getTextContent(node, arena) else null; if (filter.name) |nf| { const n = name orelse continue; if (std.ascii.indexOfIgnoreCase(n, nf) == null) continue; @@ -516,6 +518,24 @@ test "browser.interactive: an element with no role keeps its text as name" { try testing.expectEqual("Open menu", elements[0].name.?); } +test "browser.interactive: an element with a role takes only its accessible name" { + const elements = try testInteractive( + \\ + \\ + \\
More

Content

+ ); + defer testing.test_session.closeAllPages(); + try testing.expectEqual(4, elements.len); + try testing.expectEqual("combobox", elements[0].role.?); + try testing.expectEqual(null, elements[0].name); + try testing.expectEqual("textbox", elements[1].role.?); + try testing.expectEqual(null, elements[1].name); + try testing.expectEqual("group", elements[2].role.?); + try testing.expectEqual(null, elements[2].name); + try testing.expectEqual("button", elements[3].role.?); + try testing.expectEqual("More", elements[3].name.?); +} + test "browser.interactive: button" { const elements = try testInteractive(""); defer testing.test_session.closeAllPages();