diff --git a/packages/playwright-core/src/server/injected/yaml.ts b/packages/playwright-core/src/server/injected/yaml.ts
index e87c6706dea79..7daebc574a5cf 100644
--- a/packages/playwright-core/src/server/injected/yaml.ts
+++ b/packages/playwright-core/src/server/injected/yaml.ts
@@ -62,12 +62,8 @@ function yamlStringNeedsQuotes(str: string): boolean {
if (/^-\s/.test(str))
return true;
- // Strings that start with a special indicator character need quotes
- if (/^[&*\],].*/.test(str))
- return true;
-
- // Strings containing ':' followed by a space or at the end need quotes
- if (/:(\s|$)/.test(str))
+ // Strings containing ':' or '\n' followed by a space or at the end need quotes
+ if (/[\n:](\s|$)/.test(str))
return true;
// Strings containing '#' preceded by a space need quotes (comment indicator)
@@ -78,21 +74,17 @@ function yamlStringNeedsQuotes(str: string): boolean {
if (/[\n\r]/.test(str))
return true;
- // Strings starting with '?' or '!' (directives) need quotes
- if (/^[?!]/.test(str))
- return true;
-
- // Strings starting with '>' or '|' (block scalar indicators) need quotes
- if (/^[>|]/.test(str))
- return true;
-
- // Strings starting with quotes need quotes
- if (/^["']/.test(str))
+ // Strings starting with indicator characters or quotes need quotes
+ if (/^[&*\],?!>|@"'#%]/.test(str))
return true;
// Strings containing special characters that could cause ambiguity
if (/[{}`]/.test(str))
return true;
+ // Non-string types recognized by YAML
+ if (!isNaN(Number(str)) || ['y', 'n', 'yes', 'no', 'true', 'false', 'on', 'off', 'null'].includes(str.toLowerCase()))
+ return true;
+
return false;
}
diff --git a/tests/page/page-aria-snapshot.spec.ts b/tests/page/page-aria-snapshot.spec.ts
index 6b37438419b7a..2289e59d74113 100644
--- a/tests/page/page-aria-snapshot.spec.ts
+++ b/tests/page/page-aria-snapshot.spec.ts
@@ -509,3 +509,57 @@ it('should handle long strings', async ({ page }) => {
- region: ${s}
`);
});
+
+it('should escape special yaml characters', async ({ page }) => {
+ await page.setContent(`
+ @hello@hello
+ ]hello]hello
+ hello\n
+ hello\n\n hello\n hello
+ #hello#hello
+ `);
+
+ await checkAndMatchSnapshot(page.locator('body'), `
+ - link "@hello"
+ - text: "@hello"
+ - link "]hello"
+ - text: "]hello"
+ - link "hello"
+ - text: hello
+ - link "hello"
+ - text: hello
+ - link "#hello"
+ - text: "#hello"
+ `);
+});
+
+it('should escape special yaml values', async ({ page }) => {
+ await page.setContent(`
+ trueFalse
+ NOyes
+ yN
+ onOff
+ nullNULL
+ 123123
+ -1.2-1.2
+
+ `);
+
+ await checkAndMatchSnapshot(page.locator('body'), `
+ - link "true"
+ - text: "False"
+ - link "NO"
+ - text: "yes"
+ - link "y"
+ - text: "N"
+ - link "on"
+ - text: "Off"
+ - link "null"
+ - text: "NULL"
+ - link "123"
+ - text: "123"
+ - link "-1.2"
+ - text: "-1.2"
+ - textbox: "555"
+ `);
+});