From c4eb2d4b1e17a0de1cea7220be45545c7c524614 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Fri, 20 Aug 2021 21:32:21 +0200 Subject: [PATCH] chore: move sdkLanguage over to the protocol init call (#8329) --- src/browserServerImpl.ts | 2 +- src/cli/driver.ts | 4 +-- src/client/android.ts | 2 +- src/client/browserContext.ts | 5 +-- src/client/browserType.ts | 1 - src/client/connection.ts | 2 +- src/client/electron.ts | 1 - src/dispatchers/androidDispatcher.ts | 2 +- src/dispatchers/dispatcher.ts | 6 ++-- src/inprocess.ts | 2 +- src/protocol/channels.ts | 8 +---- src/protocol/protocol.yml | 7 +--- src/protocol/validator.ts | 8 +---- src/remote/playwrightServer.ts | 2 +- src/server/android/android.ts | 6 ++-- src/server/browser.ts | 1 + src/server/browserType.ts | 4 +-- src/server/chromium/chromium.ts | 4 +-- src/server/chromium/crPage.ts | 21 ++--------- src/server/electron/electron.ts | 1 - src/server/playwright.ts | 7 ++-- .../supplements/recorder/recorderApp.ts | 1 - src/server/supplements/recorderSupplement.ts | 2 +- src/server/trace/viewer/traceModel.ts | 2 +- src/server/trace/viewer/traceViewer.ts | 5 ++- src/server/types.ts | 1 - src/utils/registry.ts | 35 +++++++++++++------ src/web/traceViewer/ui/workbench.tsx | 1 - 28 files changed, 57 insertions(+), 86 deletions(-) diff --git a/src/browserServerImpl.ts b/src/browserServerImpl.ts index 5741357207..92c28a4ac8 100644 --- a/src/browserServerImpl.ts +++ b/src/browserServerImpl.ts @@ -43,7 +43,7 @@ export class BrowserServerLauncherImpl implements BrowserServerLauncher { } async launchServer(options: LaunchServerOptions = {}): Promise { - const playwright = createPlaywright(); + const playwright = createPlaywright('javascript'); // 1. Pre-launch the browser const browser = await playwright[this._browserName].launch(internalCallMetadata(), { ...options, diff --git a/src/cli/driver.ts b/src/cli/driver.ts index 71145dfd8b..8252acca07 100644 --- a/src/cli/driver.ts +++ b/src/cli/driver.ts @@ -34,8 +34,8 @@ export function printApiJson() { export function runDriver() { const dispatcherConnection = new DispatcherConnection(); - new Root(dispatcherConnection, async rootScope => { - const playwright = createPlaywright(); + new Root(dispatcherConnection, async (rootScope, { sdkLanguage }) => { + const playwright = createPlaywright(sdkLanguage); return new PlaywrightDispatcher(rootScope, playwright); }); const transport = new Transport(process.stdout, process.stdin); diff --git a/src/client/android.ts b/src/client/android.ts index 8fc54deb41..7da0893705 100644 --- a/src/client/android.ts +++ b/src/client/android.ts @@ -394,7 +394,7 @@ export class AndroidWebView extends EventEmitter implements api.AndroidWebView { private async _fetchPage(): Promise { return this._device._wrapApiCall(async (channel: channels.AndroidDeviceChannel) => { - const { context } = await channel.connectToWebView({ pid: this._data.pid, sdkLanguage: 'javascript' }); + const { context } = await channel.connectToWebView({ pid: this._data.pid }); return BrowserContext.from(context).pages()[0]; }); } diff --git a/src/client/browserContext.ts b/src/client/browserContext.ts index 6615392227..a8b72abe56 100644 --- a/src/client/browserContext.ts +++ b/src/client/browserContext.ts @@ -45,9 +45,7 @@ export class BrowserContext extends ChannelOwner; - _options: channels.BrowserNewContextParams = { - sdkLanguage: 'javascript' - }; + _options: channels.BrowserNewContextParams = { }; readonly tracing: Tracing; private _closed = false; @@ -360,7 +358,6 @@ export async function prepareBrowserContextParams(options: BrowserContextOptions if (options.extraHTTPHeaders) network.validateHeaders(options.extraHTTPHeaders); const contextParams: channels.BrowserNewContextParams = { - sdkLanguage: 'javascript', ...options, viewport: options.viewport === null ? undefined : options.viewport, noDefaultViewport: options.viewport === null, diff --git a/src/client/browserType.ts b/src/client/browserType.ts index f062263ea0..baad567735 100644 --- a/src/client/browserType.ts +++ b/src/client/browserType.ts @@ -245,7 +245,6 @@ export class BrowserType extends ChannelOwner { async initialize(): Promise { return Playwright.from((await this._channel.initialize({ - language: 'javascript', + sdkLanguage: 'javascript', })).playwright); } } diff --git a/src/client/electron.ts b/src/client/electron.ts index c49399cb24..d171daa00e 100644 --- a/src/client/electron.ts +++ b/src/client/electron.ts @@ -48,7 +48,6 @@ export class Electron extends ChannelOwner { return this._wrapApiCall(async (channel: channels.ElectronChannel) => { const params: channels.ElectronLaunchParams = { - sdkLanguage: 'javascript', ...options, extraHTTPHeaders: options.extraHTTPHeaders && headersObjectToArray(options.extraHTTPHeaders), env: envObjectToArray(options.env ? options.env : process.env), diff --git a/src/dispatchers/androidDispatcher.ts b/src/dispatchers/androidDispatcher.ts index 86caa8892c..54ca7c6594 100644 --- a/src/dispatchers/androidDispatcher.ts +++ b/src/dispatchers/androidDispatcher.ts @@ -165,7 +165,7 @@ export class AndroidDeviceDispatcher extends Dispatcher { - return { context: new BrowserContextDispatcher(this._scope, await this._object.connectToWebView(params.pid, params.sdkLanguage)) }; + return { context: new BrowserContextDispatcher(this._scope, await this._object.connectToWebView(params.pid)) }; } } diff --git a/src/dispatchers/dispatcher.ts b/src/dispatchers/dispatcher.ts index c294424e13..5be5dca39e 100644 --- a/src/dispatchers/dispatcher.ts +++ b/src/dispatchers/dispatcher.ts @@ -125,16 +125,16 @@ export type DispatcherScope = Dispatcher; export class Root extends Dispatcher<{ guid: '' }, {}> { private _initialized = false; - constructor(connection: DispatcherConnection, private readonly createPlaywright?: (scope: DispatcherScope) => Promise) { + constructor(connection: DispatcherConnection, private readonly createPlaywright?: (scope: DispatcherScope, options: channels.RootInitializeParams) => Promise) { super(connection, { guid: '' }, 'Root', {}, true); } - async initialize(params: { language?: string }): Promise { + async initialize(params: channels.RootInitializeParams): Promise { assert(this.createPlaywright); assert(!this._initialized); this._initialized = true; return { - playwright: await this.createPlaywright(this), + playwright: await this.createPlaywright(this, params), }; } } diff --git a/src/inprocess.ts b/src/inprocess.ts index 9bd5b41fc8..ea1f6c7593 100644 --- a/src/inprocess.ts +++ b/src/inprocess.ts @@ -22,7 +22,7 @@ import { Connection } from './client/connection'; import { BrowserServerLauncherImpl } from './browserServerImpl'; function setupInProcess(): PlaywrightAPI { - const playwright = createPlaywright(); + const playwright = createPlaywright('javascript'); const clientConnection = new Connection(); const dispatcherConnection = new DispatcherConnection(); diff --git a/src/protocol/channels.ts b/src/protocol/channels.ts index edf9112da4..edaa64e7bc 100644 --- a/src/protocol/channels.ts +++ b/src/protocol/channels.ts @@ -158,7 +158,7 @@ export interface RootChannel extends Channel { initialize(params: RootInitializeParams, metadata?: Metadata): Promise; } export type RootInitializeParams = { - language: string, + sdkLanguage: string, }; export type RootInitializeOptions = { @@ -358,7 +358,6 @@ export type BrowserTypeLaunchPersistentContextParams = { downloadsPath?: string, tracesDir?: string, chromiumSandbox?: boolean, - sdkLanguage: string, noDefaultViewport?: boolean, viewport?: { width: number, @@ -484,7 +483,6 @@ export type BrowserTypeLaunchPersistentContextResult = { context: BrowserContextChannel, }; export type BrowserTypeConnectOverCDPParams = { - sdkLanguage: string, endpointURL: string, headers?: NameValue[], slowMo?: number, @@ -522,7 +520,6 @@ export type BrowserKillForTestsParams = {}; export type BrowserKillForTestsOptions = {}; export type BrowserKillForTestsResult = void; export type BrowserNewContextParams = { - sdkLanguage: string, noDefaultViewport?: boolean, viewport?: { width: number, @@ -2802,7 +2799,6 @@ export interface ElectronChannel extends Channel { launch(params: ElectronLaunchParams, metadata?: Metadata): Promise; } export type ElectronLaunchParams = { - sdkLanguage: string, executablePath?: string, args?: string[], cwd?: string, @@ -3165,7 +3161,6 @@ export type AndroidDeviceInputDragOptions = { }; export type AndroidDeviceInputDragResult = void; export type AndroidDeviceLaunchBrowserParams = { - sdkLanguage: string, pkg?: string, ignoreHTTPSErrors?: boolean, javaScriptEnabled?: boolean, @@ -3303,7 +3298,6 @@ export type AndroidDeviceSetDefaultTimeoutNoReplyOptions = { }; export type AndroidDeviceSetDefaultTimeoutNoReplyResult = void; export type AndroidDeviceConnectToWebViewParams = { - sdkLanguage: string, pid: number, }; export type AndroidDeviceConnectToWebViewOptions = { diff --git a/src/protocol/protocol.yml b/src/protocol/protocol.yml index 82555e8814..0a9528a30c 100644 --- a/src/protocol/protocol.yml +++ b/src/protocol/protocol.yml @@ -256,7 +256,6 @@ LaunchOptions: ContextOptions: type: mixin properties: - sdkLanguage: string noDefaultViewport: boolean? viewport: type: object? @@ -332,7 +331,7 @@ Root: initialize: parameters: - language: string + sdkLanguage: string returns: playwright: Playwright @@ -462,7 +461,6 @@ BrowserType: connectOverCDP: parameters: - sdkLanguage: string endpointURL: string headers: type: array? @@ -2384,7 +2382,6 @@ Electron: launch: parameters: - sdkLanguage: string executablePath: string? args: type: array? @@ -2644,7 +2641,6 @@ AndroidDevice: launchBrowser: parameters: - sdkLanguage: string pkg: string? ignoreHTTPSErrors: boolean? javaScriptEnabled: boolean? @@ -2743,7 +2739,6 @@ AndroidDevice: connectToWebView: parameters: - sdkLanguage: string pid: number returns: context: BrowserContext diff --git a/src/protocol/validator.ts b/src/protocol/validator.ts index 9180434466..4e0457a878 100644 --- a/src/protocol/validator.ts +++ b/src/protocol/validator.ts @@ -150,7 +150,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { })), }); scheme.RootInitializeParams = tObject({ - language: tString, + sdkLanguage: tString, }); scheme.PlaywrightSocksConnectedParams = tObject({ uid: tString, @@ -224,7 +224,6 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { downloadsPath: tOptional(tString), tracesDir: tOptional(tString), chromiumSandbox: tOptional(tBoolean), - sdkLanguage: tString, noDefaultViewport: tOptional(tBoolean), viewport: tOptional(tObject({ width: tNumber, @@ -276,7 +275,6 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { slowMo: tOptional(tNumber), }); scheme.BrowserTypeConnectOverCDPParams = tObject({ - sdkLanguage: tString, endpointURL: tString, headers: tOptional(tArray(tType('NameValue'))), slowMo: tOptional(tNumber), @@ -285,7 +283,6 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { scheme.BrowserCloseParams = tOptional(tObject({})); scheme.BrowserKillForTestsParams = tOptional(tObject({})); scheme.BrowserNewContextParams = tObject({ - sdkLanguage: tString, noDefaultViewport: tOptional(tBoolean), viewport: tOptional(tObject({ width: tNumber, @@ -1079,7 +1076,6 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { }); scheme.CDPSessionDetachParams = tOptional(tObject({})); scheme.ElectronLaunchParams = tObject({ - sdkLanguage: tString, executablePath: tOptional(tString), args: tOptional(tArray(tString)), cwd: tOptional(tString), @@ -1217,7 +1213,6 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { steps: tNumber, }); scheme.AndroidDeviceLaunchBrowserParams = tObject({ - sdkLanguage: tString, pkg: tOptional(tString), ignoreHTTPSErrors: tOptional(tBoolean), javaScriptEnabled: tOptional(tBoolean), @@ -1282,7 +1277,6 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { timeout: tNumber, }); scheme.AndroidDeviceConnectToWebViewParams = tObject({ - sdkLanguage: tString, pid: tNumber, }); scheme.AndroidDeviceCloseParams = tOptional(tObject({})); diff --git a/src/remote/playwrightServer.ts b/src/remote/playwrightServer.ts index 56605417f9..11fe45d393 100644 --- a/src/remote/playwrightServer.ts +++ b/src/remote/playwrightServer.ts @@ -47,7 +47,7 @@ export class PlaywrightServer { onConnect: async (connection: DispatcherConnection) => { let playwright: Playwright | undefined; new Root(connection, async (rootScope): Promise => { - playwright = createPlaywright(); + playwright = createPlaywright('javascript'); const dispatcher = new PlaywrightDispatcher(rootScope, playwright); if (process.env.PW_SOCKS_PROXY_PORT) await dispatcher.enableSocksProxy(); diff --git a/src/server/android/android.ts b/src/server/android/android.ts index 6d2a5bec71..40d823c59b 100644 --- a/src/server/android/android.ts +++ b/src/server/android/android.ts @@ -243,14 +243,14 @@ export class AndroidDevice extends SdkObject { return await this._connectToBrowser(socketName, options); } - async connectToWebView(pid: number, sdkLanguage: string): Promise { + async connectToWebView(pid: number): Promise { const webView = this._webViews.get(pid); if (!webView) throw new Error('WebView has been closed'); - return await this._connectToBrowser(`webview_devtools_remote_${pid}`, { sdkLanguage }); + return await this._connectToBrowser(`webview_devtools_remote_${pid}`); } - private async _connectToBrowser(socketName: string, options: types.BrowserContextOptions): Promise { + private async _connectToBrowser(socketName: string, options: types.BrowserContextOptions = {}): Promise { const socket = await this._waitForLocalAbstract(socketName); const androidBrowser = new AndroidBrowser(this, socket); await androidBrowser._init(); diff --git a/src/server/browser.ts b/src/server/browser.ts index ee804a12a4..bc338849f7 100644 --- a/src/server/browser.ts +++ b/src/server/browser.ts @@ -36,6 +36,7 @@ export type PlaywrightOptions = { rootSdkObject: SdkObject; selectors: Selectors; socksProxyPort?: number; + sdkLanguage: string, }; export type BrowserOptions = PlaywrightOptions & { diff --git a/src/server/browserType.ts b/src/server/browserType.ts index 766603200a..0a2c3b5237 100644 --- a/src/server/browserType.ts +++ b/src/server/browserType.ts @@ -165,7 +165,7 @@ export abstract class BrowserType extends SdkObject { const registryExecutable = registry.findExecutable(options.channel || this._name); if (!registryExecutable || registryExecutable.browserName !== this._name) throw new Error(`Unsupported ${this._name} channel "${options.channel}"`); - executable = registryExecutable.executablePathOrDie(); + executable = registryExecutable.executablePathOrDie(this._playwrightOptions.sdkLanguage); await registryExecutable.validateHostRequirements(); } @@ -239,7 +239,7 @@ export abstract class BrowserType extends SdkObject { return { browserProcess, artifactsDir, transport }; } - async connectOverCDP(metadata: CallMetadata, endpointURL: string, options: { slowMo?: number, sdkLanguage: string }, timeout?: number): Promise { + async connectOverCDP(metadata: CallMetadata, endpointURL: string, options: { slowMo?: number }, timeout?: number): Promise { throw new Error('CDP connections are only supported by Chromium'); } diff --git a/src/server/chromium/chromium.ts b/src/server/chromium/chromium.ts index f1ed62eee9..fd7369b270 100644 --- a/src/server/chromium/chromium.ts +++ b/src/server/chromium/chromium.ts @@ -48,7 +48,7 @@ export class Chromium extends BrowserType { this._devtools = this._createDevTools(); } - async connectOverCDP(metadata: CallMetadata, endpointURL: string, options: { slowMo?: number, sdkLanguage: string, headers?: types.HeadersArray }, timeout?: number) { + async connectOverCDP(metadata: CallMetadata, endpointURL: string, options: { slowMo?: number, headers?: types.HeadersArray }, timeout?: number) { const controller = new ProgressController(metadata, this); controller.setLogName('browser'); const browserLogsCollector = new RecentLogsCollector(); @@ -75,7 +75,7 @@ export class Chromium extends BrowserType { slowMo: options.slowMo, name: 'chromium', isChromium: true, - persistent: { sdkLanguage: options.sdkLanguage, noDefaultViewport: true }, + persistent: { noDefaultViewport: true }, browserProcess, protocolLogger: helper.debugProtocolLogger(), browserLogsCollector, diff --git a/src/server/chromium/crPage.ts b/src/server/chromium/crPage.ts index 13ace45a20..454cbff2c0 100644 --- a/src/server/chromium/crPage.ts +++ b/src/server/chromium/crPage.ts @@ -36,7 +36,7 @@ import { CRPDF } from './crPdf'; import { CRBrowserContext } from './crBrowser'; import * as types from '../types'; import { rewriteErrorMessage } from '../../utils/stackTrace'; -import { assert, headersArrayToObject, createGuid, canAccessFile } from '../../utils/utils'; +import { assert, headersArrayToObject, createGuid } from '../../utils/utils'; import { VideoRecorder } from './videoRecorder'; import { Progress } from '../progress'; import { DragManager } from './crDragDrop'; @@ -845,24 +845,7 @@ class FrameSession { async _createVideoRecorder(screencastId: string, options: types.PageScreencastOptions): Promise { assert(!this._screencastId); - const ffmpegPath = registry.findExecutable('ffmpeg')!.executablePath(); - // TODO: use default error message once it's ready. - if (!ffmpegPath || !canAccessFile(ffmpegPath)) { - let message: string = ''; - switch (this._page._browserContext._options.sdkLanguage) { - case 'python': message = 'playwright install ffmpeg'; break; - case 'python-async': message = 'playwright install ffmpeg'; break; - case 'javascript': message = 'npx playwright install ffmpeg'; break; - case 'java': message = 'mvn exec:java -e -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args="install ffmpeg"'; break; - } - throw new Error(` -============================================================ - Please install ffmpeg in order to record video. - - $ ${message} -============================================================ - `); - } + const ffmpegPath = registry.findExecutable('ffmpeg')!.executablePathOrDie(this._page._browserContext._browser.options.sdkLanguage); this._videoRecorder = await VideoRecorder.launch(this._crPage._page, ffmpegPath, options); this._screencastId = screencastId; } diff --git a/src/server/electron/electron.ts b/src/server/electron/electron.ts index 54e87294c3..15e987885a 100644 --- a/src/server/electron/electron.ts +++ b/src/server/electron/electron.ts @@ -163,7 +163,6 @@ export class Electron extends SdkObject { isChromium: true, headful: true, persistent: { - sdkLanguage: options.sdkLanguage, noDefaultViewport: true, acceptDownloads: options.acceptDownloads, bypassCSP: options.bypassCSP, diff --git a/src/server/playwright.ts b/src/server/playwright.ts index 6b6a519470..7bdb6a5714 100644 --- a/src/server/playwright.ts +++ b/src/server/playwright.ts @@ -34,7 +34,7 @@ export class Playwright extends SdkObject { readonly webkit: WebKit; readonly options: PlaywrightOptions; - constructor(isInternal: boolean) { + constructor(sdkLanguage: string, isInternal: boolean) { super({ attribution: { isInternal }, instrumentation: createInstrumentation() } as any, undefined, 'Playwright'); this.instrumentation.addListener({ onCallLog: (logName: string, message: string, sdkObject: SdkObject, metadata: CallMetadata) => { @@ -44,6 +44,7 @@ export class Playwright extends SdkObject { this.options = { rootSdkObject: this, selectors: new Selectors(), + sdkLanguage: sdkLanguage, }; this.chromium = new Chromium(this.options); this.firefox = new Firefox(this.options); @@ -54,6 +55,6 @@ export class Playwright extends SdkObject { } } -export function createPlaywright(isInternal = false) { - return new Playwright(isInternal); +export function createPlaywright(sdkLanguage: string, isInternal: boolean = false) { + return new Playwright(sdkLanguage, isInternal); } diff --git a/src/server/supplements/recorder/recorderApp.ts b/src/server/supplements/recorder/recorderApp.ts index ca2c3da0c4..454f232e19 100644 --- a/src/server/supplements/recorder/recorderApp.ts +++ b/src/server/supplements/recorder/recorderApp.ts @@ -103,7 +103,6 @@ export class RecorderApp extends EventEmitter { const context = await recorderPlaywright.chromium.launchPersistentContext(internalCallMetadata(), '', { channel, executablePath, - sdkLanguage: inspectedContext._options.sdkLanguage, args, noDefaultViewport: true, headless: !!process.env.PWTEST_CLI_HEADLESS || (isUnderTest() && !inspectedContext._browser.options.headful), diff --git a/src/server/supplements/recorderSupplement.ts b/src/server/supplements/recorderSupplement.ts index 3252dc3de3..045aab9794 100644 --- a/src/server/supplements/recorderSupplement.ts +++ b/src/server/supplements/recorderSupplement.ts @@ -78,7 +78,7 @@ export class RecorderSupplement implements InstrumentationListener { context.instrumentation.addListener(this); this._params = params; this._mode = params.startRecording ? 'recording' : 'none'; - const language = params.language || context._options.sdkLanguage; + const language = params.language || context._browser.options.sdkLanguage; const languages = new Set([ new JavaLanguageGenerator(), diff --git a/src/server/trace/viewer/traceModel.ts b/src/server/trace/viewer/traceModel.ts index 4098cc2fb8..e463c816d0 100644 --- a/src/server/trace/viewer/traceModel.ts +++ b/src/server/trace/viewer/traceModel.ts @@ -35,7 +35,7 @@ export class TraceModel { startTime: Number.MAX_VALUE, endTime: Number.MIN_VALUE, browserName: '', - options: { sdkLanguage: '' }, + options: { }, pages: [], resources: [], }; diff --git a/src/server/trace/viewer/traceViewer.ts b/src/server/trace/viewer/traceViewer.ts index 8098eb0bf6..ae4751e089 100644 --- a/src/server/trace/viewer/traceViewer.ts +++ b/src/server/trace/viewer/traceViewer.ts @@ -126,7 +126,7 @@ export class TraceViewer { async show(headless: boolean): Promise { const urlPrefix = await this._server.start(); - const traceViewerPlaywright = createPlaywright(true); + const traceViewerPlaywright = createPlaywright('javascript', true); const traceViewerBrowser = isUnderTest() ? 'chromium' : this._browserName; const args = traceViewerBrowser === 'chromium' ? [ '--app=data:text/html,', @@ -141,7 +141,7 @@ export class TraceViewer { if (traceViewerBrowser === 'chromium') { for (const name of ['chromium', 'chrome', 'msedge']) { try { - registry.findExecutable(name)!.executablePathOrDie(); + registry.findExecutable(name)!.executablePathOrDie(traceViewerPlaywright.options.sdkLanguage); channel = name === 'chromium' ? undefined : name; break; } catch (e) { @@ -161,7 +161,6 @@ Please run 'npx playwright install' to install Playwright browsers const context = await traceViewerPlaywright[traceViewerBrowser as 'chromium'].launchPersistentContext(internalCallMetadata(), '', { // TODO: store language in the trace. channel: channel as any, - sdkLanguage: 'javascript', args, noDefaultViewport: true, headless, diff --git a/src/server/types.ts b/src/server/types.ts index 8b20414c6f..a5a946b740 100644 --- a/src/server/types.ts +++ b/src/server/types.ts @@ -245,7 +245,6 @@ export type SetNetworkCookieParam = { export type EmulatedSize = { viewport: Size, screen: Size }; export type BrowserContextOptions = { - sdkLanguage: string, viewport?: Size, screen?: Size, noDefaultViewport?: boolean, diff --git a/src/utils/registry.ts b/src/utils/registry.ts index 4dec123d62..c4054c1750 100644 --- a/src/utils/registry.ts +++ b/src/utils/registry.ts @@ -225,7 +225,7 @@ export interface Executable { browserName: BrowserName | undefined; installType: 'download-by-default' | 'download-on-demand' | 'install-script' | 'none'; directory: string | undefined; - executablePathOrDie(): string; + executablePathOrDie(sdkLanguage: string): string; executablePath(): string | undefined; validateHostRequirements(): Promise; } @@ -244,16 +244,16 @@ export class Registry { const tokens = EXECUTABLE_PATHS[name][hostPlatform]; return tokens ? path.join(dir, ...tokens) : undefined; }; - const executablePathOrDie = (name: string, e: string | undefined, installByDefault: boolean) => { + const executablePathOrDie = (name: string, e: string | undefined, installByDefault: boolean, sdkLanguage: string) => { if (!e) throw new Error(`${name} is not supported on ${hostPlatform}`); - // TODO: language-specific error message + const installCommand = buildPlaywrightCLICommand(sdkLanguage, `install${installByDefault ? '' : ' ' + name}`); if (!canAccessFile(e)) { const prettyMessage = [ `Looks like Playwright Test or Playwright was just installed or updated.`, `Please run the following command to download new browser${installByDefault ? 's' : ''}:`, ``, - ` npx playwright install${installByDefault ? '' : ' ' + name}`, + ` ${installCommand}`, ``, `<3 Playwright Team`, ].join('\n'); @@ -271,7 +271,7 @@ export class Registry { browserName: 'chromium', directory: chromium.dir, executablePath: () => chromiumExecutable, - executablePathOrDie: () => executablePathOrDie('chromium', chromiumExecutable, chromium.installByDefault), + executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('chromium', chromiumExecutable, chromium.installByDefault, sdkLanguage), installType: chromium.installByDefault ? 'download-by-default' : 'download-on-demand', validateHostRequirements: () => this._validateHostRequirements('chromium', chromium.dir, ['chrome-linux'], [], ['chrome-win']), _install: () => this._downloadExecutable(chromium, chromiumExecutable, DOWNLOAD_URLS['chromium'][hostPlatform], 'PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST'), @@ -286,7 +286,7 @@ export class Registry { browserName: 'chromium', directory: chromiumWithSymbols.dir, executablePath: () => chromiumWithSymbolsExecutable, - executablePathOrDie: () => executablePathOrDie('chromium-with-symbols', chromiumWithSymbolsExecutable, chromiumWithSymbols.installByDefault), + executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('chromium-with-symbols', chromiumWithSymbolsExecutable, chromiumWithSymbols.installByDefault, sdkLanguage), installType: chromiumWithSymbols.installByDefault ? 'download-by-default' : 'download-on-demand', validateHostRequirements: () => this._validateHostRequirements('chromium', chromiumWithSymbols.dir, ['chrome-linux'], [], ['chrome-win']), _install: () => this._downloadExecutable(chromiumWithSymbols, chromiumWithSymbolsExecutable, DOWNLOAD_URLS['chromium-with-symbols'][hostPlatform], 'PLAYWRIGHT_CHROMIUM_DOWNLOAD_HOST'), @@ -369,7 +369,7 @@ export class Registry { browserName: 'firefox', directory: firefox.dir, executablePath: () => firefoxExecutable, - executablePathOrDie: () => executablePathOrDie('firefox', firefoxExecutable, firefox.installByDefault), + executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('firefox', firefoxExecutable, firefox.installByDefault, sdkLanguage), installType: firefox.installByDefault ? 'download-by-default' : 'download-on-demand', validateHostRequirements: () => this._validateHostRequirements('firefox', firefox.dir, ['firefox'], [], ['firefox']), _install: () => this._downloadExecutable(firefox, firefoxExecutable, DOWNLOAD_URLS['firefox'][hostPlatform], 'PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST'), @@ -384,7 +384,7 @@ export class Registry { browserName: 'firefox', directory: firefoxBeta.dir, executablePath: () => firefoxBetaExecutable, - executablePathOrDie: () => executablePathOrDie('firefox-beta', firefoxBetaExecutable, firefoxBeta.installByDefault), + executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('firefox-beta', firefoxBetaExecutable, firefoxBeta.installByDefault, sdkLanguage), installType: firefoxBeta.installByDefault ? 'download-by-default' : 'download-on-demand', validateHostRequirements: () => this._validateHostRequirements('firefox', firefoxBeta.dir, ['firefox'], [], ['firefox']), _install: () => this._downloadExecutable(firefoxBeta, firefoxBetaExecutable, DOWNLOAD_URLS['firefox-beta'][hostPlatform], 'PLAYWRIGHT_FIREFOX_DOWNLOAD_HOST'), @@ -407,7 +407,7 @@ export class Registry { browserName: 'webkit', directory: webkit.dir, executablePath: () => webkitExecutable, - executablePathOrDie: () => executablePathOrDie('webkit', webkitExecutable, webkit.installByDefault), + executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('webkit', webkitExecutable, webkit.installByDefault, sdkLanguage), installType: webkit.installByDefault ? 'download-by-default' : 'download-on-demand', validateHostRequirements: () => this._validateHostRequirements('webkit', webkit.dir, webkitLinuxLddDirectories, ['libGLESv2.so.2', 'libx264.so'], ['']), _install: () => this._downloadExecutable(webkit, webkitExecutable, DOWNLOAD_URLS['webkit'][hostPlatform], 'PLAYWRIGHT_WEBKIT_DOWNLOAD_HOST'), @@ -422,7 +422,7 @@ export class Registry { browserName: undefined, directory: ffmpeg.dir, executablePath: () => ffmpegExecutable, - executablePathOrDie: () => executablePathOrDie('ffmpeg', ffmpegExecutable, ffmpeg.installByDefault), + executablePathOrDie: (sdkLanguage: string) => executablePathOrDie('ffmpeg', ffmpegExecutable, ffmpeg.installByDefault, sdkLanguage), installType: ffmpeg.installByDefault ? 'download-by-default' : 'download-on-demand', validateHostRequirements: () => Promise.resolve(), _install: () => this._downloadExecutable(ffmpeg, ffmpegExecutable, DOWNLOAD_URLS['ffmpeg'][hostPlatform], 'PLAYWRIGHT_FFMPEG_DOWNLOAD_HOST'), @@ -461,7 +461,7 @@ export class Registry { browserName: 'chromium', directory: undefined, executablePath: () => executablePath(false), - executablePathOrDie: () => executablePath(true)!, + executablePathOrDie: (sdkLanguage: string) => executablePath(true)!, installType: install ? 'install-script' : 'none', validateHostRequirements: () => Promise.resolve(), _install: install, @@ -660,6 +660,19 @@ function markerFilePath(browserDirectory: string): string { return path.join(browserDirectory, 'INSTALLATION_COMPLETE'); } +function buildPlaywrightCLICommand(sdkLanguage: string, parameters: string): string { + switch (sdkLanguage) { + case 'python': + return `playwright ${parameters}`; + case 'java': + return `mvn exec:java -e -Dexec.mainClass=com.microsoft.playwright.CLI -Dexec.args="${parameters}"`; + case 'csharp': + return `playwright ${parameters}`; + default: + return `npx playwright ${parameters}`; + } +} + export async function installDefaultBrowsersForNpmInstall() { // PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD should have a value of 0 or 1 if (getAsBooleanFromENV('PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD')) { diff --git a/src/web/traceViewer/ui/workbench.tsx b/src/web/traceViewer/ui/workbench.tsx index 50b7fdbab0..9e55158b21 100644 --- a/src/web/traceViewer/ui/workbench.tsx +++ b/src/web/traceViewer/ui/workbench.tsx @@ -117,7 +117,6 @@ const emptyContext: ContextEntry = { endTime: now, browserName: '', options: { - sdkLanguage: '', deviceScaleFactor: 1, isMobile: false, viewport: { width: 1280, height: 800 },