mirror of
https://github.com/microsoft/playwright.git
synced 2025-06-26 21:40:17 +00:00
chore: switch to the new debug controller harness (#18308)
This commit is contained in:
parent
d819f97f40
commit
37250cde17
@ -57,7 +57,7 @@ program
|
||||
|
||||
commandWithOpenOptions('open [url]', 'open page in browser specified via -b, --browser', [])
|
||||
.action(function(url, options) {
|
||||
open(options, url, language()).catch(logErrorAndExit);
|
||||
open(options, url, codegenId()).catch(logErrorAndExit);
|
||||
})
|
||||
.addHelpText('afterAll', `
|
||||
Examples:
|
||||
@ -68,7 +68,7 @@ Examples:
|
||||
commandWithOpenOptions('codegen [url]', 'open page and generate code for user actions',
|
||||
[
|
||||
['-o, --output <file name>', 'saves the generated script to a file'],
|
||||
['--target <language>', `language to generate, one of javascript, test, python, python-async, pytest, csharp, csharp-mstest, csharp-nunit, java`, language()],
|
||||
['--target <language>', `language to generate, one of javascript, playwright-test, python, python-async, python-pytest, csharp, csharp-mstest, csharp-nunit, java`, codegenId()],
|
||||
['--save-trace <filename>', 'record a trace for the session and save it to a file'],
|
||||
]).action(function(url, options) {
|
||||
codegen(options, url, options.target, options.output).catch(logErrorAndExit);
|
||||
@ -267,13 +267,12 @@ program
|
||||
|
||||
program
|
||||
.command('run-server', { hidden: true })
|
||||
.option('--reuse-browser', 'Whether to reuse the browser instance')
|
||||
.option('--port <port>', 'Server port')
|
||||
.option('--path <path>', 'Endpoint Path', '/')
|
||||
.option('--max-clients <maxClients>', 'Maximum clients')
|
||||
.option('--no-socks-proxy', 'Disable Socks Proxy')
|
||||
.action(function(options) {
|
||||
runServer(options.port ? +options.port : undefined, options.path, options.maxClients ? +options.maxClients : Infinity, options.socksProxy, options.reuseBrowser).catch(logErrorAndExit);
|
||||
runServer(options.port ? +options.port : undefined, options.path, options.maxClients ? +options.maxClients : Infinity, options.socksProxy).catch(logErrorAndExit);
|
||||
});
|
||||
|
||||
program
|
||||
@ -682,8 +681,8 @@ function logErrorAndExit(e: Error) {
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
function language(): string {
|
||||
return process.env.PW_LANG_NAME || 'test';
|
||||
function codegenId(): string {
|
||||
return process.env.PW_LANG_NAME || 'playwright-test';
|
||||
}
|
||||
|
||||
function commandWithOpenOptions(command: string, description: string, options: any[][]): Command {
|
||||
|
@ -21,12 +21,9 @@ import * as playwright from '../..';
|
||||
import type { BrowserType } from '../client/browserType';
|
||||
import type { LaunchServerOptions } from '../client/types';
|
||||
import { createPlaywright, DispatcherConnection, RootDispatcher, PlaywrightDispatcher } from '../server';
|
||||
import type { Playwright } from '../server/playwright';
|
||||
import { IpcTransport, PipeTransport } from '../protocol/transport';
|
||||
import { PlaywrightServer } from '../remote/playwrightServer';
|
||||
import { gracefullyCloseAll } from '../utils/processLauncher';
|
||||
import type { Mode } from '@recorder/recorderTypes';
|
||||
import { DebugController } from '../server/debugController';
|
||||
|
||||
export function printApiJson() {
|
||||
// Note: this file is generated by build-playwright-driver.sh
|
||||
@ -49,14 +46,12 @@ export function runDriver() {
|
||||
};
|
||||
}
|
||||
|
||||
export async function runServer(port: number | undefined, path = '/', maxConnections = Infinity, enableSocksProxy = true, reuseBrowser = false) {
|
||||
export async function runServer(port: number | undefined, path = '/', maxConnections = Infinity, enableSocksProxy = true) {
|
||||
const server = new PlaywrightServer({ path, maxConnections, enableSocksProxy });
|
||||
const wsEndpoint = await server.listen(port);
|
||||
process.on('exit', () => server.close().catch(console.error));
|
||||
console.log('Listening on ' + wsEndpoint); // eslint-disable-line no-console
|
||||
process.stdin.on('close', () => selfDestruct());
|
||||
if (reuseBrowser && process.send)
|
||||
wireController(server.preLaunchedPlaywright(), wsEndpoint);
|
||||
}
|
||||
|
||||
export async function launchBrowserServer(browserName: string, configFile?: string) {
|
||||
@ -76,67 +71,3 @@ function selfDestruct() {
|
||||
process.exit(0);
|
||||
});
|
||||
}
|
||||
|
||||
class ProtocolHandler {
|
||||
private _controller: DebugController;
|
||||
|
||||
constructor(playwright: Playwright) {
|
||||
this._controller = playwright.debugController;
|
||||
this._controller.setAutoCloseAllowed(true);
|
||||
this._controller.setReportStateChanged(true);
|
||||
this._controller.on(DebugController.Events.BrowsersChanged, browsers => {
|
||||
process.send!({ method: 'browsersChanged', params: { browsers } });
|
||||
});
|
||||
this._controller.on(DebugController.Events.InspectRequested, ({ selector, locators }) => {
|
||||
process.send!({ method: 'inspectRequested', params: { selector, locators } });
|
||||
});
|
||||
this._controller.on(DebugController.Events.SourcesChanged, sources => {
|
||||
process.send!({ method: 'sourcesChanged', params: { sources } });
|
||||
});
|
||||
}
|
||||
|
||||
async resetForReuse() {
|
||||
await this._controller.resetForReuse();
|
||||
}
|
||||
|
||||
async navigate(params: { url: string }) {
|
||||
await this._controller.navigate(params.url);
|
||||
}
|
||||
|
||||
async setMode(params: { mode: Mode, language?: string, file?: string }) {
|
||||
await this._controller.setRecorderMode(params);
|
||||
}
|
||||
|
||||
async setAutoClose(params: { enabled: boolean }) {
|
||||
await this._controller.setAutoCloseEnabled(params.enabled);
|
||||
}
|
||||
|
||||
async highlight(params: { selector: string }) {
|
||||
await this._controller.highlight(params.selector);
|
||||
}
|
||||
|
||||
async hideHighlight() {
|
||||
await this._controller.hideHighlight();
|
||||
}
|
||||
|
||||
async closeAllBrowsers() {
|
||||
await this._controller.closeAllBrowsers();
|
||||
}
|
||||
|
||||
async kill() {
|
||||
await this._controller.kill();
|
||||
}
|
||||
}
|
||||
|
||||
function wireController(playwright: Playwright, wsEndpoint: string) {
|
||||
process.send!({ method: 'ready', params: { wsEndpoint } });
|
||||
const handler = new ProtocolHandler(playwright);
|
||||
process.on('message', async message => {
|
||||
try {
|
||||
const result = await (handler as any)[message.method](message.params);
|
||||
process.send!({ id: message.id, result });
|
||||
} catch (e) {
|
||||
process.send!({ id: message.id, error: e.toString() });
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -58,21 +58,21 @@ function determineUserAgent(): string {
|
||||
additionalTokens.push('CI/1');
|
||||
const serializedTokens = additionalTokens.length ? ' ' + additionalTokens.join(' ') : '';
|
||||
|
||||
const { langName, langVersion } = getClientLanguage();
|
||||
return `Playwright/${getPlaywrightVersion()} (${os.arch()}; ${osIdentifier} ${osVersion}) ${langName}/${langVersion}${serializedTokens}`;
|
||||
const { embedderName, embedderVersion } = getEmbedderName();
|
||||
return `Playwright/${getPlaywrightVersion()} (${os.arch()}; ${osIdentifier} ${osVersion}) ${embedderName}/${embedderVersion}${serializedTokens}`;
|
||||
}
|
||||
|
||||
export function getClientLanguage(): { langName: string, langVersion: string } {
|
||||
let langName = 'unknown';
|
||||
let langVersion = 'unknown';
|
||||
export function getEmbedderName(): { embedderName: string, embedderVersion: string } {
|
||||
let embedderName = 'unknown';
|
||||
let embedderVersion = 'unknown';
|
||||
if (!process.env.PW_LANG_NAME) {
|
||||
langName = 'node';
|
||||
langVersion = process.version.substring(1).split('.').slice(0, 2).join('.');
|
||||
embedderName = 'node';
|
||||
embedderVersion = process.version.substring(1).split('.').slice(0, 2).join('.');
|
||||
} else if (['node', 'python', 'java', 'csharp'].includes(process.env.PW_LANG_NAME)) {
|
||||
langName = process.env.PW_LANG_NAME;
|
||||
langVersion = process.env.PW_LANG_NAME_VERSION ?? 'unknown';
|
||||
embedderName = process.env.PW_LANG_NAME;
|
||||
embedderVersion = process.env.PW_LANG_NAME_VERSION ?? 'unknown';
|
||||
}
|
||||
return { langName, langVersion };
|
||||
return { embedderName, embedderVersion };
|
||||
}
|
||||
|
||||
export function getPlaywrightVersion(majorMinorOnly = false): string {
|
||||
|
@ -333,11 +333,14 @@ scheme.RecorderSource = tObject({
|
||||
scheme.DebugControllerInitializer = tOptional(tObject({}));
|
||||
scheme.DebugControllerInspectRequestedEvent = tObject({
|
||||
selector: tString,
|
||||
locators: tArray(tType('NameValue')),
|
||||
locator: tString,
|
||||
});
|
||||
scheme.DebugControllerStateChangedEvent = tObject({
|
||||
pageCount: tNumber,
|
||||
});
|
||||
scheme.DebugControllerSourceChangedEvent = tObject({
|
||||
text: tString,
|
||||
});
|
||||
scheme.DebugControllerBrowsersChangedEvent = tObject({
|
||||
browsers: tArray(tObject({
|
||||
contexts: tArray(tObject({
|
||||
@ -345,9 +348,11 @@ scheme.DebugControllerBrowsersChangedEvent = tObject({
|
||||
})),
|
||||
})),
|
||||
});
|
||||
scheme.DebugControllerSourcesChangedEvent = tObject({
|
||||
sources: tArray(tType('RecorderSource')),
|
||||
scheme.DebugControllerInitializeParams = tObject({
|
||||
codegenId: tString,
|
||||
sdkLanguage: tEnum(['javascript', 'python', 'java', 'csharp']),
|
||||
});
|
||||
scheme.DebugControllerInitializeResult = tOptional(tObject({}));
|
||||
scheme.DebugControllerSetReportStateChangedParams = tObject({
|
||||
enabled: tBoolean,
|
||||
});
|
||||
@ -360,8 +365,6 @@ scheme.DebugControllerNavigateParams = tObject({
|
||||
scheme.DebugControllerNavigateResult = tOptional(tObject({}));
|
||||
scheme.DebugControllerSetRecorderModeParams = tObject({
|
||||
mode: tEnum(['inspecting', 'recording', 'none']),
|
||||
language: tOptional(tString),
|
||||
file: tOptional(tString),
|
||||
});
|
||||
scheme.DebugControllerSetRecorderModeResult = tOptional(tObject({}));
|
||||
scheme.DebugControllerHighlightParams = tObject({
|
||||
|
@ -25,7 +25,6 @@ import { Recorder } from './recorder';
|
||||
import { EmptyRecorderApp } from './recorder/recorderApp';
|
||||
import { asLocator } from './isomorphic/locatorGenerators';
|
||||
import type { Language } from './isomorphic/locatorGenerators';
|
||||
import type { NameValue } from '../common/types';
|
||||
|
||||
const internalMetadata = serverSideCallMetadata();
|
||||
|
||||
@ -34,7 +33,7 @@ export class DebugController extends SdkObject {
|
||||
BrowsersChanged: 'browsersChanged',
|
||||
StateChanged: 'stateChanged',
|
||||
InspectRequested: 'inspectRequested',
|
||||
SourcesChanged: 'sourcesChanged',
|
||||
SourceChanged: 'sourceChanged',
|
||||
};
|
||||
|
||||
private _autoCloseTimer: NodeJS.Timeout | undefined;
|
||||
@ -42,12 +41,19 @@ export class DebugController extends SdkObject {
|
||||
private _autoCloseAllowed = false;
|
||||
private _trackHierarchyListener: InstrumentationListener | undefined;
|
||||
private _playwright: Playwright;
|
||||
_sdkLanguage: Language = 'javascript';
|
||||
_codegenId: string = 'playwright-test';
|
||||
|
||||
constructor(playwright: Playwright) {
|
||||
super({ attribution: { isInternalPlaywright: true }, instrumentation: createInstrumentation() } as any, undefined, 'DebugController');
|
||||
this._playwright = playwright;
|
||||
}
|
||||
|
||||
initialize(codegenId: string, sdkLanguage: Language) {
|
||||
this._codegenId = codegenId;
|
||||
this._sdkLanguage = sdkLanguage;
|
||||
}
|
||||
|
||||
setAutoCloseAllowed(allowed: boolean) {
|
||||
this._autoCloseAllowed = allowed;
|
||||
}
|
||||
@ -83,7 +89,8 @@ export class DebugController extends SdkObject {
|
||||
await p.mainFrame().goto(internalMetadata, url);
|
||||
}
|
||||
|
||||
async setRecorderMode(params: { mode: Mode, language?: string, file?: string }) {
|
||||
async setRecorderMode(params: { mode: Mode, file?: string }) {
|
||||
// TODO: |file| is only used in the legacy mode.
|
||||
await this._closeBrowsersWithoutPages();
|
||||
|
||||
if (params.mode === 'none') {
|
||||
@ -108,7 +115,7 @@ export class DebugController extends SdkObject {
|
||||
for (const recorder of await this._allRecorders()) {
|
||||
recorder.setHighlightedSelector('');
|
||||
if (params.mode === 'recording')
|
||||
recorder.setOutput(params.language!, params.file);
|
||||
recorder.setOutput(this._codegenId, params.file);
|
||||
recorder.setMode(params.mode);
|
||||
}
|
||||
this.setAutoCloseEnabled(true);
|
||||
@ -216,11 +223,12 @@ class InspectingRecorderApp extends EmptyRecorderApp {
|
||||
}
|
||||
|
||||
override async setSelector(selector: string): Promise<void> {
|
||||
const locators: NameValue[] = ['javascript', 'python', 'java', 'csharp'].map(l => ({ name: l, value: asLocator(l as Language, selector) }));
|
||||
this._debugController.emit(DebugController.Events.InspectRequested, { selector, locators });
|
||||
const locator: string = asLocator(this._debugController._sdkLanguage, selector);
|
||||
this._debugController.emit(DebugController.Events.InspectRequested, { selector, locator });
|
||||
}
|
||||
|
||||
override async setSources(sources: Source[]): Promise<void> {
|
||||
this._debugController.emit(DebugController.Events.SourcesChanged, sources);
|
||||
const source = sources.find(s => s.id === this._debugController._codegenId);
|
||||
this._debugController.emit(DebugController.Events.SourceChanged, source?.text || '');
|
||||
}
|
||||
}
|
||||
|
@ -28,14 +28,18 @@ export class DebugControllerDispatcher extends Dispatcher<DebugController, chann
|
||||
this._object.on(DebugController.Events.StateChanged, params => {
|
||||
this._dispatchEvent('stateChanged', params);
|
||||
});
|
||||
this._object.on(DebugController.Events.InspectRequested, ({ selector, locators }) => {
|
||||
this._dispatchEvent('inspectRequested', { selector, locators });
|
||||
this._object.on(DebugController.Events.InspectRequested, ({ selector, locator }) => {
|
||||
this._dispatchEvent('inspectRequested', { selector, locator });
|
||||
});
|
||||
this._object.on(DebugController.Events.SourcesChanged, sources => {
|
||||
this._dispatchEvent('sourcesChanged', { sources });
|
||||
this._object.on(DebugController.Events.SourceChanged, text => {
|
||||
this._dispatchEvent('sourceChanged', { text });
|
||||
});
|
||||
}
|
||||
|
||||
async initialize(params: channels.DebugControllerInitializeParams) {
|
||||
this._object.initialize(params.codegenId, params.sdkLanguage);
|
||||
}
|
||||
|
||||
async setReportStateChanged(params: channels.DebugControllerSetReportStateChangedParams) {
|
||||
this._object.setReportStateChanged(params.enabled);
|
||||
}
|
||||
|
@ -214,8 +214,8 @@ export class Recorder implements InstrumentationListener {
|
||||
this._refreshOverlay();
|
||||
}
|
||||
|
||||
setOutput(language: string, outputFile: string | undefined) {
|
||||
this._contextRecorder.setOutput(language, outputFile);
|
||||
setOutput(codegenId: string, outputFile: string | undefined) {
|
||||
this._contextRecorder.setOutput(codegenId, outputFile);
|
||||
}
|
||||
|
||||
private _refreshOverlay() {
|
||||
@ -367,7 +367,7 @@ class ContextRecorder extends EventEmitter {
|
||||
this._generator = generator;
|
||||
}
|
||||
|
||||
setOutput(language: string, outputFile: string | undefined) {
|
||||
setOutput(codegenId: string, outputFile?: string) {
|
||||
const languages = new Set([
|
||||
new JavaLanguageGenerator(),
|
||||
new JavaScriptLanguageGenerator(/* isPlaywrightTest */false),
|
||||
@ -379,10 +379,9 @@ class ContextRecorder extends EventEmitter {
|
||||
new CSharpLanguageGenerator('nunit'),
|
||||
new CSharpLanguageGenerator('library'),
|
||||
]);
|
||||
const primaryLanguage = [...languages].find(l => l.id === language);
|
||||
const primaryLanguage = [...languages].find(l => l.id === codegenId);
|
||||
if (!primaryLanguage)
|
||||
throw new Error(`\n===============================\nUnsupported language: '${language}'\n===============================\n`);
|
||||
|
||||
throw new Error(`\n===============================\nUnsupported language: '${codegenId}'\n===============================\n`);
|
||||
languages.delete(primaryLanguage);
|
||||
this._orderedLanguages = [primaryLanguage, ...languages];
|
||||
this._throttledOutputFile = outputFile ? new ThrottledFile(outputFile) : null;
|
||||
|
@ -33,7 +33,7 @@ export class JavaScriptLanguageGenerator implements LanguageGenerator {
|
||||
private _isTest: boolean;
|
||||
|
||||
constructor(isTest: boolean) {
|
||||
this.id = isTest ? 'test' : 'javascript';
|
||||
this.id = isTest ? 'playwright-test' : 'javascript';
|
||||
this.name = isTest ? 'Test Runner' : 'Library';
|
||||
this._isTest = isTest;
|
||||
}
|
||||
@ -175,7 +175,7 @@ ${useText ? '\ntest.use(' + useText + ');\n' : ''}
|
||||
}
|
||||
|
||||
generateTestFooter(saveStorage: string | undefined): string {
|
||||
return `\n});`;
|
||||
return `});`;
|
||||
}
|
||||
|
||||
generateStandaloneHeader(options: LanguageGeneratorOptions): string {
|
||||
|
@ -37,7 +37,7 @@ export class PythonLanguageGenerator implements LanguageGenerator {
|
||||
private _isPyTest: boolean;
|
||||
|
||||
constructor(isAsync: boolean, isPyTest: boolean) {
|
||||
this.id = isPyTest ? 'pytest' : (isAsync ? 'python-async' : 'python');
|
||||
this.id = isPyTest ? 'python-pytest' : (isAsync ? 'python-async' : 'python');
|
||||
this.name = isPyTest ? 'Pytest' : (isAsync ? 'Library Async' : 'Library');
|
||||
this._isAsync = isAsync;
|
||||
this._isPyTest = isPyTest;
|
||||
|
@ -22,7 +22,7 @@ import * as fs from 'fs';
|
||||
import { lockfile } from '../../utilsBundle';
|
||||
import { getLinuxDistributionInfo } from '../../utils/linuxUtils';
|
||||
import { fetchData } from '../../common/netUtils';
|
||||
import { getClientLanguage } from '../../common/userAgent';
|
||||
import { getEmbedderName } from '../../common/userAgent';
|
||||
import { getFromENV, getAsBooleanFromENV, calculateSha1, wrapInASCIIBox } from '../../utils';
|
||||
import { removeFolders, existsAsync, canAccessFile } from '../../utils/fileUtils';
|
||||
import { hostPlatform } from '../../utils/hostPlatform';
|
||||
@ -696,9 +696,9 @@ export class Registry {
|
||||
if (!executable._install)
|
||||
throw new Error(`ERROR: Playwright does not support installing ${executable.name}`);
|
||||
|
||||
const { langName } = getClientLanguage();
|
||||
if (!getAsBooleanFromENV('CI') && !executable._isHermeticInstallation && !forceReinstall && executable.executablePath(langName)) {
|
||||
const command = buildPlaywrightCLICommand(langName, 'install --force ' + executable.name);
|
||||
const { embedderName } = getEmbedderName();
|
||||
if (!getAsBooleanFromENV('CI') && !executable._isHermeticInstallation && !forceReinstall && executable.executablePath(embedderName)) {
|
||||
const command = buildPlaywrightCLICommand(embedderName, 'install --force ' + executable.name);
|
||||
throw new Error('\n' + wrapInASCIIBox([
|
||||
`ATTENTION: "${executable.name}" is already installed on the system!`,
|
||||
``,
|
||||
|
@ -591,11 +591,12 @@ export type DebugControllerInitializer = {};
|
||||
export interface DebugControllerEventTarget {
|
||||
on(event: 'inspectRequested', callback: (params: DebugControllerInspectRequestedEvent) => void): this;
|
||||
on(event: 'stateChanged', callback: (params: DebugControllerStateChangedEvent) => void): this;
|
||||
on(event: 'sourceChanged', callback: (params: DebugControllerSourceChangedEvent) => void): this;
|
||||
on(event: 'browsersChanged', callback: (params: DebugControllerBrowsersChangedEvent) => void): this;
|
||||
on(event: 'sourcesChanged', callback: (params: DebugControllerSourcesChangedEvent) => void): this;
|
||||
}
|
||||
export interface DebugControllerChannel extends DebugControllerEventTarget, Channel {
|
||||
_type_DebugController: boolean;
|
||||
initialize(params: DebugControllerInitializeParams, metadata?: Metadata): Promise<DebugControllerInitializeResult>;
|
||||
setReportStateChanged(params: DebugControllerSetReportStateChangedParams, metadata?: Metadata): Promise<DebugControllerSetReportStateChangedResult>;
|
||||
resetForReuse(params?: DebugControllerResetForReuseParams, metadata?: Metadata): Promise<DebugControllerResetForReuseResult>;
|
||||
navigate(params: DebugControllerNavigateParams, metadata?: Metadata): Promise<DebugControllerNavigateResult>;
|
||||
@ -607,11 +608,14 @@ export interface DebugControllerChannel extends DebugControllerEventTarget, Chan
|
||||
}
|
||||
export type DebugControllerInspectRequestedEvent = {
|
||||
selector: string,
|
||||
locators: NameValue[],
|
||||
locator: string,
|
||||
};
|
||||
export type DebugControllerStateChangedEvent = {
|
||||
pageCount: number,
|
||||
};
|
||||
export type DebugControllerSourceChangedEvent = {
|
||||
text: string,
|
||||
};
|
||||
export type DebugControllerBrowsersChangedEvent = {
|
||||
browsers: {
|
||||
contexts: {
|
||||
@ -619,9 +623,14 @@ export type DebugControllerBrowsersChangedEvent = {
|
||||
}[],
|
||||
}[],
|
||||
};
|
||||
export type DebugControllerSourcesChangedEvent = {
|
||||
sources: RecorderSource[],
|
||||
export type DebugControllerInitializeParams = {
|
||||
codegenId: string,
|
||||
sdkLanguage: 'javascript' | 'python' | 'java' | 'csharp',
|
||||
};
|
||||
export type DebugControllerInitializeOptions = {
|
||||
|
||||
};
|
||||
export type DebugControllerInitializeResult = void;
|
||||
export type DebugControllerSetReportStateChangedParams = {
|
||||
enabled: boolean,
|
||||
};
|
||||
@ -641,12 +650,9 @@ export type DebugControllerNavigateOptions = {
|
||||
export type DebugControllerNavigateResult = void;
|
||||
export type DebugControllerSetRecorderModeParams = {
|
||||
mode: 'inspecting' | 'recording' | 'none',
|
||||
language?: string,
|
||||
file?: string,
|
||||
};
|
||||
export type DebugControllerSetRecorderModeOptions = {
|
||||
language?: string,
|
||||
file?: string,
|
||||
|
||||
};
|
||||
export type DebugControllerSetRecorderModeResult = void;
|
||||
export type DebugControllerHighlightParams = {
|
||||
@ -669,8 +675,8 @@ export type DebugControllerCloseAllBrowsersResult = void;
|
||||
export interface DebugControllerEvents {
|
||||
'inspectRequested': DebugControllerInspectRequestedEvent;
|
||||
'stateChanged': DebugControllerStateChangedEvent;
|
||||
'sourceChanged': DebugControllerSourceChangedEvent;
|
||||
'browsersChanged': DebugControllerBrowsersChangedEvent;
|
||||
'sourcesChanged': DebugControllerSourcesChangedEvent;
|
||||
}
|
||||
|
||||
// ----------- SocksSupport -----------
|
||||
|
@ -660,6 +660,17 @@ DebugController:
|
||||
type: interface
|
||||
|
||||
commands:
|
||||
initialize:
|
||||
parameters:
|
||||
codegenId: string
|
||||
sdkLanguage:
|
||||
type: enum
|
||||
literals:
|
||||
- javascript
|
||||
- python
|
||||
- java
|
||||
- csharp
|
||||
|
||||
setReportStateChanged:
|
||||
parameters:
|
||||
enabled: boolean
|
||||
@ -678,8 +689,6 @@ DebugController:
|
||||
- inspecting
|
||||
- recording
|
||||
- none
|
||||
language: string?
|
||||
file: string?
|
||||
|
||||
highlight:
|
||||
parameters:
|
||||
@ -695,14 +704,16 @@ DebugController:
|
||||
inspectRequested:
|
||||
parameters:
|
||||
selector: string
|
||||
locators:
|
||||
type: array
|
||||
items: NameValue
|
||||
locator: string
|
||||
|
||||
stateChanged:
|
||||
parameters:
|
||||
pageCount: number
|
||||
|
||||
sourceChanged:
|
||||
parameters:
|
||||
text: string
|
||||
|
||||
# Deprecated
|
||||
browsersChanged:
|
||||
parameters:
|
||||
@ -720,12 +731,6 @@ DebugController:
|
||||
type: array
|
||||
items: string
|
||||
|
||||
sourcesChanged:
|
||||
parameters:
|
||||
sources:
|
||||
type: array
|
||||
items: RecorderSource
|
||||
|
||||
SocksSupport:
|
||||
type: interface
|
||||
|
||||
|
@ -70,20 +70,10 @@ test('should pick element', async ({ backend, connectedBrowser }) => {
|
||||
expect(events).toEqual([
|
||||
{
|
||||
selector: 'body',
|
||||
locators: [
|
||||
{ name: 'javascript', value: 'locator(\'body\')' },
|
||||
{ name: 'python', value: 'locator("body")' },
|
||||
{ name: 'java', value: 'locator("body")' },
|
||||
{ name: 'csharp', value: 'Locator("body")' }
|
||||
]
|
||||
locator: 'locator(\'body\')',
|
||||
}, {
|
||||
selector: 'body',
|
||||
locators: [
|
||||
{ name: 'javascript', value: 'locator(\'body\')' },
|
||||
{ name: 'python', value: 'locator("body")' },
|
||||
{ name: 'java', value: 'locator("body")' },
|
||||
{ name: 'csharp', value: 'Locator("body")' }
|
||||
]
|
||||
locator: 'locator(\'body\')',
|
||||
},
|
||||
]);
|
||||
|
||||
@ -156,3 +146,29 @@ test('should highlight all', async ({ backend, connectedBrowser }) => {
|
||||
await expect(page1.getByText('locator(\'button\')')).toBeHidden({ timeout: 1000000 });
|
||||
await expect(page2.getByText('locator(\'button\')')).toBeHidden();
|
||||
});
|
||||
|
||||
test('should record', async ({ backend, connectedBrowser }) => {
|
||||
const events = [];
|
||||
backend.on('sourceChanged', event => events.push(event));
|
||||
|
||||
await backend.setMode({ mode: 'recording' });
|
||||
|
||||
const context = await connectedBrowser._newContextForReuse();
|
||||
const [page] = context.pages();
|
||||
|
||||
await page.locator('body').click();
|
||||
|
||||
await expect.poll(() => events[events.length - 1]).toEqual({
|
||||
text: `import { test, expect } from '@playwright/test';
|
||||
|
||||
test('test', async ({ page }) => {
|
||||
await page.goto('about:blank');
|
||||
await page.locator('body').click();
|
||||
});`
|
||||
});
|
||||
const length = events.length;
|
||||
// No events after mode disabled
|
||||
await backend.setMode({ mode: 'none' });
|
||||
await page.locator('body').click();
|
||||
expect(events).toHaveLength(length);
|
||||
});
|
||||
|
@ -21,7 +21,7 @@ import { test, expect } from './inspectorTest';
|
||||
const emptyHTML = new URL('file://' + path.join(__dirname, '..', '..', 'assets', 'empty.html')).toString();
|
||||
|
||||
test('should print the correct imports and context options', async ({ runCLI }) => {
|
||||
const cli = runCLI(['--target=pytest', emptyHTML]);
|
||||
const cli = runCLI(['--target=python-pytest', emptyHTML]);
|
||||
const expectedResult = `from playwright.sync_api import Page, expect
|
||||
|
||||
|
||||
@ -34,7 +34,7 @@ test('should print the correct context options when using a device and lang', as
|
||||
test.skip(browserName !== 'webkit');
|
||||
|
||||
const tmpFile = testInfo.outputPath('script.js');
|
||||
const cli = runCLI(['--target=pytest', '--device=iPhone 11', '--lang=en-US', '--output', tmpFile, emptyHTML]);
|
||||
const cli = runCLI(['--target=python-pytest', '--device=iPhone 11', '--lang=en-US', '--output', tmpFile, emptyHTML]);
|
||||
await cli.exited;
|
||||
const content = fs.readFileSync(tmpFile);
|
||||
expect(content.toString()).toBe(`import pytest
|
||||
@ -54,7 +54,7 @@ def test_example(page: Page) -> None:
|
||||
|
||||
test('should save the codegen output to a file if specified', async ({ runCLI }, testInfo) => {
|
||||
const tmpFile = testInfo.outputPath('test_example.py');
|
||||
const cli = runCLI(['--target=pytest', '--output', tmpFile, emptyHTML]);
|
||||
const cli = runCLI(['--target=python-pytest', '--output', tmpFile, emptyHTML]);
|
||||
await cli.exited;
|
||||
const content = fs.readFileSync(tmpFile);
|
||||
expect(content.toString()).toBe(`from playwright.sync_api import Page, expect
|
||||
|
@ -25,7 +25,6 @@ test('should print the correct imports and context options', async ({ runCLI })
|
||||
const expectedResult = `import { test, expect } from '@playwright/test';
|
||||
|
||||
test('test', async ({ page }) => {
|
||||
|
||||
});`;
|
||||
await cli.waitFor(expectedResult);
|
||||
expect(cli.text()).toContain(expectedResult);
|
||||
@ -93,7 +92,7 @@ test('test', async ({ page }) => {`;
|
||||
|
||||
test('should work with --save-har', async ({ runCLI }, testInfo) => {
|
||||
const harFileName = testInfo.outputPath('har.har');
|
||||
const cli = runCLI(['--target=test', `--save-har=${harFileName}`]);
|
||||
const cli = runCLI(['--target=playwright-test', `--save-har=${harFileName}`]);
|
||||
const expectedResult = `
|
||||
recordHar: {
|
||||
mode: 'minimal',
|
||||
|
@ -33,11 +33,11 @@ const codegenLang2Id: Map<string, string> = new Map([
|
||||
['Java', 'java'],
|
||||
['Python', 'python'],
|
||||
['Python Async', 'python-async'],
|
||||
['Pytest', 'pytest'],
|
||||
['Pytest', 'python-pytest'],
|
||||
['C#', 'csharp'],
|
||||
['C# NUnit', 'csharp-nunit'],
|
||||
['C# MSTest', 'csharp-mstest'],
|
||||
['Playwright Test', 'test'],
|
||||
['Playwright Test', 'playwright-test'],
|
||||
]);
|
||||
const codegenLangId2lang = new Map([...codegenLang2Id.entries()].map(([lang, langId]) => [langId, lang]));
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user