fix: fix the cli tests, generate snake python (#5003)

This commit is contained in:
Pavel Feldman 2021-01-13 12:52:03 -08:00 committed by GitHub
parent decf373c81
commit 9a9ac60d21
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 115 additions and 78 deletions

View file

@ -341,7 +341,7 @@ async function codegen(options: Options, url: string | undefined, target: string
if (process.env.PWTRACE)
contextOptions.recordVideo = { dir: path.join(process.cwd(), '.trace') };
const outputs: CodeGeneratorOutput[] = [new TerminalOutput(process.stdout, languageGenerator.highligherType())];
const outputs: CodeGeneratorOutput[] = [TerminalOutput.create(process.stdout, languageGenerator.highlighterType())];
if (outputFile)
outputs.push(new FileOutput(outputFile));
const output = new OutputMultiplexer(outputs);

View file

@ -23,7 +23,7 @@ import { MouseClickOptions, toModifiers } from '../utils';
export class CSharpLanguageGenerator implements LanguageGenerator {
highligherType(): HighlighterType {
highlighterType(): HighlighterType {
return 'csharp';
}
@ -155,7 +155,7 @@ export class CSharpLanguageGenerator implements LanguageGenerator {
}
generateFooter(saveStorage: string | undefined): string {
const storageStateLine = saveStorage ? `\nawait context.StorageStateAsync(path: "${saveStorage}")` : '';
const storageStateLine = saveStorage ? `\nawait context.StorageStateAsync(path: "${saveStorage}");` : '';
return `// ---------------------${storageStateLine}`;
}
}

View file

@ -23,7 +23,7 @@ export interface LanguageGenerator {
generateHeader(browserName: string, launchOptions: LaunchOptions, contextOptions: BrowserContextOptions, deviceName?: string): string;
generateAction(actionInContext: ActionInContext, performingAction: boolean): string;
generateFooter(saveStorage: string | undefined): string;
highligherType(): HighlighterType;
highlighterType(): HighlighterType;
}
export { JavaScriptLanguageGenerator } from './javascript';

View file

@ -23,7 +23,7 @@ import { MouseClickOptions, toModifiers } from '../utils';
export class JavaScriptLanguageGenerator implements LanguageGenerator {
highligherType(): HighlighterType {
highlighterType(): HighlighterType {
return 'javascript';
}
@ -157,7 +157,7 @@ export class JavaScriptLanguageGenerator implements LanguageGenerator {
}
generateFooter(saveStorage: string | undefined): string {
const storageStateLine = saveStorage ? `\n await context.storageState({ path: '${saveStorage}' })` : '';
const storageStateLine = saveStorage ? `\n await context.storageState({ path: '${saveStorage}' });` : '';
return ` // ---------------------${storageStateLine}
await context.close();
await browser.close();

View file

@ -32,7 +32,7 @@ export class PythonLanguageGenerator implements LanguageGenerator {
this._asyncPrefix = isAsync ? 'async ' : '';
}
highligherType(): HighlighterType {
highlighterType(): HighlighterType {
return 'python';
}
@ -43,7 +43,7 @@ export class PythonLanguageGenerator implements LanguageGenerator {
formatter.add('# ' + actionTitle(action));
if (action.name === 'openPage') {
formatter.add(`${pageAlias} = ${this._awaitPrefix}context.newPage()`);
formatter.add(`${pageAlias} = ${this._awaitPrefix}context.new_page()`);
if (action.url && action.url !== 'about:blank' && action.url !== 'chrome://newtab/')
formatter.add(`${pageAlias}.goto('${action.url}')`);
return formatter.format();
@ -155,21 +155,21 @@ from playwright.async_api import async_playwright
async def run(playwright) {
browser = await playwright.${browserName}.launch(${formatOptions(launchOptions, false)})
context = await browser.newContext(${formatContextOptions(contextOptions, deviceName)})`);
context = await browser.new_context(${formatContextOptions(contextOptions, deviceName)})`);
} else {
formatter.add(`
from playwright.sync_api import sync_playwright
def run(playwright) {
browser = playwright.${browserName}.launch(${formatOptions(launchOptions, false)})
context = browser.newContext(${formatContextOptions(contextOptions, deviceName)})`);
context = browser.new_context(${formatContextOptions(contextOptions, deviceName)})`);
}
return formatter.format();
}
generateFooter(saveStorage: string | undefined): string {
if (this._isAsync) {
const storageStateLine = saveStorage ? `\n await context.storageState(path="${saveStorage}")` : '';
const storageStateLine = saveStorage ? `\n await context.storage_state(path="${saveStorage}")` : '';
return ` # ---------------------${storageStateLine}
await context.close()
await browser.close()
@ -179,7 +179,7 @@ async def main():
await run(playwright)
asyncio.run(main())`;
} else {
const storageStateLine = saveStorage ? `\n context.storageState(path="${saveStorage}")` : '';
const storageStateLine = saveStorage ? `\n context.storage_state(path="${saveStorage}")` : '';
return ` # ---------------------${storageStateLine}
context.close()
browser.close()
@ -204,11 +204,16 @@ function formatValue(value: any): string {
return String(value);
}
function toSnakeCase(name: string): string {
const toSnakeCaseRegex = /((?<=[a-z0-9])[A-Z]|(?!^)[A-Z](?=[a-z]))/g;
return name.replace(toSnakeCaseRegex, `_$1`).toLowerCase();
}
function formatOptions(value: any, hasArguments: boolean): string {
const keys = Object.keys(value);
if (!keys.length)
return '';
return (hasArguments ? ', ' : '') + keys.map(key => `${key}=${formatValue(value[key])}`).join(', ');
return (hasArguments ? ', ' : '') + keys.map(key => `${toSnakeCase(key)}=${formatValue(value[key])}`).join(', ');
}
function formatContextOptions(options: BrowserContextOptions, deviceName: string | undefined): string {

View file

@ -42,24 +42,32 @@ export class OutputMultiplexer implements CodeGeneratorOutput {
}
}
export class FileOutput implements CodeGeneratorOutput {
private _fileName: string;
private _lines: string[];
constructor(fileName: string) {
this._fileName = fileName;
this._lines = [];
}
export class BufferOutput {
lines: string[] = [];
printLn(text: string) {
this._lines.push(...text.trimEnd().split('\n'));
this.lines.push(...text.trimEnd().split('\n'));
}
popLn(text: string) {
this._lines.length -= text.trimEnd().split('\n').length;
this.lines.length -= text.trimEnd().split('\n').length;
}
buffer(): string {
return this.lines.join('\n');
}
}
export class FileOutput extends BufferOutput implements CodeGeneratorOutput {
private _fileName: string;
constructor(fileName: string) {
super();
this._fileName = fileName;
}
flush() {
fs.writeFileSync(this._fileName, this._lines.join('\n'));
fs.writeFileSync(this._fileName, this.buffer());
}
}
@ -67,6 +75,12 @@ export class TerminalOutput implements CodeGeneratorOutput {
private _output: Writable
private _language: string;
static create(output: Writable, language: string) {
if (process.stdout.columns)
return new TerminalOutput(output, language);
return new FlushingTerminalOutput(output);
}
constructor(output: Writable, language: string) {
this._output = output;
this._language = language;
@ -112,3 +126,23 @@ export class TerminalOutput implements CodeGeneratorOutput {
flush() {}
}
export class FlushingTerminalOutput extends BufferOutput implements CodeGeneratorOutput {
private _output: Writable
constructor(output: Writable) {
super();
this._output = output;
}
printLn(text: string) {
super.printLn(text);
this._output.write('-------------8<-------------\n');
this._output.write(this.buffer() + '\n');
this._output.write('-------------8<-------------\n');
}
flush() {
this._output.write(this.buffer() + '\n');
}
}

View file

@ -136,7 +136,7 @@ it('should print load/save storageState', async ({ runCLI, testInfo }) => {
const cli = runCLI([`--load-storage=${loadFileName}`, `--save-storage=${saveFileName}`, 'codegen', '--target=csharp', emptyHTML]);
const expectedResult = `await Playwright.InstallAsync();
using var playwright = await Playwright.CreateAsync();
await using var browser = await playwright.Chromium.LaunchAsync();
await using var browser = await playwright.Chromium.LaunchAsync(headless: false);
var context = await browser.NewContextAsync(storageState: "${loadFileName}");
// Open new page

View file

@ -86,7 +86,7 @@ it('should save the codegen output to a file if specified', async ({ runCLI, tes
const tmpFile = testInfo.outputPath('script.js');
const cli = runCLI(['codegen', '--output', tmpFile, emptyHTML]);
await cli.exited;
const content = await fs.readFileSync(tmpFile);
const content = fs.readFileSync(tmpFile);
expect(content.toString()).toBe(`const { chromium } = require('playwright');
(async () => {
@ -115,7 +115,7 @@ it('should print load/save storageState', async ({ runCLI, testInfo }) => {
const saveFileName = testInfo.outputPath('save.json');
await fs.promises.writeFile(loadFileName, JSON.stringify({ cookies: [], origins: [] }), 'utf8');
const cli = runCLI([`--load-storage=${loadFileName}`, `--save-storage=${saveFileName}`, 'codegen', emptyHTML]);
const expectedResult = `const { chromium, devices } = require('playwright');
const expectedResult = `const { chromium } = require('playwright');
(async () => {
const browser = await chromium.launch({

View file

@ -29,7 +29,7 @@ from playwright.async_api import async_playwright
async def run(playwright):
browser = await playwright.chromium.launch(headless=False)
context = await browser.newContext()`;
context = await browser.new_context()`;
await cli.waitFor(expectedResult);
expect(cli.text()).toContain(expectedResult);
});
@ -41,7 +41,7 @@ from playwright.async_api import async_playwright
async def run(playwright):
browser = await playwright.chromium.launch(headless=False)
context = await browser.newContext(colorScheme="light")`;
context = await browser.new_context(color_scheme="light")`;
await cli.waitFor(expectedResult);
expect(cli.text()).toContain(expectedResult);
});
@ -53,7 +53,7 @@ from playwright.async_api import async_playwright
async def run(playwright):
browser = await playwright.chromium.launch(headless=False)
context = await browser.newContext(**playwright.devices["Pixel 2"])`;
context = await browser.new_context(**playwright.devices["Pixel 2"])`;
await cli.waitFor(expectedResult);
expect(cli.text()).toContain(expectedResult);
});
@ -65,7 +65,7 @@ from playwright.async_api import async_playwright
async def run(playwright):
browser = await playwright.chromium.launch(headless=False)
context = await browser.newContext(**playwright.devices["Pixel 2"], colorScheme="light")`;
context = await browser.new_context(**playwright.devices["Pixel 2"], color_scheme="light")`;
await cli.waitFor(expectedResult);
expect(cli.text()).toContain(expectedResult);
});
@ -80,10 +80,10 @@ from playwright.async_api import async_playwright
async def run(playwright):
browser = await playwright.chromium.launch(headless=False)
context = await browser.newContext()
context = await browser.new_context()
# Open new page
page = await context.newPage()
page = await context.new_page()
# Go to ${emptyHTML}
await page.goto("${emptyHTML}")
@ -101,29 +101,29 @@ async def main():
asyncio.run(main())`);
});
it('should print load/save storageState', async ({ runCLI, testInfo }) => {
it('should print load/save storage_state', async ({ runCLI, testInfo }) => {
const loadFileName = testInfo.outputPath('load.json');
const saveFileName = testInfo.outputPath('save.json');
await fs.promises.writeFile(loadFileName, JSON.stringify({ cookies: [], origins: [] }), 'utf8');
const cli = runCLI([`--load-storage=${loadFileName}`, `--save-storage=${saveFileName}`, 'codegen', '--target=python-async', emptyHTML]);
const expectedResult = `import asyncio
from playwright.async_api import async_playwright
from playwright.async_api import async_playwright
async def run(playwright):
browser = await playwright.chromium.launch(headless=False)
context = await browser.newContext(storageState="${loadFileName}")
async def run(playwright):
browser = await playwright.chromium.launch(headless=False)
context = await browser.new_context(storage_state="${loadFileName}")
# Open new page
page = await context.newPage()
# Open new page
page = await context.new_page()
# ---------------------
await context.storageState(path="${saveFileName}")
await context.close()
await browser.close()
# ---------------------
await context.storage_state(path="${saveFileName}")
await context.close()
await browser.close()
async def main():
async with async_playwright() as playwright:
await run(playwright)
asyncio.run(main())`;
async def main():
async with async_playwright() as playwright:
await run(playwright)
asyncio.run(main())`;
await cli.waitFor(expectedResult);
});

View file

@ -28,7 +28,7 @@ it('should print the correct imports and context options', async ({ runCLI }) =>
def run(playwright):
browser = playwright.chromium.launch(headless=False)
context = browser.newContext()`;
context = browser.new_context()`;
await cli.waitFor(expectedResult);
expect(cli.text()).toContain(expectedResult);
});
@ -39,7 +39,7 @@ it('should print the correct context options for custom settings', async ({ runC
def run(playwright):
browser = playwright.chromium.launch(headless=False)
context = browser.newContext(colorScheme="light")`;
context = browser.new_context(color_scheme="light")`;
await cli.waitFor(expectedResult);
expect(cli.text()).toContain(expectedResult);
});
@ -50,7 +50,7 @@ it('should print the correct context options when using a device', async ({ runC
def run(playwright):
browser = playwright.chromium.launch(headless=False)
context = browser.newContext(**playwright.devices["Pixel 2"])`;
context = browser.new_context(**playwright.devices["Pixel 2"])`;
await cli.waitFor(expectedResult);
expect(cli.text()).toContain(expectedResult);
});
@ -61,7 +61,7 @@ it('should print the correct context options when using a device and additional
def run(playwright):
browser = playwright.chromium.launch(headless=False)
context = browser.newContext(**playwright.devices["Pixel 2"], colorScheme="light")`;
context = browser.new_context(**playwright.devices["Pixel 2"], color_scheme="light")`;
await cli.waitFor(expectedResult);
expect(cli.text()).toContain(expectedResult);
});
@ -75,10 +75,10 @@ it('should save the codegen output to a file if specified', async ({ runCLI, tes
def run(playwright):
browser = playwright.chromium.launch(headless=False)
context = browser.newContext()
context = browser.new_context()
# Open new page
page = context.newPage()
page = context.new_page()
# Go to ${emptyHTML}
page.goto("${emptyHTML}")
@ -94,26 +94,26 @@ with sync_playwright() as playwright:
run(playwright)`);
});
it('should print load/save storageState', async ({ runCLI, testInfo }) => {
it('should print load/save storage_state', async ({ runCLI, testInfo }) => {
const loadFileName = testInfo.outputPath('load.json');
const saveFileName = testInfo.outputPath('save.json');
await fs.promises.writeFile(loadFileName, JSON.stringify({ cookies: [], origins: [] }), 'utf8');
const cli = runCLI([`--load-storage=${loadFileName}`, `--save-storage=${saveFileName}`, 'codegen', '--target=python', emptyHTML]);
const expectedResult = `from playwright.sync_api import sync_playwright
def run(playwright):
browser = playwright.chromium.launch(headless=False)
context = browser.newContext(storageState="${loadFileName}")
def run(playwright):
browser = playwright.chromium.launch(headless=False)
context = browser.new_context(storage_state="${loadFileName}")
# Open new page
page = context.newPage()
# Open new page
page = context.new_page()
# ---------------------
context.storageState(path="${saveFileName}")
context.close()
browser.close()
# ---------------------
context.storage_state(path="${saveFileName}")
context.close()
browser.close()
with sync_playwright() as playwright:
run(playwright)`;
with sync_playwright() as playwright:
run(playwright)`;
await cli.waitFor(expectedResult);
});

View file

@ -197,7 +197,7 @@ fixtures.runCLI.init(async ({ }, runTest) => {
return cli;
};
await runTest(cliFactory);
cli.kill();
await cli.exited;
});
class CLIMock {
@ -216,18 +216,20 @@ class CLIMock {
env: {
...process.env,
PWCLI_EXIT_FOR_TEST: '1'
}
},
stdio: 'pipe'
});
this.process.stdout.on('data', line => {
this.data += removeAnsiColors(line.toString());
this.process.stdout.on('data', data => {
this.data = data.toString();
if (this.waitForCallback && this.data.includes(this.waitForText))
this.waitForCallback();
});
this.exited = new Promise<void>(r => this.process.on('exit', () => {
if (this.waitForCallback)
this.waitForCallback();
return r();
}));
this.exited = new Promise((f, r) => {
this.process.stderr.on('data', data => {
r(new Error(data));
});
this.process.on('exit', f);
});
}
async waitFor(text: string): Promise<void> {
@ -240,10 +242,6 @@ class CLIMock {
text() {
return removeAnsiColors(this.data);
}
kill() {
this.process.kill();
}
}
interface httpServer {