Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions packages/injected/src/ariaSnapshot.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,14 @@ type AriaRef = {

let lastRef = 0;

function isVisible(element: Element, options?: { forAI?: boolean }): boolean {
if (!roleUtils.isElementHiddenForAria(element))
return true;
if (options?.forAI && isElementVisible(element))
return true;
return false;
}

export function generateAriaTree(rootElement: Element, options?: { forAI?: boolean, refPrefix?: string }): AriaSnapshot {
const visited = new Set<Node>();

Expand All @@ -61,6 +69,9 @@ export function generateAriaTree(rootElement: Element, options?: { forAI?: boole
visited.add(node);

if (node.nodeType === Node.TEXT_NODE && node.nodeValue) {
if (node.parentElement && !isVisible(node.parentElement, options))
return;

const text = node.nodeValue;
// <textarea>AAA</textarea> should not report AAA as a child of the textarea.
if (ariaNode.role !== 'textbox' && text)
Expand All @@ -72,11 +83,12 @@ export function generateAriaTree(rootElement: Element, options?: { forAI?: boole
return;

const element = node as Element;
let isVisible = !roleUtils.isElementHiddenForAria(element);
if (options?.forAI)
isVisible = isVisible || isElementVisible(element);
if (!isVisible)
if (!isVisible(element, options)) {
if (options?.forAI)
// skip this element, but still process its children https://github.com/microsoft/playwright/issues/36296
processElement(ariaNode, element, []);
return;
}

const ariaChildren: Element[] = [];
if (element.hasAttribute('aria-owns')) {
Expand Down
13 changes: 13 additions & 0 deletions tests/page/page-aria-snapshot-ai.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -252,3 +252,16 @@ it('should auto-wait for blocking CSS', async ({ page, server }) => {
`, { waitUntil: 'commit' });
expect(await snapshotForAI(page)).toContainYaml('Hello World');
});

it('should show visible children of hidden elements', { annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/36296' } }, async ({ page }) => {
await page.setContent(`
<div style="visibility: hidden;">
<div style="visibility: visible;">
<button>Foo</button>
</div>
<button>Bar</button>
</div>
`);

expect(await snapshotForAI(page)).toEqual(`- button "Foo" [ref=e3]`);
});
24 changes: 24 additions & 0 deletions tests/page/page-aria-snapshot.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -658,3 +658,27 @@ it('should not report textarea textContent', async ({ page }) => {
- textbox: After
`);
});

it('should not show visible children of hidden elements', { annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/36296' } }, async ({ page }) => {
await page.setContent(`
<div style="visibility: hidden;">
<div style="visibility: visible;">
<button>Button</button>
</div>
</div>
`);

expect(await page.locator('body').ariaSnapshot()).toBe('');
});

it('should not show unhidden children of aria-hidden elements', { annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright/issues/36296' } }, async ({ page }) => {
await page.setContent(`
<div aria-hidden="true">
<div aria-hidden="false">
<button>Button</button>
</div>
</div>
`);

expect(await page.locator('body').ariaSnapshot()).toBe('');
});
Loading