diff --git a/packages/playwright-core/src/server/injected/roleUtils.ts b/packages/playwright-core/src/server/injected/roleUtils.ts
index 99f3cafa29..498fc189aa 100644
--- a/packages/playwright-core/src/server/injected/roleUtils.ts
+++ b/packages/playwright-core/src/server/injected/roleUtils.ts
@@ -375,7 +375,8 @@ function getPseudoContent(element: Element, pseudo: '::before' | '::after') {
}
function getPseudoContentImpl(pseudoStyle: CSSStyleDeclaration | undefined) {
- if (!pseudoStyle)
+ // Note: all browsers ignore display:none and visibility:hidden pseudos.
+ if (!pseudoStyle || pseudoStyle.display === 'none' || pseudoStyle.visibility === 'hidden')
return '';
const content = pseudoStyle.content;
if ((content[0] === '\'' && content[content.length - 1] === '\'') ||
diff --git a/tests/library/role-utils.spec.ts b/tests/library/role-utils.spec.ts
index 067053ba11..6c45686f68 100644
--- a/tests/library/role-utils.spec.ts
+++ b/tests/library/role-utils.spec.ts
@@ -475,6 +475,26 @@ test('should ignore stylesheet from hidden aria-labelledby subtree', async ({ pa
expect.soft(await getNameAndRole(page, 'input')).toEqual({ role: 'textbox', name: 'hello' });
});
+test('should not include hidden pseudo into accessible name', async ({ page }) => {
+ await page.setContent(`
+
+
+ hello
+ hello
+
+ `);
+ expect.soft(await getNameAndRole(page, 'a')).toEqual({ role: 'link', name: 'hello hello' });
+});
+
function toArray(x: any): any[] {
return Array.isArray(x) ? x : [x];
}