Replace focusable/focused with active attribute in aria snapshot

Co-authored-by: yury-s <9798949+yury-s@users.noreply.github.com>
This commit is contained in:
copilot-swe-agent[bot] 2025-05-23 01:15:08 +00:00
parent c9453ede0c
commit 77835061b9
7 changed files with 16 additions and 38 deletions

View File

@ -31,8 +31,7 @@ export type AriaNode = AriaProps & {
element: Element;
box: Box;
receivesPointerEvents: boolean;
focused?: boolean;
focusable?: boolean;
active?: boolean;
props: Record<string, string>;
};
@ -195,8 +194,7 @@ function toAriaNode(element: Element, options?: { forAI?: boolean, refPrefix?: s
element,
box: box(element),
receivesPointerEvents,
focused: element.ownerDocument.activeElement === element,
focusable: roleUtils.isFocusable(element)
active: element.ownerDocument.activeElement === element
};
if (roleUtils.kAriaCheckedRoles.includes(role))
@ -435,10 +433,8 @@ export function renderAriaTree(ariaSnapshot: AriaSnapshot, options?: { mode?: 'r
key += ` [disabled]`;
if (ariaNode.expanded)
key += ` [expanded]`;
if (ariaNode.focused)
key += ` [focused]`;
if (ariaNode.focusable)
key += ` [focusable]`;
if (ariaNode.active)
key += ` [active]`;
if (ariaNode.level)
key += ` [level=${ariaNode.level}]`;
if (ariaNode.pressed === 'mixed')

View File

@ -66,7 +66,7 @@ function hasTabIndex(element: Element) {
return !Number.isNaN(Number(String(element.getAttribute('tabindex'))));
}
export function isFocusable(element: Element) {
function isFocusable(element: Element) {
// TODO:
// - "inert" attribute makes the whole substree not focusable
// - when dialog is open on the page - everything but the dialog is not focusable

View File

@ -254,9 +254,6 @@ class CRAXNode implements accessibility.AXNode {
continue;
node[booleanProperty] = value;
}
// Add focusable property
node.focusable = this._focusable;
const numericalProperties: Array<keyof channels.AXNode> = [
'level',
'valuemax',

View File

@ -234,10 +234,6 @@ class FFAXNode implements accessibility.AXNode {
continue;
node[booleanProperty] = value;
}
// Add focusable property
node.focusable = this._focusable;
const numericalProperties: Array<keyof channels.AXNode & keyof Protocol.Accessibility.AXTree> = [
'level'
];

View File

@ -225,9 +225,6 @@ class WKAXNode implements accessibility.AXNode {
continue;
(node as any)[booleanProperty] = value;
}
// Add focusable property
node.focusable = this._payload.focusable;
const numericalProperties: Array<keyof channels.AXNode & keyof Protocol.Page.AXNode> = [
'level',

View File

@ -28,8 +28,7 @@ export type AriaProps = {
checked?: boolean | 'mixed';
disabled?: boolean;
expanded?: boolean;
focused?: boolean;
focusable?: boolean;
active?: boolean;
level?: number;
pressed?: boolean | 'mixed';
selected?: boolean;
@ -445,14 +444,9 @@ export class KeyParser {
node.expanded = value === 'true';
return;
}
if (key === 'focused') {
this._assert(value === 'true' || value === 'false', 'Value of "focused" attribute must be a boolean', errorPos);
node.focused = value === 'true';
return;
}
if (key === 'focusable') {
this._assert(value === 'true' || value === 'false', 'Value of "focusable" attribute must be a boolean', errorPos);
node.focusable = value === 'true';
if (key === 'active') {
this._assert(value === 'true' || value === 'false', 'Value of "active" attribute must be a boolean', errorPos);
node.active = value === 'true';
return;
}
if (key === 'level') {

View File

@ -232,7 +232,7 @@ it('should gracefully fallback when child frame cant be captured', async ({ page
`);
});
it('should include focused and focusable information', async ({ page }) => {
it('should include active element information', async ({ page }) => {
await page.setContent(`
<button id="btn1">Button 1</button>
<button id="btn2" autofocus>Button 2</button>
@ -241,17 +241,15 @@ it('should include focused and focusable information', async ({ page }) => {
const snapshot = await snapshotForAI(page);
// Check for Button 1 with focusable attribute
// Check for Button 1
expect(snapshot).toContain('button "Button 1"');
expect(snapshot).toContain('[focusable]');
// Check for Button 2 with focusable attribute
// Check for Button 2
expect(snapshot).toContain('button "Button 2"');
expect(snapshot).toMatch(/Button 2.*\[focusable\]/);
// Check that there's a focused element somewhere in the snapshot
expect(snapshot).toContain('[focused]');
// Check that there's an active element somewhere in the snapshot
expect(snapshot).toContain('[active]');
// Check for the non-focusable div
// Check for the div
expect(snapshot).toContain('Not focusable');
});