diff --git a/packages/playwright-core/src/server/injected/ariaSnapshot.ts b/packages/playwright-core/src/server/injected/ariaSnapshot.ts
index 84537cddd7d94..ee27cbceeb35e 100644
--- a/packages/playwright-core/src/server/injected/ariaSnapshot.ts
+++ b/packages/playwright-core/src/server/injected/ariaSnapshot.ts
@@ -16,7 +16,7 @@
import * as roleUtils from './roleUtils';
import { getElementComputedStyle } from './domUtils';
-import { escapeRegExp, longestCommonSubstring } from '@isomorphic/stringUtils';
+import { escapeRegExp, longestCommonSubstring, normalizeWhiteSpace } from '@isomorphic/stringUtils';
import { yamlEscapeKeyIfNeeded, yamlEscapeValueIfNeeded } from './yaml';
import type { AriaProps, AriaRole, AriaTemplateNode, AriaTemplateRoleNode, AriaTemplateTextNode } from '@isomorphic/ariaSnapshot';
@@ -137,7 +137,7 @@ function toAriaNode(element: Element): AriaNode | null {
if (!role || role === 'presentation' || role === 'none')
return null;
- const name = roleUtils.getElementAccessibleName(element, false) || '';
+ const name = normalizeWhiteSpace(roleUtils.getElementAccessibleName(element, false) || '');
const result: AriaNode = { role, name, children: [], element };
if (roleUtils.kAriaCheckedRoles.includes(role))
@@ -170,7 +170,7 @@ function normalizeStringChildren(rootA11yNode: AriaNode) {
const flushChildren = (buffer: string[], normalizedChildren: (AriaNode | string)[]) => {
if (!buffer.length)
return;
- const text = normalizeWhitespaceWithin(buffer.join('')).trim();
+ const text = normalizeWhiteSpace(buffer.join(''));
if (text)
normalizedChildren.push(text);
buffer.length = 0;
@@ -196,8 +196,6 @@ function normalizeStringChildren(rootA11yNode: AriaNode) {
visit(rootA11yNode);
}
-const normalizeWhitespaceWithin = (text: string) => text.replace(/[\u200b\s\t\r\n]+/g, ' ');
-
function matchesText(text: string, template: RegExp | string | undefined): boolean {
if (!template)
return true;
diff --git a/packages/playwright-core/src/utils/isomorphic/ariaSnapshot.ts b/packages/playwright-core/src/utils/isomorphic/ariaSnapshot.ts
index 67db4651494ba..59b26ec04929a 100644
--- a/packages/playwright-core/src/utils/isomorphic/ariaSnapshot.ts
+++ b/packages/playwright-core/src/utils/isomorphic/ariaSnapshot.ts
@@ -212,7 +212,7 @@ class KeyParser {
const ch = this._peek();
if (ch === '"') {
this._next();
- return this._readString();
+ return normalizeWhitespace(this._readString());
}
if (ch === '/') {
diff --git a/tests/page/page-aria-snapshot.spec.ts b/tests/page/page-aria-snapshot.spec.ts
index b7bb77091aef1..878262400d950 100644
--- a/tests/page/page-aria-snapshot.spec.ts
+++ b/tests/page/page-aria-snapshot.spec.ts
@@ -509,6 +509,32 @@ it('should escape yaml text in text nodes', async ({ page }) => {
`);
});
+it('should normalize whitespace', async ({ page }) => {
+ await page.setContent(`
+
+ one \n two link \n 1
+
+
+ `);
+
+ await checkAndMatchSnapshot(page.locator('body'), `
+ - group:
+ - text: one two
+ - link "link 1"
+ - textbox: hello world
+ `);
+
+ // Weird whitespace in the template should be normalized.
+ await expect(page.locator('body')).toMatchAriaSnapshot(`
+ - group:
+ - text: |
+ one
+ two
+ - link " link 1 "
+ - textbox: hello world
+ `);
+});
+
it('should handle long strings', async ({ page }) => {
const s = 'a'.repeat(10000);
await page.setContent(`