mirror of
https://github.com/microsoft/playwright-cli.git
synced 2026-09-14 19:59:39 +08:00
feat: refactoring to provide cross-lang support (#64)
This commit is contained in:
+6
-3
@@ -21,8 +21,9 @@ import * as os from 'os';
|
||||
import * as playwright from 'playwright';
|
||||
import { Browser, BrowserContext, Page } from 'playwright';
|
||||
import { ScriptController } from './scriptController';
|
||||
import { OutputMultiplexer, TerminalOutput, FileOutput } from './outputs'
|
||||
import { CodeGeneratorOutput } from './codeGenerator';
|
||||
import { OutputMultiplexer, TerminalOutput, FileOutput } from './codegen/outputs'
|
||||
import { CodeGeneratorOutput } from './codegen/codeGenerator';
|
||||
import { JavaScriptLanguageGenerator } from './codegen/languages';
|
||||
|
||||
program
|
||||
.version('Version ' + require('../package.json').version)
|
||||
@@ -252,7 +253,9 @@ async function open(options: Options, url: string | undefined, enableRecorder: b
|
||||
const outputs: CodeGeneratorOutput[] = [new TerminalOutput(process.stdout)];
|
||||
if (outputFile)
|
||||
outputs.push(new FileOutput(outputFile));
|
||||
new ScriptController(browserName, launchOptions, contextOptions, context, new OutputMultiplexer(outputs), enableRecorder, options.device);
|
||||
const output = new OutputMultiplexer(outputs)
|
||||
const languageGenerator = new JavaScriptLanguageGenerator(output)
|
||||
new ScriptController(browserName, launchOptions, contextOptions, context, output, languageGenerator, enableRecorder, options.device);
|
||||
await openPage(context, url);
|
||||
if (process.env.PWCLI_EXIT_FOR_TEST)
|
||||
await Promise.all(context.pages().map(p => p.close()))
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as playwright from 'playwright';
|
||||
import { Frame } from 'playwright';
|
||||
import { LanguageGenerator } from './languages'
|
||||
import { Action, Signal } from './recorderActions';
|
||||
|
||||
export type ActionInContext = {
|
||||
pageAlias: string;
|
||||
frame: Frame;
|
||||
action: Action;
|
||||
committed?: boolean;
|
||||
}
|
||||
|
||||
export interface CodeGeneratorOutput {
|
||||
write(text: string): void
|
||||
popLine(): void
|
||||
flush(): void
|
||||
}
|
||||
|
||||
export class CodeGenerator {
|
||||
private _currentAction: ActionInContext | undefined;
|
||||
private _lastAction: ActionInContext | undefined;
|
||||
private _lastActionText: string | undefined;
|
||||
private _languageGenerator: LanguageGenerator;
|
||||
private _output: CodeGeneratorOutput;
|
||||
|
||||
constructor(browserName: string, launchOptions: playwright.LaunchOptions, contextOptions: playwright.BrowserContextOptions, output: CodeGeneratorOutput, languageGenerator: LanguageGenerator, deviceName: string | undefined) {
|
||||
this._output = output
|
||||
this._languageGenerator = languageGenerator
|
||||
|
||||
launchOptions = { headless: false, ...launchOptions };
|
||||
this._languageGenerator.writeHeader(browserName, launchOptions, contextOptions, deviceName)
|
||||
}
|
||||
|
||||
exit() {
|
||||
this._languageGenerator.writeFooter()
|
||||
this._output.flush();
|
||||
}
|
||||
|
||||
addAction(action: ActionInContext) {
|
||||
this.willPerformAction(action);
|
||||
this.didPerformAction(action);
|
||||
}
|
||||
|
||||
willPerformAction(action: ActionInContext) {
|
||||
this._currentAction = action;
|
||||
}
|
||||
|
||||
didPerformAction(actionInContext: ActionInContext) {
|
||||
const { action, pageAlias } = actionInContext;
|
||||
let eraseLastAction = false;
|
||||
if (this._lastAction && this._lastAction.pageAlias === pageAlias) {
|
||||
const { action: lastAction } = this._lastAction;
|
||||
// We augment last action based on the type.
|
||||
if (this._lastAction && action.name === 'fill' && lastAction.name === 'fill') {
|
||||
if (action.selector === lastAction.selector)
|
||||
eraseLastAction = true;
|
||||
}
|
||||
if (lastAction && action.name === 'click' && lastAction.name === 'click') {
|
||||
if (action.selector === lastAction.selector && action.clickCount > lastAction.clickCount)
|
||||
eraseLastAction = true;
|
||||
}
|
||||
if (lastAction && action.name === 'navigate' && lastAction.name === 'navigate') {
|
||||
if (action.url === lastAction.url)
|
||||
return;
|
||||
}
|
||||
for (const name of ['check', 'uncheck']) {
|
||||
if (lastAction && action.name === name && lastAction.name === 'click') {
|
||||
if ((action as any).selector === (lastAction as any).selector)
|
||||
eraseLastAction = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
this._printAction(actionInContext, eraseLastAction);
|
||||
}
|
||||
|
||||
commitLastAction() {
|
||||
const action = this._lastAction;
|
||||
if (action)
|
||||
action.committed = true;
|
||||
}
|
||||
|
||||
_printAction(actionInContext: ActionInContext, eraseLastAction: boolean) {
|
||||
this._languageGenerator.preWriteAction(eraseLastAction, this._lastActionText)
|
||||
const performingAction = !!this._currentAction;
|
||||
this._currentAction = undefined;
|
||||
this._lastAction = actionInContext;
|
||||
this._lastActionText = this._languageGenerator.generateAction(actionInContext, performingAction)
|
||||
this._languageGenerator.postWriteAction(this._lastActionText)
|
||||
}
|
||||
|
||||
signal(pageAlias: string, frame: playwright.Frame, signal: Signal) {
|
||||
// Signal either arrives while action is being performed or shortly after.
|
||||
if (this._currentAction) {
|
||||
this._currentAction.action.signals.push(signal);
|
||||
return;
|
||||
}
|
||||
if (this._lastAction && !this._lastAction.committed) {
|
||||
this._lastAction.action.signals.push(signal);
|
||||
this._printAction(this._lastAction, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (signal.name === 'navigation') {
|
||||
this.addAction({
|
||||
pageAlias,
|
||||
frame,
|
||||
committed: true,
|
||||
action: {
|
||||
name: 'navigate',
|
||||
url: frame.url(),
|
||||
signals: [],
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
import * as playwright from 'playwright';
|
||||
import { ActionInContext } from '../codeGenerator';
|
||||
|
||||
export interface LanguageGenerator {
|
||||
writeHeader(browserName: string, launchOptions: playwright.LaunchOptions, contextOptions: playwright.BrowserContextOptions, deviceName?: string): void
|
||||
generateAction(actionInContext: ActionInContext, performingAction: boolean): string
|
||||
preWriteAction(eraseLastAction: boolean, lastActionText?: string): void
|
||||
postWriteAction(lastActionText: string): void
|
||||
writeFooter(): void
|
||||
}
|
||||
|
||||
export { JavaScriptLanguageGenerator } from './javascript'
|
||||
@@ -15,139 +15,34 @@
|
||||
*/
|
||||
|
||||
import * as playwright from 'playwright';
|
||||
import { Frame } from 'playwright';
|
||||
import { quote, Formatter } from './formatter';
|
||||
import { Action, actionTitle, NavigationSignal, PopupSignal, Signal, DownloadSignal, DialogSignal } from './recorderActions';
|
||||
import { MouseClickOptions, toModifiers } from './utils';
|
||||
import { LanguageGenerator } from '.';
|
||||
import { ActionInContext, CodeGeneratorOutput } from '../codeGenerator';
|
||||
import { actionTitle, NavigationSignal, PopupSignal, DownloadSignal, DialogSignal, Action } from '../recorderActions'
|
||||
import { MouseClickOptions, toModifiers } from '../../utils';
|
||||
|
||||
export type ActionInContext = {
|
||||
pageAlias: string;
|
||||
frame: Frame;
|
||||
action: Action;
|
||||
committed?: boolean;
|
||||
}
|
||||
|
||||
export interface CodeGeneratorOutput {
|
||||
write(text: string): void
|
||||
popLine(): void
|
||||
flush(): void
|
||||
}
|
||||
|
||||
export class CodeGenerator {
|
||||
private _currentAction: ActionInContext | undefined;
|
||||
private _lastAction: ActionInContext | undefined;
|
||||
private _lastActionText: string | undefined;
|
||||
private _output: CodeGeneratorOutput;
|
||||
|
||||
constructor(browserName: string, launchOptions: playwright.LaunchOptions, contextOptions: playwright.BrowserContextOptions, output: CodeGeneratorOutput, deviceName: string | undefined) {
|
||||
this._output = output
|
||||
const formatter = new Formatter();
|
||||
launchOptions = { headless: false, ...launchOptions };
|
||||
|
||||
formatter.add(`
|
||||
const { ${browserName}${deviceName ? ', devices' : ''} } = require('playwright');
|
||||
|
||||
(async () => {
|
||||
const browser = await ${browserName}.launch(${formatObjectOrVoid(launchOptions)});
|
||||
const context = await browser.newContext(${formatContextOptions(contextOptions, deviceName)});
|
||||
})();`);
|
||||
this._output.write(formatter.format() + '\n');
|
||||
export class JavaScriptLanguageGenerator implements LanguageGenerator {
|
||||
private _output: CodeGeneratorOutput
|
||||
constructor(output: CodeGeneratorOutput) {
|
||||
this._output = output;
|
||||
}
|
||||
|
||||
exit() {
|
||||
this._output.popLine();
|
||||
this._output.write(' // Close browser\n');
|
||||
this._output.write(' await browser.close();\n})();\n');
|
||||
this._output.flush();
|
||||
}
|
||||
|
||||
addAction(action: ActionInContext) {
|
||||
this.willPerformAction(action);
|
||||
this.didPerformAction(action);
|
||||
}
|
||||
|
||||
willPerformAction(action: ActionInContext) {
|
||||
this._currentAction = action;
|
||||
}
|
||||
|
||||
didPerformAction(actionInContext: ActionInContext) {
|
||||
const { action, pageAlias } = actionInContext;
|
||||
let eraseLastAction = false;
|
||||
if (this._lastAction && this._lastAction.pageAlias === pageAlias) {
|
||||
const { action: lastAction } = this._lastAction;
|
||||
// We augment last action based on the type.
|
||||
if (this._lastAction && action.name === 'fill' && lastAction.name === 'fill') {
|
||||
if (action.selector === lastAction.selector)
|
||||
eraseLastAction = true;
|
||||
}
|
||||
if (lastAction && action.name === 'click' && lastAction.name === 'click') {
|
||||
if (action.selector === lastAction.selector && action.clickCount > lastAction.clickCount)
|
||||
eraseLastAction = true;
|
||||
}
|
||||
if (lastAction && action.name === 'navigate' && lastAction.name === 'navigate') {
|
||||
if (action.url === lastAction.url)
|
||||
return;
|
||||
}
|
||||
for (const name of ['check', 'uncheck']) {
|
||||
if (lastAction && action.name === name && lastAction.name === 'click') {
|
||||
if ((action as any).selector === (lastAction as any).selector)
|
||||
eraseLastAction = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
this._printAction(actionInContext, eraseLastAction);
|
||||
}
|
||||
|
||||
commitLastAction() {
|
||||
const action = this._lastAction;
|
||||
if (action)
|
||||
action.committed = true;
|
||||
}
|
||||
|
||||
_printAction(actionInContext: ActionInContext, eraseLastAction: boolean) {
|
||||
preWriteAction(eraseLastAction: boolean, lastActionText?: string): void {
|
||||
// We erase terminating `})();` at all times.
|
||||
let eraseLines = 1;
|
||||
if (eraseLastAction && this._lastActionText)
|
||||
eraseLines += this._lastActionText.split('\n').length;
|
||||
if (eraseLastAction && lastActionText)
|
||||
eraseLines += lastActionText.split('\n').length;
|
||||
// And we erase the last action too if augmenting.
|
||||
for (let i = 0; i < eraseLines; ++i)
|
||||
this._output.popLine()
|
||||
const performingAction = !!this._currentAction;
|
||||
this._currentAction = undefined;
|
||||
this._lastAction = actionInContext;
|
||||
this._lastActionText = this._generateAction(actionInContext, performingAction);
|
||||
this._output.write(this._lastActionText + '\n})();\n');
|
||||
}
|
||||
|
||||
signal(pageAlias: string, frame: playwright.Frame, signal: Signal) {
|
||||
// Signal either arrives while action is being performed or shortly after.
|
||||
if (this._currentAction) {
|
||||
this._currentAction.action.signals.push(signal);
|
||||
return;
|
||||
}
|
||||
if (this._lastAction && !this._lastAction.committed) {
|
||||
this._lastAction.action.signals.push(signal);
|
||||
this._printAction(this._lastAction, true);
|
||||
return;
|
||||
}
|
||||
|
||||
if (signal.name === 'navigation') {
|
||||
this.addAction({
|
||||
pageAlias,
|
||||
frame,
|
||||
committed: true,
|
||||
action: {
|
||||
name: 'navigate',
|
||||
url: frame.url(),
|
||||
signals: [],
|
||||
}
|
||||
});
|
||||
}
|
||||
postWriteAction(lastActionText: string): void {
|
||||
this._output.write(lastActionText + '\n})();\n');
|
||||
}
|
||||
|
||||
private _generateAction(actionInContext: ActionInContext, performingAction: boolean): string {
|
||||
generateAction(actionInContext: ActionInContext, performingAction: boolean): string {
|
||||
const { action, pageAlias, frame } = actionInContext;
|
||||
const formatter = new Formatter(2);
|
||||
const formatter = new JavaScriptFormatter(2);
|
||||
formatter.newLine();
|
||||
formatter.add('// ' + actionTitle(action));
|
||||
|
||||
@@ -223,7 +118,7 @@ export class CodeGenerator {
|
||||
}
|
||||
|
||||
private _generateActionCall(action: Action): string {
|
||||
switch (action.name) {
|
||||
switch (action.name) {
|
||||
case 'openPage':
|
||||
throw Error('Not reached');
|
||||
case 'closePage':
|
||||
@@ -262,6 +157,24 @@ export class CodeGenerator {
|
||||
return `selectOption(${quote(action.selector)}, ${formatObject(action.options.length > 1 ? action.options : action.options[0])})`;
|
||||
}
|
||||
}
|
||||
|
||||
writeHeader(browserName: string, launchOptions: playwright.LaunchOptions, contextOptions: playwright.BrowserContextOptions, deviceName?: string): void {
|
||||
const formatter = new JavaScriptFormatter();
|
||||
formatter.add(`
|
||||
const { ${browserName}${deviceName ? ', devices' : ''} } = require('playwright');
|
||||
|
||||
(async () => {
|
||||
const browser = await ${browserName}.launch(${formatObjectOrVoid(launchOptions)});
|
||||
const context = await browser.newContext(${formatContextOptions(contextOptions, deviceName)});
|
||||
})();`);
|
||||
this._output.write(formatter.format() + '\n');
|
||||
}
|
||||
|
||||
writeFooter(): void {
|
||||
this._output.popLine();
|
||||
this._output.write(' // Close browser\n');
|
||||
this._output.write(' await browser.close();\n})();\n');
|
||||
}
|
||||
}
|
||||
|
||||
function formatOptions(value: any): string {
|
||||
@@ -299,7 +212,7 @@ function formatContextOptions(options: playwright.BrowserContextOptions, deviceN
|
||||
return formatObjectOrVoid(options);
|
||||
// Filter out all the properties from the device descriptor.
|
||||
const cleanedOptions: Record<string, any> = {}
|
||||
for(const property in options)
|
||||
for (const property in options)
|
||||
if ((device as any)[property] !== (options as any)[property])
|
||||
cleanedOptions[property] = (options as any)[property]
|
||||
let serializedObject = formatObjectOrVoid(cleanedOptions);
|
||||
@@ -309,4 +222,56 @@ function formatContextOptions(options: playwright.BrowserContextOptions, deviceN
|
||||
const lines = serializedObject.split('\n');
|
||||
lines.splice(1, 0, `...devices['${deviceName}'],`);
|
||||
return lines.join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
class JavaScriptFormatter {
|
||||
private _baseIndent: string;
|
||||
private _baseOffset: string;
|
||||
private _lines: string[] = [];
|
||||
|
||||
constructor(offset = 0) {
|
||||
this._baseIndent = ' '.repeat(2);
|
||||
this._baseOffset = ' '.repeat(offset);
|
||||
}
|
||||
|
||||
prepend(text: string) {
|
||||
this._lines = text.trim().split('\n').map(line => line.trim()).concat(this._lines);
|
||||
}
|
||||
|
||||
add(text: string) {
|
||||
this._lines.push(...text.trim().split('\n').map(line => line.trim()));
|
||||
}
|
||||
|
||||
newLine() {
|
||||
this._lines.push('');
|
||||
}
|
||||
|
||||
format(): string {
|
||||
let spaces = '';
|
||||
let previousLine = '';
|
||||
return this._lines.map((line: string) => {
|
||||
if (line === '')
|
||||
return line;
|
||||
if (line.startsWith('}') || line.startsWith(']'))
|
||||
spaces = spaces.substring(this._baseIndent.length);
|
||||
|
||||
const extraSpaces = /^(for|while|if).*\(.*\)$/.test(previousLine) ? this._baseIndent : '';
|
||||
previousLine = line;
|
||||
|
||||
line = spaces + extraSpaces + line;
|
||||
if (line.endsWith('{') || line.endsWith('['))
|
||||
spaces += this._baseIndent;
|
||||
return this._baseOffset + line;
|
||||
}).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');
|
||||
}
|
||||
@@ -17,7 +17,8 @@
|
||||
import * as playwright from 'playwright';
|
||||
import * as actions from './recorderActions';
|
||||
import { CodeGenerator, ActionInContext, CodeGeneratorOutput } from './codeGenerator';
|
||||
import { BindingSource, toClickOptions, toModifiers } from './utils';
|
||||
import { BindingSource, toClickOptions, toModifiers } from '../utils';
|
||||
import { LanguageGenerator } from './languages';
|
||||
|
||||
export class RecorderController {
|
||||
private _generator: CodeGenerator;
|
||||
@@ -25,8 +26,8 @@ export class RecorderController {
|
||||
private _lastPopupOrdinal = 0;
|
||||
private _timers = new Set<NodeJS.Timeout>();
|
||||
|
||||
constructor(browserName: string, launchOptions: playwright.LaunchOptions, contextOptions: playwright.BrowserContextOptions, context: playwright.BrowserContext, output: CodeGeneratorOutput, deviceName: string | undefined) {
|
||||
this._generator = new CodeGenerator(browserName, launchOptions, contextOptions, output, deviceName);
|
||||
constructor(browserName: string, launchOptions: playwright.LaunchOptions, contextOptions: playwright.BrowserContextOptions, context: playwright.BrowserContext, output: CodeGeneratorOutput, languageGenerator: LanguageGenerator, deviceName: string | undefined) {
|
||||
this._generator = new CodeGenerator(browserName, launchOptions, contextOptions, output, languageGenerator, deviceName);
|
||||
|
||||
// Input actions that potentially lead to navigation are intercepted on the page and are
|
||||
// performed by the Playwright.
|
||||
@@ -1,67 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
export class Formatter {
|
||||
private _baseIndent: string;
|
||||
private _baseOffset: string;
|
||||
private _lines: string[] = [];
|
||||
|
||||
constructor(offset = 0) {
|
||||
this._baseIndent = ' '.repeat(2);
|
||||
this._baseOffset = ' '.repeat(offset);
|
||||
}
|
||||
|
||||
prepend(text: string) {
|
||||
this._lines = text.trim().split('\n').map(line => line.trim()).concat(this._lines);
|
||||
}
|
||||
|
||||
add(text: string) {
|
||||
this._lines.push(...text.trim().split('\n').map(line => line.trim()));
|
||||
}
|
||||
|
||||
newLine() {
|
||||
this._lines.push('');
|
||||
}
|
||||
|
||||
format(): string {
|
||||
let spaces = '';
|
||||
let previousLine = '';
|
||||
return this._lines.map((line: string) => {
|
||||
if (line === '')
|
||||
return line;
|
||||
if (line.startsWith('}') || line.startsWith(']'))
|
||||
spaces = spaces.substring(this._baseIndent.length);
|
||||
|
||||
const extraSpaces = /^(for|while|if).*\(.*\)$/.test(previousLine) ? this._baseIndent : '';
|
||||
previousLine = line;
|
||||
|
||||
line = spaces + extraSpaces + line;
|
||||
if (line.endsWith('{') || line.endsWith('['))
|
||||
spaces += this._baseIndent;
|
||||
return this._baseOffset + line;
|
||||
}).join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
export 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');
|
||||
}
|
||||
@@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import type * as actions from '../recorderActions';
|
||||
import type * as actions from '../codegen/recorderActions';
|
||||
import { ConsoleAPI, InjectedScript } from './consoleApi';
|
||||
import { html } from './html';
|
||||
import { addEventListener, RegisteredListener, removeEventListeners } from './util';
|
||||
|
||||
@@ -19,13 +19,12 @@ import { Recorder } from './recorder';
|
||||
|
||||
export default class Script {
|
||||
private _consoleAPI: ConsoleAPI | undefined;
|
||||
private _recorder: Recorder | undefined;
|
||||
|
||||
constructor(injectedScript: InjectedScript, options: { enableRecorder: boolean }) {
|
||||
if ((window as any).playwright)
|
||||
return;
|
||||
this._consoleAPI = new ConsoleAPI(injectedScript);
|
||||
if (options.enableRecorder)
|
||||
this._recorder = new Recorder(injectedScript, this._consoleAPI);
|
||||
new Recorder(injectedScript, this._consoleAPI);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { ConsoleAPI, InjectedScript } from './consoleApi';
|
||||
import { InjectedScript } from './consoleApi';
|
||||
/**
|
||||
* Copyright (c) Microsoft Corporation.
|
||||
*
|
||||
|
||||
@@ -16,15 +16,16 @@
|
||||
|
||||
import * as playwright from 'playwright';
|
||||
import * as injectedScriptSource from './generated/scriptSource';
|
||||
import { RecorderController } from './recorderController';
|
||||
import { CodeGeneratorOutput } from './codeGenerator';
|
||||
import { RecorderController } from './codegen/recorderController';
|
||||
import { CodeGeneratorOutput } from './codegen/codeGenerator';
|
||||
import { LanguageGenerator } from './codegen/languages';
|
||||
|
||||
export class ScriptController {
|
||||
private _recorder: RecorderController | undefined;
|
||||
|
||||
constructor(browserName: string, launchOptions: playwright.LaunchOptions, contextOptions: playwright.BrowserContextOptions, context: playwright.BrowserContext, output: CodeGeneratorOutput, enableRecorder: boolean, deviceName?: string) {
|
||||
constructor(browserName: string, launchOptions: playwright.LaunchOptions, contextOptions: playwright.BrowserContextOptions, context: playwright.BrowserContext, output: CodeGeneratorOutput, languageGenerator: LanguageGenerator, enableRecorder: boolean, deviceName?: string) {
|
||||
if (enableRecorder)
|
||||
this._recorder = new RecorderController(browserName, launchOptions, contextOptions, context, output, deviceName);
|
||||
this._recorder = new RecorderController(browserName, launchOptions, contextOptions, context, output, languageGenerator, deviceName);
|
||||
context.on('page', page => this._onPage(page));
|
||||
for (const page of context.pages())
|
||||
this._onPage(page);
|
||||
|
||||
+1
-1
@@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import * as playwright from 'playwright';
|
||||
import * as actions from './recorderActions';
|
||||
import * as actions from './codegen/recorderActions';
|
||||
|
||||
let __dummy: { page: playwright.Page };
|
||||
export type MouseClickOptions = Parameters<typeof __dummy.page.click>[1];
|
||||
|
||||
@@ -23,7 +23,8 @@ import * as playwright from 'playwright';
|
||||
import { fixtures as baseFixtures } from '@playwright/test-runner';
|
||||
import { ScriptController } from '../src/scriptController';
|
||||
import { Page } from 'playwright';
|
||||
import { TerminalOutput } from '../src/outputs';
|
||||
import { TerminalOutput } from '../src/codegen/outputs';
|
||||
import { JavaScriptLanguageGenerator } from '../src/codegen/languages';
|
||||
|
||||
type Parameters = {
|
||||
browserName: string;
|
||||
@@ -102,9 +103,11 @@ fixtures.defineWorkerFixture('httpServer', async ({parallelIndex}, runTest) => {
|
||||
|
||||
fixtures.defineTestFixture('contextWrapper', async ({ browser }, runTest, info) => {
|
||||
const context = await browser.newContext();
|
||||
const output = new WritableBuffer();
|
||||
new ScriptController('chromium', {}, {}, context, new TerminalOutput(output as any as Writable), true);
|
||||
await runTest({ context, output });
|
||||
const outputBuffer = new WritableBuffer();
|
||||
const output = new TerminalOutput(outputBuffer as any as Writable)
|
||||
const languageGenerator = new JavaScriptLanguageGenerator(output)
|
||||
new ScriptController('chromium', {}, {}, context, output, languageGenerator, true);
|
||||
await runTest({ context, output: outputBuffer });
|
||||
await context.close();
|
||||
});
|
||||
|
||||
|
||||
+2
-1
@@ -7,7 +7,8 @@
|
||||
"rootDir": "./src",
|
||||
"outDir": "./lib",
|
||||
"strict": true,
|
||||
"declaration": false
|
||||
"declaration": false,
|
||||
"noUnusedLocals": true
|
||||
},
|
||||
"compileOnSave": true,
|
||||
"include": ["src/**/*.ts"],
|
||||
|
||||
Reference in New Issue
Block a user