diff --git a/docs/src/api/class-tracing.md b/docs/src/api/class-tracing.md index a7a008d2dd..48be69c56b 100644 --- a/docs/src/api/class-tracing.md +++ b/docs/src/api/class-tracing.md @@ -7,41 +7,40 @@ Playwright script runs. Start with specifying the folder traces will be stored in: ```js -const browser = await chromium.launch({ traceDir: 'traces' }); +const browser = await chromium.launch(); const context = await browser.newContext(); -await context.tracing.start({ name: 'trace', screenshots: true, snapshots: true }); +await context.tracing.start({ screenshots: true, snapshots: true }); const page = await context.newPage(); await page.goto('https://playwright.dev'); await context.tracing.stop({ path: 'trace.zip' }); ``` ```java -Browser browser = chromium.launch(new BrowserType.LaunchOptions().setTraceDir("trace")); +Browser browser = chromium.launch(); BrowserContext context = browser.newContext(); context.tracing.start(page, new Tracing.StartOptions() - .setName("trace") .setScreenshots(true) .setSnapshots(true); Page page = context.newPage(); page.goto("https://playwright.dev"); context.tracing.stop(new Tracing.StopOptions() - .setSaveAs(Paths.get("trace.zip"))); + .setPath(Paths.get("trace.zip"))); ``` ```python async -browser = await chromium.launch(traceDir='traces') +browser = await chromium.launch() context = await browser.new_context() -await context.tracing.start(name="trace", screenshots=True, snapshots=True) +await context.tracing.start(screenshots=True, snapshots=True) await page.goto("https://playwright.dev") -await context.tracing.stop(save_as = "trace.zip") +await context.tracing.stop(path = "trace.zip") ``` ```python sync -browser = chromium.launch(traceDir='traces') +browser = chromium.launch() context = browser.new_context() -context.tracing.start(name="trace", screenshots=True, snapshots=True) +context.tracing.start(screenshots=True, snapshots=True) page.goto("https://playwright.dev") -context.tracing.stop(save_as = "trace.zip") +context.tracing.stop(path = "trace.zip") ``` ## async method: Tracing.start @@ -49,43 +48,41 @@ context.tracing.stop(save_as = "trace.zip") Start tracing. ```js -await context.tracing.start({ name: 'trace', screenshots: true, snapshots: true }); +await context.tracing.start({ screenshots: true, snapshots: true }); const page = await context.newPage(); await page.goto('https://playwright.dev'); -await context.tracing.stop(); -await context.tracing.export('trace.zip'); +await context.tracing.stop({ path: 'trace.zip' }); ``` ```java context.tracing.start(page, new Tracing.StartOptions() - .setName("trace") .setScreenshots(true) .setSnapshots(true); Page page = context.newPage(); page.goto('https://playwright.dev'); -context.tracing.stop(); -context.tracing.export(Paths.get("trace.zip"))) +context.tracing.stop(new Tracing.StopOptions() + .setPath(Paths.get("trace.zip"))); ``` ```python async await context.tracing.start(name="trace", screenshots=True, snapshots=True) await page.goto("https://playwright.dev") await context.tracing.stop() -await context.tracing.export("trace.zip") +await context.tracing.stop(path = "trace.zip") ``` ```python sync context.tracing.start(name="trace", screenshots=True, snapshots=True) page.goto("https://playwright.dev") context.tracing.stop() -context.tracing.export("trace.zip") +context.tracing.stop(path = "trace.zip") ``` ### option: Tracing.start.name - `name` <[string]> If specified, the trace is going to be saved into the file with the -given name inside the [`option: traceDir`] folder specified in [`method: BrowserType.launch`]. +given name inside the [`option: tracesDir`] folder specified in [`method: BrowserType.launch`]. ### option: Tracing.start.screenshots - `screenshots` <[boolean]> diff --git a/docs/src/api/params.md b/docs/src/api/params.md index 190c1ed8fd..9f2b4896a2 100644 --- a/docs/src/api/params.md +++ b/docs/src/api/params.md @@ -675,9 +675,9 @@ Logger sink for Playwright logging. Maximum time in milliseconds to wait for the browser instance to start. Defaults to `30000` (30 seconds). Pass `0` to disable timeout. -## browser-option-tracedir +## browser-option-tracesdir * langs: js, python, java -- `traceDir` <[path]> +- `tracesDir` <[path]> If specified, traces are saved into this directory. @@ -708,4 +708,4 @@ Slows down Playwright operations by the specified amount of milliseconds. Useful - %%-browser-option-ignoredefaultargs-%% - %%-browser-option-proxy-%% - %%-browser-option-timeout-%% -- %%-browser-option-tracedir-%% +- %%-browser-option-tracesdir-%% diff --git a/src/browserServerImpl.ts b/src/browserServerImpl.ts index 53bce3cfde..a589b695b1 100644 --- a/src/browserServerImpl.ts +++ b/src/browserServerImpl.ts @@ -107,10 +107,8 @@ class ConnectedBrowserDispatcher extends Dispatcher { - if (params.recordVideo) { - // TODO: we should create a separate temp directory or accept a launchServer parameter. - params.recordVideo.dir = this._object.options.downloadsPath!; - } + if (params.recordVideo) + params.recordVideo.dir = this._object.options.artifactsDir; const context = await this._object.newContext(params); this._contexts.add(context); context._setSelectors(this._selectors); diff --git a/src/protocol/channels.ts b/src/protocol/channels.ts index b521463530..ac662bf859 100644 --- a/src/protocol/channels.ts +++ b/src/protocol/channels.ts @@ -238,7 +238,7 @@ export type BrowserTypeLaunchParams = { password?: string, }, downloadsPath?: string, - traceDir?: string, + tracesDir?: string, chromiumSandbox?: boolean, firefoxUserPrefs?: any, slowMo?: number, @@ -263,7 +263,7 @@ export type BrowserTypeLaunchOptions = { password?: string, }, downloadsPath?: string, - traceDir?: string, + tracesDir?: string, chromiumSandbox?: boolean, firefoxUserPrefs?: any, slowMo?: number, @@ -291,7 +291,7 @@ export type BrowserTypeLaunchPersistentContextParams = { password?: string, }, downloadsPath?: string, - traceDir?: string, + tracesDir?: string, chromiumSandbox?: boolean, sdkLanguage: string, noDefaultViewport?: boolean, @@ -362,7 +362,7 @@ export type BrowserTypeLaunchPersistentContextOptions = { password?: string, }, downloadsPath?: string, - traceDir?: string, + tracesDir?: string, chromiumSandbox?: boolean, noDefaultViewport?: boolean, viewport?: { diff --git a/src/protocol/protocol.yml b/src/protocol/protocol.yml index 2e2b88dab0..8b372e33bf 100644 --- a/src/protocol/protocol.yml +++ b/src/protocol/protocol.yml @@ -249,7 +249,7 @@ LaunchOptions: username: string? password: string? downloadsPath: string? - traceDir: string? + tracesDir: string? chromiumSandbox: boolean? diff --git a/src/protocol/validator.ts b/src/protocol/validator.ts index 20f59c0535..1ae820a8b1 100644 --- a/src/protocol/validator.ts +++ b/src/protocol/validator.ts @@ -175,7 +175,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { password: tOptional(tString), })), downloadsPath: tOptional(tString), - traceDir: tOptional(tString), + tracesDir: tOptional(tString), chromiumSandbox: tOptional(tBoolean), firefoxUserPrefs: tOptional(tAny), slowMo: tOptional(tNumber), @@ -200,7 +200,7 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { password: tOptional(tString), })), downloadsPath: tOptional(tString), - traceDir: tOptional(tString), + tracesDir: tOptional(tString), chromiumSandbox: tOptional(tBoolean), sdkLanguage: tString, noDefaultViewport: tOptional(tBoolean), diff --git a/src/server/android/android.ts b/src/server/android/android.ts index 6645aaed87..908bd1c6d3 100644 --- a/src/server/android/android.ts +++ b/src/server/android/android.ts @@ -265,7 +265,9 @@ export class AndroidDevice extends SdkObject { isChromium: true, slowMo: 0, persistent: { ...options, noDefaultViewport: true }, - downloadsPath: undefined, + artifactsDir: '', + downloadsPath: '', + tracesDir: '', browserProcess: new ClankBrowserProcess(androidBrowser), proxy: options.proxy, protocolLogger: helper.debugProtocolLogger(), diff --git a/src/server/browser.ts b/src/server/browser.ts index 298de6a0a4..9f913a8258 100644 --- a/src/server/browser.ts +++ b/src/server/browser.ts @@ -42,8 +42,9 @@ export type BrowserOptions = PlaywrightOptions & { name: string, isChromium: boolean, channel?: string, - downloadsPath?: string, - traceDir?: string, + artifactsDir: string; + downloadsPath: string, + tracesDir: string, headful?: boolean, persistent?: types.BrowserContextOptions, // Undefined means no persistent context. browserProcess: BrowserProcess, diff --git a/src/server/browserType.ts b/src/server/browserType.ts index f44f95b971..d7bea10229 100644 --- a/src/server/browserType.ts +++ b/src/server/browserType.ts @@ -36,7 +36,7 @@ import { CallMetadata, SdkObject } from './instrumentation'; const mkdirAsync = util.promisify(fs.mkdir); const mkdtempAsync = util.promisify(fs.mkdtemp); const existsAsync = (path: string): Promise => new Promise(resolve => fs.stat(path, err => resolve(!err))); -const DOWNLOADS_FOLDER = path.join(os.tmpdir(), 'playwright_downloads-'); +const ARTIFACTS_FOLDER = path.join(os.tmpdir(), 'playwright-artifacts-'); export abstract class BrowserType extends SdkObject { private _name: registry.BrowserName; @@ -97,7 +97,7 @@ export abstract class BrowserType extends SdkObject { async _innerLaunch(progress: Progress, options: types.LaunchOptions, persistent: types.BrowserContextOptions | undefined, protocolLogger: types.ProtocolLogger, userDataDir?: string): Promise { options.proxy = options.proxy ? normalizeProxySettings(options.proxy) : undefined; const browserLogsCollector = new RecentLogsCollector(); - const { browserProcess, downloadsPath, transport } = await this._launchProcess(progress, options, !!persistent, browserLogsCollector, userDataDir); + const { browserProcess, artifactsDir, transport } = await this._launchProcess(progress, options, !!persistent, browserLogsCollector, userDataDir); if ((options as any).__testHookBeforeCreateBrowser) await (options as any).__testHookBeforeCreateBrowser(); const browserOptions: BrowserOptions = { @@ -108,14 +108,15 @@ export abstract class BrowserType extends SdkObject { slowMo: options.slowMo, persistent, headful: !options.headless, - downloadsPath, + artifactsDir, + downloadsPath: (options.downloadsPath || artifactsDir)!, + tracesDir: (options.tracesDir || artifactsDir)!, browserProcess, customExecutablePath: options.executablePath, proxy: options.proxy, protocolLogger, browserLogsCollector, wsEndpoint: options.useWebSocket ? (transport as WebSocketTransport).wsEndpoint : undefined, - traceDir: options.traceDir, }; if (persistent) validateBrowserContextOptions(persistent, browserOptions); @@ -127,7 +128,7 @@ export abstract class BrowserType extends SdkObject { return browser; } - private async _launchProcess(progress: Progress, options: types.LaunchOptions, isPersistent: boolean, browserLogsCollector: RecentLogsCollector, userDataDir?: string): Promise<{ browserProcess: BrowserProcess, downloadsPath: string, transport: ConnectionTransport }> { + private async _launchProcess(progress: Progress, options: types.LaunchOptions, isPersistent: boolean, browserLogsCollector: RecentLogsCollector, userDataDir?: string): Promise<{ browserProcess: BrowserProcess, artifactsDir: string, transport: ConnectionTransport }> { const { ignoreDefaultArgs, ignoreAllDefaultArgs, @@ -141,19 +142,13 @@ export abstract class BrowserType extends SdkObject { const env = options.env ? envArrayToObject(options.env) : process.env; const tempDirectories = []; - const ensurePath = async (tmpPrefix: string, pathFromOptions?: string) => { - let dir; - if (pathFromOptions) { - dir = pathFromOptions; - await mkdirAsync(pathFromOptions, { recursive: true }); - } else { - dir = await mkdtempAsync(tmpPrefix); - tempDirectories.push(dir); - } - return dir; - }; - // TODO: add downloadsPath to newContext(). - const downloadsPath = await ensurePath(DOWNLOADS_FOLDER, options.downloadsPath); + if (options.downloadsPath) + await mkdirAsync(options.downloadsPath, { recursive: true }); + if (options.tracesDir) + await mkdirAsync(options.tracesDir, { recursive: true }); + + const artifactsDir = await mkdtempAsync(ARTIFACTS_FOLDER); + tempDirectories.push(artifactsDir); if (!userDataDir) { userDataDir = await mkdtempAsync(path.join(os.tmpdir(), `playwright_${this._name}dev_profile-`)); @@ -252,7 +247,7 @@ export abstract class BrowserType extends SdkObject { const stdio = launchedProcess.stdio as unknown as [NodeJS.ReadableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.WritableStream, NodeJS.ReadableStream]; transport = new PipeTransport(stdio[3], stdio[4]); } - return { browserProcess, downloadsPath, transport }; + return { browserProcess, artifactsDir, transport }; } async connectOverCDP(metadata: CallMetadata, endpointURL: string, options: { slowMo?: number, sdkLanguage: string }, timeout?: number): Promise { diff --git a/src/server/chromium/chromium.ts b/src/server/chromium/chromium.ts index 929b0b422f..815c6c1c8e 100644 --- a/src/server/chromium/chromium.ts +++ b/src/server/chromium/chromium.ts @@ -15,7 +15,10 @@ * limitations under the License. */ +import fs from 'fs'; +import os from 'os'; import path from 'path'; +import util from 'util'; import { CRBrowser } from './crBrowser'; import { Env } from '../processLauncher'; import { kBrowserCloseMessageId } from './crConnection'; @@ -25,7 +28,7 @@ import { ConnectionTransport, ProtocolRequest, WebSocketTransport } from '../tra import { CRDevTools } from './crDevTools'; import { BrowserOptions, BrowserProcess, PlaywrightOptions } from '../browser'; import * as types from '../types'; -import { debugMode, headersArrayToObject } from '../../utils/utils'; +import { debugMode, headersArrayToObject, removeFolders } from '../../utils/utils'; import { RecentLogsCollector } from '../../utils/debugLogger'; import { ProgressController } from '../progress'; import { TimeoutSettings } from '../../utils/timeoutSettings'; @@ -34,6 +37,9 @@ import { CallMetadata } from '../instrumentation'; import { findChromiumChannel } from './findChromiumChannel'; import http from 'http'; +const mkdtempAsync = util.promisify(fs.mkdtemp); +const ARTIFACTS_FOLDER = path.join(os.tmpdir(), 'playwright-artifacts-'); + export class Chromium extends BrowserType { private _devtools: CRDevTools | undefined; @@ -58,12 +64,17 @@ export class Chromium extends BrowserType { let headersMap: { [key: string]: string; } | undefined; if (options.headers) headersMap = headersArrayToObject(options.headers, false); + + const artifactsDir = await mkdtempAsync(ARTIFACTS_FOLDER); + const chromeTransport = await WebSocketTransport.connect(progress, await urlToWSEndpoint(endpointURL), headersMap); const browserProcess: BrowserProcess = { close: async () => { + await removeFolders([ artifactsDir ]); await chromeTransport.closeAndWait(); }, kill: async () => { + await removeFolders([ artifactsDir ]); await chromeTransport.closeAndWait(); } }; @@ -76,6 +87,9 @@ export class Chromium extends BrowserType { browserProcess, protocolLogger: helper.debugProtocolLogger(), browserLogsCollector, + artifactsDir, + downloadsPath: artifactsDir, + tracesDir: artifactsDir }; return await CRBrowser.connect(chromeTransport, browserOptions); }, TimeoutSettings.timeout({timeout})); diff --git a/src/server/chromium/crBrowser.ts b/src/server/chromium/crBrowser.ts index 3748f5f7c1..b4accdc4ad 100644 --- a/src/server/chromium/crBrowser.ts +++ b/src/server/chromium/crBrowser.ts @@ -279,7 +279,7 @@ export class CRBrowserContext extends BrowserContext { async _initialize() { assert(!Array.from(this._browser._crPages.values()).some(page => page._browserContext === this)); const promises: Promise[] = [ super._initialize() ]; - if (this._browser.options.downloadsPath) { + if (this._browser.options.name !== 'electron') { promises.push(this._browser._session.send('Browser.setDownloadBehavior', { behavior: this._options.acceptDownloads ? 'allowAndName' : 'deny', browserContextId: this._browserContextId, diff --git a/src/server/electron/electron.ts b/src/server/electron/electron.ts index 5295fe483f..547104516c 100644 --- a/src/server/electron/electron.ts +++ b/src/server/electron/electron.ts @@ -14,7 +14,10 @@ * limitations under the License. */ -import * as os from 'os'; +import fs from 'fs'; +import os from 'os'; +import path from 'path'; +import util from 'util'; import { CRBrowser, CRBrowserContext } from '../chromium/crBrowser'; import { CRConnection, CRSession } from '../chromium/crConnection'; import { CRExecutionContext } from '../chromium/crExecutionContext'; @@ -34,6 +37,9 @@ import { RecentLogsCollector } from '../../utils/debugLogger'; import { internalCallMetadata, SdkObject } from '../instrumentation'; import * as channels from '../../protocol/channels'; +const mkdtempAsync = util.promisify(fs.mkdtemp); +const ARTIFACTS_FOLDER = path.join(os.tmpdir(), 'playwright-artifacts-'); + export class ElectronApplication extends SdkObject { static Events = { Close: 'close', @@ -119,6 +125,8 @@ export class Electron extends SdkObject { electronArguments.push('--no-sandbox'); } + const artifactsDir = await mkdtempAsync(ARTIFACTS_FOLDER); + const browserLogsCollector = new RecentLogsCollector(); const { launchedProcess, gracefullyClose, kill } = await launchProcess({ executablePath: options.executablePath || require('electron/index.js'), @@ -130,7 +138,7 @@ export class Electron extends SdkObject { }, stdio: 'pipe', cwd: options.cwd, - tempDirectories: [], + tempDirectories: [ artifactsDir ], attemptToGracefullyClose: () => app!.close(), handleSIGINT: true, handleSIGTERM: true, @@ -174,6 +182,9 @@ export class Electron extends SdkObject { browserProcess, protocolLogger: helper.debugProtocolLogger(), browserLogsCollector, + artifactsDir, + downloadsPath: artifactsDir, + tracesDir: artifactsDir, }; const browser = await CRBrowser.connect(chromeTransport, browserOptions); app = new ElectronApplication(this, browser, nodeConnection); diff --git a/src/server/firefox/ffBrowser.ts b/src/server/firefox/ffBrowser.ts index 1fb6f87fee..179acc4f1b 100644 --- a/src/server/firefox/ffBrowser.ts +++ b/src/server/firefox/ffBrowser.ts @@ -158,15 +158,13 @@ export class FFBrowserContext extends BrowserContext { assert(!this._ffPages().length); const browserContextId = this._browserContextId; const promises: Promise[] = [ super._initialize() ]; - if (this._browser.options.downloadsPath) { - promises.push(this._browser._connection.send('Browser.setDownloadOptions', { - browserContextId, - downloadOptions: { - behavior: this._options.acceptDownloads ? 'saveToDisk' : 'cancel', - downloadsDir: this._browser.options.downloadsPath, - }, - })); - } + promises.push(this._browser._connection.send('Browser.setDownloadOptions', { + browserContextId, + downloadOptions: { + behavior: this._options.acceptDownloads ? 'saveToDisk' : 'cancel', + downloadsDir: this._browser.options.downloadsPath, + }, + })); if (this._options.viewport) { const viewport = { viewportSize: { width: this._options.viewport.width, height: this._options.viewport.height }, diff --git a/src/server/trace/recorder/traceSnapshotter.ts b/src/server/trace/recorder/traceSnapshotter.ts index d0e723e248..1f232f3b1d 100644 --- a/src/server/trace/recorder/traceSnapshotter.ts +++ b/src/server/trace/recorder/traceSnapshotter.ts @@ -49,6 +49,10 @@ export class TraceSnapshotter extends EventEmitter implements SnapshotterDelegat await this._snapshotter.start(); } + async stop(): Promise { + await this._snapshotter.stop(); + } + async dispose() { this._snapshotter.dispose(); await this._writeArtifactChain; diff --git a/src/server/trace/recorder/tracing.ts b/src/server/trace/recorder/tracing.ts index 4a8679ddff..b896ca9a96 100644 --- a/src/server/trace/recorder/tracing.ts +++ b/src/server/trace/recorder/tracing.ts @@ -48,23 +48,23 @@ export class Tracing implements InstrumentationListener { private _resourcesDir: string; private _sha1s: string[] = []; private _started = false; - private _traceDir: string | undefined; + private _tracesDir: string | undefined; constructor(context: BrowserContext) { this._context = context; - this._traceDir = context._browser.options.traceDir; - this._resourcesDir = path.join(this._traceDir || '', 'resources'); + this._tracesDir = context._browser.options.tracesDir; + this._resourcesDir = path.join(this._tracesDir, 'resources'); this._snapshotter = new TraceSnapshotter(this._context, this._resourcesDir, traceEvent => this._appendTraceEvent(traceEvent)); } async start(options: TracerOptions): Promise { // context + page must be the first events added, this method can't have awaits before them. - if (!this._traceDir) + if (!this._tracesDir) throw new Error('Tracing directory is not specified when launching the browser'); if (this._started) throw new Error('Tracing has already been started'); this._started = true; - this._traceFile = path.join(this._traceDir, (options.name || createGuid()) + '.trace'); + this._traceFile = path.join(this._tracesDir, (options.name || createGuid()) + '.trace'); this._appendEventChain = mkdirIfNeeded(this._traceFile); const event: trace.ContextCreatedTraceEvent = { @@ -91,6 +91,7 @@ export class Tracing implements InstrumentationListener { if (!this._started) return; this._started = false; + await this._snapshotter.stop(); this._context.instrumentation.removeListener(this); helper.removeEventListeners(this._eventListeners); for (const { sdkObject, metadata } of this._pendingCalls.values()) diff --git a/src/server/trace/viewer/traceViewer.ts b/src/server/trace/viewer/traceViewer.ts index 8408dcd5aa..8445f8182d 100644 --- a/src/server/trace/viewer/traceViewer.ts +++ b/src/server/trace/viewer/traceViewer.ts @@ -33,9 +33,9 @@ export class TraceViewer { private _server: HttpServer; private _browserName: string; - constructor(traceDir: string, browserName: string) { + constructor(tracesDir: string, browserName: string) { this._browserName = browserName; - const resourcesDir = path.join(traceDir, 'resources'); + const resourcesDir = path.join(tracesDir, 'resources'); // Served by TraceServer // - "/tracemodel" - json with trace model. @@ -51,9 +51,9 @@ export class TraceViewer { // - "/snapshot/pageId/..." - actual snapshot html. // - "/snapshot/service-worker.js" - service worker that intercepts snapshot resources // and translates them into "/resources/". - const actionTraces = fs.readdirSync(traceDir).filter(name => name.endsWith('.trace')); + const actionTraces = fs.readdirSync(tracesDir).filter(name => name.endsWith('.trace')); const debugNames = actionTraces.map(name => { - const tracePrefix = path.join(traceDir, name.substring(0, name.indexOf('.trace'))); + const tracePrefix = path.join(tracesDir, name.substring(0, name.indexOf('.trace'))); return path.basename(tracePrefix); }); @@ -71,7 +71,7 @@ export class TraceViewer { const traceModelHandler: ServerRouteHandler = (request, response) => { const debugName = request.url!.substring('/context/'.length); - const tracePrefix = path.join(traceDir, debugName); + const tracePrefix = path.join(tracesDir, debugName); snapshotStorage.clear(); response.statusCode = 200; response.setHeader('Content-Type', 'application/json'); diff --git a/src/server/types.ts b/src/server/types.ts index 39cdaa2158..24e04d2e7e 100644 --- a/src/server/types.ts +++ b/src/server/types.ts @@ -274,7 +274,7 @@ type LaunchOptionsBase = { chromiumSandbox?: boolean, slowMo?: number, useWebSocket?: boolean, - traceDir?: string, + tracesDir?: string, }; export type LaunchOptions = LaunchOptionsBase & { firefoxUserPrefs?: { [key: string]: string | number | boolean }, diff --git a/src/server/webkit/wkBrowser.ts b/src/server/webkit/wkBrowser.ts index 429d24d2f8..58ae10f471 100644 --- a/src/server/webkit/wkBrowser.ts +++ b/src/server/webkit/wkBrowser.ts @@ -213,13 +213,11 @@ export class WKBrowserContext extends BrowserContext { assert(!this._wkPages().length); const browserContextId = this._browserContextId; const promises: Promise[] = [ super._initialize() ]; - if (this._browser.options.downloadsPath) { - promises.push(this._browser._browserSession.send('Playwright.setDownloadBehavior', { - behavior: this._options.acceptDownloads ? 'allow' : 'deny', - downloadPath: this._browser.options.downloadsPath, - browserContextId - })); - } + promises.push(this._browser._browserSession.send('Playwright.setDownloadBehavior', { + behavior: this._options.acceptDownloads ? 'allow' : 'deny', + downloadPath: this._browser.options.downloadsPath, + browserContextId + })); if (this._options.ignoreHTTPSErrors) promises.push(this._browser._browserSession.send('Playwright.setIgnoreCertificateErrors', { browserContextId, ignore: true })); if (this._options.locale) diff --git a/tests/config/browserTest.ts b/tests/config/browserTest.ts index 080bd7fc94..76979827d1 100644 --- a/tests/config/browserTest.ts +++ b/tests/config/browserTest.ts @@ -27,7 +27,7 @@ import { baseTest, CommonWorkerFixtures } from './baseTest'; const mkdtempAsync = util.promisify(fs.mkdtemp); type PlaywrightWorkerOptions = { - traceDir: LaunchOptions['traceDir']; + tracesDir: LaunchOptions['tracesDir']; executablePath: LaunchOptions['executablePath']; proxy: LaunchOptions['proxy']; args: LaunchOptions['args']; @@ -53,7 +53,7 @@ type PlaywrightTestFixtures = { export type PlaywrightOptions = PlaywrightWorkerOptions & PlaywrightTestOptions; export const playwrightFixtures: folio.Fixtures = { - traceDir: [ undefined, { scope: 'worker' } ], + tracesDir: [ undefined, { scope: 'worker' } ], executablePath: [ undefined, { scope: 'worker' } ], proxy: [ undefined, { scope: 'worker' } ], args: [ undefined, { scope: 'worker' } ], @@ -63,12 +63,12 @@ export const playwrightFixtures: folio.Fixtures { + browserOptions: [async ({ headless, channel, executablePath, tracesDir, proxy, args }, run) => { await run({ headless, channel, executablePath, - traceDir, + tracesDir, proxy, args, handleSIGINT: false, diff --git a/tests/config/default.config.ts b/tests/config/default.config.ts index d711068dff..d50fa64c08 100644 --- a/tests/config/default.config.ts +++ b/tests/config/default.config.ts @@ -78,7 +78,7 @@ for (const browserName of browserNames) { channel, video, executablePath, - traceDir: process.env.PWTRACE ? path.join(outputDir, 'trace') : undefined, + tracesDir: process.env.PWTRACE ? path.join(outputDir, 'trace') : undefined, coverageName: browserName, }, define: { test: pageTest, fixtures: pageFixtures }, diff --git a/tests/config/remoteServer.ts b/tests/config/remoteServer.ts index 1523f1f6b8..a7f02262b6 100644 --- a/tests/config/remoteServer.ts +++ b/tests/config/remoteServer.ts @@ -50,7 +50,7 @@ export class RemoteServer { args: browserOptions.args, headless: browserOptions.headless, channel: browserOptions.channel, - traceDir: browserOptions.traceDir, + tracesDir: browserOptions.tracesDir, handleSIGINT: true, handleSIGTERM: true, handleSIGHUP: true, diff --git a/tests/tracing.spec.ts b/tests/tracing.spec.ts index 346c48309a..6347972d1e 100644 --- a/tests/tracing.spec.ts +++ b/tests/tracing.spec.ts @@ -14,20 +14,10 @@ * limitations under the License. */ -import path from 'path'; import { expect, contextTest as test, browserTest } from './config/browserTest'; import yauzl from 'yauzl'; -import removeFolder from 'rimraf'; import jpeg from 'jpeg-js'; -const traceDir = path.join(__dirname, '..', 'test-results', 'trace-' + process.env.FOLIO_WORKER_INDEX); -test.use({ traceDir }); - -test.beforeEach(async ({ browserName, headless }) => { - test.fixme(browserName === 'chromium' && !headless, 'Chromium screencast on headed has a min width issue'); - await new Promise(f => removeFolder(traceDir, f)); -}); - test('should collect trace', async ({ context, page, server, browserName }, testInfo) => { await context.tracing.start({ name: 'test', screenshots: true, snapshots: true }); await page.goto(server.EMPTY_PAGE); diff --git a/types/types.d.ts b/types/types.d.ts index 6bc6c0cab1..a28a7e1c49 100644 --- a/types/types.d.ts +++ b/types/types.d.ts @@ -7235,7 +7235,7 @@ export interface BrowserType { /** * If specified, traces are saved into this directory. */ - traceDir?: string; + tracesDir?: string; /** * Specific user agent to use in this context. @@ -7424,7 +7424,7 @@ export interface BrowserType { /** * If specified, traces are saved into this directory. */ - traceDir?: string; + tracesDir?: string; }): Promise; /** @@ -10604,9 +10604,9 @@ export interface Touchscreen { * Start with specifying the folder traces will be stored in: * * ```js - * const browser = await chromium.launch({ traceDir: 'traces' }); + * const browser = await chromium.launch(); * const context = await browser.newContext(); - * await context.tracing.start({ name: 'trace', screenshots: true, snapshots: true }); + * await context.tracing.start({ screenshots: true, snapshots: true }); * const page = await context.newPage(); * await page.goto('https://playwright.dev'); * await context.tracing.stop({ path: 'trace.zip' }); @@ -10618,19 +10618,18 @@ export interface Tracing { * Start tracing. * * ```js - * await context.tracing.start({ name: 'trace', screenshots: true, snapshots: true }); + * await context.tracing.start({ screenshots: true, snapshots: true }); * const page = await context.newPage(); * await page.goto('https://playwright.dev'); - * await context.tracing.stop(); - * await context.tracing.export('trace.zip'); + * await context.tracing.stop({ path: 'trace.zip' }); * ``` * * @param options */ start(options?: { /** - * If specified, the trace is going to be saved into the file with the given name inside the `traceDir` folder specified in - * [browserType.launch([options])](https://playwright.dev/docs/api/class-browsertype#browsertypelaunchoptions). + * If specified, the trace is going to be saved into the file with the given name inside the `tracesDir` folder specified + * in [browserType.launch([options])](https://playwright.dev/docs/api/class-browsertype#browsertypelaunchoptions). */ name?: string; @@ -11343,7 +11342,7 @@ export interface LaunchOptions { /** * If specified, traces are saved into this directory. */ - traceDir?: string; + tracesDir?: string; } export interface ConnectOverCDPOptions {