cherry-pick(#12020): chore: headless mode for codegen
This commit is contained in:
parent
55be85284c
commit
73d78f5988
|
|
@ -38,7 +38,18 @@ declare global {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export class RecorderApp extends EventEmitter {
|
export interface IRecorderApp extends EventEmitter {
|
||||||
|
close(): Promise<void>;
|
||||||
|
setPaused(paused: boolean): Promise<void>;
|
||||||
|
setMode(mode: 'none' | 'recording' | 'inspecting'): Promise<void>;
|
||||||
|
setFile(file: string): Promise<void>;
|
||||||
|
setSelector(selector: string, focus?: boolean): Promise<void>;
|
||||||
|
updateCallLogs(callLogs: CallLog[]): Promise<void>;
|
||||||
|
bringToFront(): void;
|
||||||
|
setSources(sources: Source[]): Promise<void>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class RecorderApp extends EventEmitter implements IRecorderApp {
|
||||||
private _page: Page;
|
private _page: Page;
|
||||||
readonly wsEndpoint: string | undefined;
|
readonly wsEndpoint: string | undefined;
|
||||||
|
|
||||||
|
|
@ -85,7 +96,9 @@ export class RecorderApp extends EventEmitter {
|
||||||
await mainFrame.goto(internalCallMetadata(), 'https://playwright/index.html');
|
await mainFrame.goto(internalCallMetadata(), 'https://playwright/index.html');
|
||||||
}
|
}
|
||||||
|
|
||||||
static async open(sdkLanguage: string, headed: boolean): Promise<RecorderApp> {
|
static async open(sdkLanguage: string, headed: boolean): Promise<IRecorderApp> {
|
||||||
|
if (process.env.PW_CODEGEN_NO_INSPECTOR)
|
||||||
|
return new HeadlessRecorderApp();
|
||||||
const recorderPlaywright = (require('../../playwright').createPlaywright as typeof import('../../playwright').createPlaywright)('javascript', true);
|
const recorderPlaywright = (require('../../playwright').createPlaywright as typeof import('../../playwright').createPlaywright)('javascript', true);
|
||||||
const args = [
|
const args = [
|
||||||
'--app=data:text/html,',
|
'--app=data:text/html,',
|
||||||
|
|
@ -163,3 +176,14 @@ export class RecorderApp extends EventEmitter {
|
||||||
await this._page.bringToFront();
|
await this._page.bringToFront();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class HeadlessRecorderApp extends EventEmitter implements IRecorderApp {
|
||||||
|
async close(): Promise<void> {}
|
||||||
|
async setPaused(paused: boolean): Promise<void> {}
|
||||||
|
async setMode(mode: 'none' | 'recording' | 'inspecting'): Promise<void> {}
|
||||||
|
async setFile(file: string): Promise<void> {}
|
||||||
|
async setSelector(selector: string, focus?: boolean): Promise<void> {}
|
||||||
|
async updateCallLogs(callLogs: CallLog[]): Promise<void> {}
|
||||||
|
bringToFront(): void {}
|
||||||
|
async setSources(sources: Source[]): Promise<void> {}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,7 +28,7 @@ import { CSharpLanguageGenerator } from './recorder/csharp';
|
||||||
import { PythonLanguageGenerator } from './recorder/python';
|
import { PythonLanguageGenerator } from './recorder/python';
|
||||||
import * as recorderSource from '../../generated/recorderSource';
|
import * as recorderSource from '../../generated/recorderSource';
|
||||||
import * as consoleApiSource from '../../generated/consoleApiSource';
|
import * as consoleApiSource from '../../generated/consoleApiSource';
|
||||||
import { RecorderApp } from './recorder/recorderApp';
|
import { IRecorderApp, RecorderApp } from './recorder/recorderApp';
|
||||||
import { CallMetadata, InstrumentationListener, SdkObject } from '../instrumentation';
|
import { CallMetadata, InstrumentationListener, SdkObject } from '../instrumentation';
|
||||||
import { Point } from '../../common/types';
|
import { Point } from '../../common/types';
|
||||||
import { CallLog, CallLogStatus, EventData, Mode, Source, UIState } from './recorder/recorderTypes';
|
import { CallLog, CallLogStatus, EventData, Mode, Source, UIState } from './recorder/recorderTypes';
|
||||||
|
|
@ -46,7 +46,7 @@ export class RecorderSupplement implements InstrumentationListener {
|
||||||
private _context: BrowserContext;
|
private _context: BrowserContext;
|
||||||
private _mode: Mode;
|
private _mode: Mode;
|
||||||
private _highlightedSelector = '';
|
private _highlightedSelector = '';
|
||||||
private _recorderApp: RecorderApp | null = null;
|
private _recorderApp: IRecorderApp | null = null;
|
||||||
private _currentCallsMetadata = new Map<CallMetadata, SdkObject>();
|
private _currentCallsMetadata = new Map<CallMetadata, SdkObject>();
|
||||||
private _recorderSources: Source[] = [];
|
private _recorderSources: Source[] = [];
|
||||||
private _userSources = new Map<string, Source>();
|
private _userSources = new Map<string, Source>();
|
||||||
|
|
@ -317,7 +317,7 @@ class ContextRecorder extends EventEmitter {
|
||||||
|
|
||||||
this._recorderSources = [];
|
this._recorderSources = [];
|
||||||
const generator = new CodeGenerator(context._browser.options.name, !!params.startRecording, params.launchOptions || {}, params.contextOptions || {}, params.device, params.saveStorage);
|
const generator = new CodeGenerator(context._browser.options.name, !!params.startRecording, params.launchOptions || {}, params.contextOptions || {}, params.device, params.saveStorage);
|
||||||
let text = '';
|
const throttledOutputFile = params.outputFile ? new ThrottledFile(params.outputFile) : null;
|
||||||
generator.on('change', () => {
|
generator.on('change', () => {
|
||||||
this._recorderSources = [];
|
this._recorderSources = [];
|
||||||
for (const languageGenerator of orderedLanguages) {
|
for (const languageGenerator of orderedLanguages) {
|
||||||
|
|
@ -330,21 +330,19 @@ class ContextRecorder extends EventEmitter {
|
||||||
source.revealLine = source.text.split('\n').length - 1;
|
source.revealLine = source.text.split('\n').length - 1;
|
||||||
this._recorderSources.push(source);
|
this._recorderSources.push(source);
|
||||||
if (languageGenerator === orderedLanguages[0])
|
if (languageGenerator === orderedLanguages[0])
|
||||||
text = source.text;
|
throttledOutputFile?.setContent(source.text);
|
||||||
}
|
}
|
||||||
this.emit(ContextRecorder.Events.Change, {
|
this.emit(ContextRecorder.Events.Change, {
|
||||||
sources: this._recorderSources,
|
sources: this._recorderSources,
|
||||||
primaryFileName: primaryLanguage.fileName
|
primaryFileName: primaryLanguage.fileName
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
if (params.outputFile) {
|
if (throttledOutputFile) {
|
||||||
context.on(BrowserContext.Events.BeforeClose, () => {
|
context.on(BrowserContext.Events.BeforeClose, () => {
|
||||||
fs.writeFileSync(params.outputFile!, text);
|
throttledOutputFile.flush();
|
||||||
text = '';
|
|
||||||
});
|
});
|
||||||
process.on('exit', () => {
|
process.on('exit', () => {
|
||||||
if (text)
|
throttledOutputFile.flush();
|
||||||
fs.writeFileSync(params.outputFile!, text);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
this._generator = generator;
|
this._generator = generator;
|
||||||
|
|
@ -590,3 +588,29 @@ function languageForFile(file: string) {
|
||||||
return 'csharp';
|
return 'csharp';
|
||||||
return 'javascript';
|
return 'javascript';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ThrottledFile {
|
||||||
|
private _file: string;
|
||||||
|
private _timer: NodeJS.Timeout | undefined;
|
||||||
|
private _text: string | undefined;
|
||||||
|
|
||||||
|
constructor(file: string) {
|
||||||
|
this._file = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
setContent(text: string) {
|
||||||
|
this._text = text;
|
||||||
|
if (!this._timer)
|
||||||
|
this._timer = setTimeout(() => this.flush(), 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
flush(): void {
|
||||||
|
if (this._timer) {
|
||||||
|
clearTimeout(this._timer);
|
||||||
|
this._timer = undefined;
|
||||||
|
}
|
||||||
|
if (this._text)
|
||||||
|
fs.writeFileSync(this._file, this._text);
|
||||||
|
this._text = undefined;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue