fix(codegen): escape tricky characters (#8350)

This commit is contained in:
Joel Einbinder 2021-08-23 12:22:19 -04:00 committed by GitHub
parent 026426227d
commit 60829f8909
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 59 additions and 29 deletions

View File

@ -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, '\"');
}

View File

@ -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, '\"');
}

View File

@ -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, '\'');
}

View File

@ -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, '\"');
}

View File

@ -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');
}

View File

@ -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');
});
});