mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
fix(codegen): escape tricky characters (#8350)
This commit is contained in:
parent
026426227d
commit
60829f8909
@ -18,7 +18,7 @@ import type { BrowserContextOptions } from '../../../..';
|
||||
import { LanguageGenerator, LanguageGeneratorOptions, sanitizeDeviceOptions, toSignalMap } from './language';
|
||||
import { ActionInContext } from './codeGenerator';
|
||||
import { actionTitle, Action } from './recorderActions';
|
||||
import { MouseClickOptions, toModifiers } from './utils';
|
||||
import { escapeWithQuotes, MouseClickOptions, toModifiers } from './utils';
|
||||
import deviceDescriptors from '../../deviceDescriptors';
|
||||
|
||||
export class CSharpLanguageGenerator implements LanguageGenerator {
|
||||
@ -266,5 +266,5 @@ class CSharpFormatter {
|
||||
}
|
||||
|
||||
function quote(text: string) {
|
||||
return `"${text.replace(/["]/g, '\\"')}"`;
|
||||
return escapeWithQuotes(text, '\"');
|
||||
}
|
||||
@ -18,7 +18,7 @@ import type { BrowserContextOptions } from '../../../..';
|
||||
import { LanguageGenerator, LanguageGeneratorOptions, toSignalMap } from './language';
|
||||
import { ActionInContext } from './codeGenerator';
|
||||
import { Action, actionTitle } from './recorderActions';
|
||||
import { MouseClickOptions, toModifiers } from './utils';
|
||||
import { escapeWithQuotes, MouseClickOptions, toModifiers } from './utils';
|
||||
import deviceDescriptors from '../../deviceDescriptors';
|
||||
import { JavaScriptFormatter } from './javascript';
|
||||
|
||||
@ -228,12 +228,6 @@ function formatClickOptions(options: MouseClickOptions, isPage: boolean) {
|
||||
return lines.join('\n');
|
||||
}
|
||||
|
||||
function quote(text: string, char: string = '\"') {
|
||||
if (char === '\'')
|
||||
return char + text.replace(/[']/g, '\\\'') + char;
|
||||
if (char === '"')
|
||||
return char + text.replace(/["]/g, '\\"') + char;
|
||||
if (char === '`')
|
||||
return char + text.replace(/[`]/g, '\\`') + char;
|
||||
throw new Error('Invalid escape char');
|
||||
function quote(text: string) {
|
||||
return escapeWithQuotes(text, '\"');
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ import type { BrowserContextOptions } from '../../../..';
|
||||
import { LanguageGenerator, LanguageGeneratorOptions, sanitizeDeviceOptions, toSignalMap } from './language';
|
||||
import { ActionInContext } from './codeGenerator';
|
||||
import { Action, actionTitle } from './recorderActions';
|
||||
import { MouseClickOptions, toModifiers } from './utils';
|
||||
import { escapeWithQuotes, MouseClickOptions, toModifiers } from './utils';
|
||||
import deviceDescriptors from '../../deviceDescriptors';
|
||||
|
||||
export class JavaScriptLanguageGenerator implements LanguageGenerator {
|
||||
@ -275,12 +275,6 @@ export class JavaScriptFormatter {
|
||||
}
|
||||
}
|
||||
|
||||
function quote(text: string, char: string = '\'') {
|
||||
if (char === '\'')
|
||||
return char + text.replace(/[']/g, '\\\'') + char;
|
||||
if (char === '"')
|
||||
return char + text.replace(/["]/g, '\\"') + char;
|
||||
if (char === '`')
|
||||
return char + text.replace(/[`]/g, '\\`') + char;
|
||||
throw new Error('Invalid escape char');
|
||||
function quote(text: string) {
|
||||
return escapeWithQuotes(text, '\'');
|
||||
}
|
||||
|
||||
@ -18,7 +18,7 @@ import type { BrowserContextOptions } from '../../../..';
|
||||
import { LanguageGenerator, LanguageGeneratorOptions, sanitizeDeviceOptions, toSignalMap } from './language';
|
||||
import { ActionInContext } from './codeGenerator';
|
||||
import { actionTitle, Action } from './recorderActions';
|
||||
import { MouseClickOptions, toModifiers } from './utils';
|
||||
import { escapeWithQuotes, MouseClickOptions, toModifiers } from './utils';
|
||||
import deviceDescriptors from '../../deviceDescriptors';
|
||||
|
||||
export class PythonLanguageGenerator implements LanguageGenerator {
|
||||
@ -264,12 +264,6 @@ class PythonFormatter {
|
||||
}
|
||||
}
|
||||
|
||||
function quote(text: string, char: string = '\"') {
|
||||
if (char === '\'')
|
||||
return char + text.replace(/[']/g, '\\\'') + char;
|
||||
if (char === '"')
|
||||
return char + text.replace(/["]/g, '\\"') + char;
|
||||
if (char === '`')
|
||||
return char + text.replace(/[`]/g, '\\`') + char;
|
||||
throw new Error('Invalid escape char');
|
||||
function quote(text: string) {
|
||||
return escapeWithQuotes(text, '\"');
|
||||
}
|
||||
|
||||
@ -56,3 +56,15 @@ export function describeFrame(frame: Frame): { frameName?: string, frameUrl: str
|
||||
return { isMainFrame: false, frameUrl: frame.url(), frameName: frame.name() };
|
||||
return { isMainFrame: false, frameUrl: frame.url() };
|
||||
}
|
||||
|
||||
export function escapeWithQuotes(text: string, char: string = '\'') {
|
||||
const stringified = JSON.stringify(text);
|
||||
const escapedText = stringified.substring(1, stringified.length - 1).replace(/\\"/g, '"');
|
||||
if (char === '\'')
|
||||
return char + escapedText.replace(/[']/g, '\\\'') + char;
|
||||
if (char === '"')
|
||||
return char + escapedText.replace(/["]/g, '\\"') + char;
|
||||
if (char === '`')
|
||||
return char + escapedText.replace(/[`]/g, '`') + char;
|
||||
throw new Error('Invalid escape char');
|
||||
}
|
||||
|
||||
@ -645,4 +645,40 @@ test.describe('cli codegen', () => {
|
||||
await cli.exited;
|
||||
expect(fs.existsSync(traceFileName)).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should fill tricky characters', async ({ page, openRecorder }) => {
|
||||
const recorder = await openRecorder();
|
||||
|
||||
await recorder.setContentAndWait(`<textarea id="textarea" name="name" oninput="console.log(textarea.value)"></textarea>`);
|
||||
const selector = await recorder.focusElement('textarea');
|
||||
expect(selector).toBe('textarea[name="name"]');
|
||||
|
||||
const [message, sources] = await Promise.all([
|
||||
page.waitForEvent('console', msg => msg.type() !== 'error'),
|
||||
recorder.waitForOutput('JavaScript', 'fill'),
|
||||
page.fill('textarea', 'Hello\'\"\`\nWorld')
|
||||
]);
|
||||
|
||||
expect(sources.get('JavaScript').text).toContain(`
|
||||
// Fill textarea[name="name"]
|
||||
await page.fill('textarea[name="name"]', 'Hello\\'"\`\\nWorld');`);
|
||||
expect(sources.get('Java').text).toContain(`
|
||||
// Fill textarea[name="name"]
|
||||
page.fill("textarea[name=\\\"name\\\"]", "Hello'\\"\`\\nWorld");`);
|
||||
|
||||
expect(sources.get('Python').text).toContain(`
|
||||
# Fill textarea[name="name"]
|
||||
page.fill(\"textarea[name=\\\"name\\\"]\", \"Hello'\\"\`\\nWorld\")`);
|
||||
|
||||
expect(sources.get('Python Async').text).toContain(`
|
||||
# Fill textarea[name="name"]
|
||||
await page.fill(\"textarea[name=\\\"name\\\"]\", \"Hello'\\"\`\\nWorld\")`);
|
||||
|
||||
expect(sources.get('C#').text).toContain(`
|
||||
// Fill textarea[name="name"]
|
||||
await page.FillAsync(\"textarea[name=\\\"name\\\"]\", \"Hello'\\"\`\\nWorld\");`);
|
||||
|
||||
expect(message.text()).toBe('Hello\'\"\`\nWorld');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user