diff --git a/docs/api.md b/docs/api.md index 3102b7079020a..17445a31548e7 100644 --- a/docs/api.md +++ b/docs/api.md @@ -220,12 +220,10 @@ Indicates that the browser is connected. - `password` <[string]> - `colorScheme` <"light"|"dark"|"no-preference"> Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See [page.emulateMedia(options)](#pageemulatemediaoptions) for more details. Defaults to '`light`'. - `logger` <[Logger]> Logger sink for Playwright logging. - - `relativeArtifactsPath` <[string]> Specifies a folder for artifacts like downloads, videos and traces, relative to `artifactsPath` from [`browserType.launch`](#browsertypelaunchoptions). Defaults to `.`. - - `recordVideos` <[boolean]> Enables video recording for all pages to the `relativeArtifactsPath` folder. - - `videoSize` <[Object]> Specifies dimensions of the automatically recorded video. Can only be used if `recordVideos` is true. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of the page will be scaled down if necessary to fit specified size. + - `videosPath` <[string]> Enables video recording for all pages to `videosPath` folder. If not specified, videos are not recorded. + - `videoSize` <[Object]> Specifies dimensions of the automatically recorded video. Can only be used if `videosPath` is set. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of the page will be scaled down if necessary to fit specified size. - `width` <[number]> Video frame width. - `height` <[number]> Video frame height. - - `recordTrace` <[boolean]> Enables trace recording to the `relativeArtifactsPath` folder. - returns: <[Promise]<[BrowserContext]>> Creates a new browser context. It won't share cookies/cache with other browser contexts. @@ -268,12 +266,10 @@ Creates a new browser context. It won't share cookies/cache with other browser c - `password` <[string]> - `colorScheme` <"light"|"dark"|"no-preference"> Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See [page.emulateMedia(options)](#pageemulatemediaoptions) for more details. Defaults to '`light`'. - `logger` <[Logger]> Logger sink for Playwright logging. - - `relativeArtifactsPath` <[string]> Specifies a folder for artifacts like downloads, videos and traces, relative to `artifactsPath` from [`browserType.launch`](#browsertypelaunchoptions). Defaults to `.`. - - `recordVideos` <[boolean]> Enables video recording for all pages to the `relativeArtifactsPath` folder. - - `videoSize` <[Object]> Specifies dimensions of the automatically recorded video. Can only be used if `recordVideos` is true. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of the page will be scaled down if necessary to fit specified size. + - `videosPath` <[string]> Enables video recording for all pages to `videosPath` folder. If not specified, videos are not recorded. + - `videoSize` <[Object]> Specifies dimensions of the automatically recorded video. Can only be used if `videosPath` is set. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of the page will be scaled down if necessary to fit specified size. - `width` <[number]> Video frame width. - `height` <[number]> Video frame height. - - `recordTrace` <[boolean]> Enables trace recording to the `relativeArtifactsPath` folder. - returns: <[Promise]<[Page]>> Creates a new page in a new browser context. Closing this page will close the context as well. @@ -4174,7 +4170,6 @@ This methods attaches Playwright to an existing browser instance. - `username` <[string]> Optional username to use if HTTP proxy requires authentication. - `password` <[string]> Optional password to use if HTTP proxy requires authentication. - `downloadsPath` <[string]> If specified, accepted downloads are downloaded into this folder. Otherwise, temporary folder is created and is deleted when browser is closed. - - `artifactsPath` <[string]> Specifies a folder for various artifacts like downloads, videos and traces. If not specified, artifacts are not collected. - `chromiumSandbox` <[boolean]> Enable Chromium sandboxing. Defaults to `true`. - `firefoxUserPrefs` <[Object]<[string], [string]|[number]|[boolean]>> Firefox user preferences. Learn more about the Firefox user preferences at [`about:config`](https://support.mozilla.org/en-US/kb/about-config-editor-firefox). - `handleSIGINT` <[boolean]> Close the browser process on Ctrl-C. Defaults to `true`. @@ -4217,7 +4212,6 @@ const browser = await chromium.launch({ // Or 'firefox' or 'webkit'. - `password` <[string]> Optional password to use if HTTP proxy requires authentication. - `acceptDownloads` <[boolean]> Whether to automatically download all the attachments. Defaults to `false` where all the downloads are canceled. - `downloadsPath` <[string]> If specified, accepted downloads are downloaded into this folder. Otherwise, temporary folder is created and is deleted when browser is closed. - - `artifactsPath` <[string]> Specifies a folder for various artifacts like downloads, videos and traces. If not specified, artifacts are not collected. - `chromiumSandbox` <[boolean]> Enable Chromium sandboxing. Defaults to `true`. - `handleSIGINT` <[boolean]> Close the browser process on Ctrl-C. Defaults to `true`. - `handleSIGTERM` <[boolean]> Close the browser process on SIGTERM. Defaults to `true`. @@ -4250,12 +4244,10 @@ const browser = await chromium.launch({ // Or 'firefox' or 'webkit'. - `username` <[string]> - `password` <[string]> - `colorScheme` <"light"|"dark"|"no-preference"> Emulates `'prefers-colors-scheme'` media feature, supported values are `'light'`, `'dark'`, `'no-preference'`. See [page.emulateMedia(options)](#pageemulatemediaoptions) for more details. Defaults to '`light`'. - - `relativeArtifactsPath` <[string]> Specifies a folder for artifacts like downloads, videos and traces, relative to `artifactsPath`. Defaults to `.`. - - `recordVideos` <[boolean]> Enables video recording for all pages to the `relativeArtifactsPath` folder. - - `videoSize` <[Object]> Specifies dimensions of the automatically recorded video. Can only be used if `recordVideos` is true. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of the page will be scaled down if necessary to fit specified size. + - `videosPath` <[string]> Enables video recording for all pages to `videosPath` folder. If not specified, videos are not recorded. + - `videoSize` <[Object]> Specifies dimensions of the automatically recorded video. Can only be used if `videosPath` is set. If not specified the size will be equal to `viewport`. If `viewport` is not configured explicitly the video size defaults to 1280x720. Actual picture of the page will be scaled down if necessary to fit specified size. - `width` <[number]> Video frame width. - `height` <[number]> Video frame height. - - `recordTrace` <[boolean]> Enables trace recording to the `relativeArtifactsPath` folder. - returns: <[Promise]<[BrowserContext]>> Promise that resolves to the persistent browser context instance. Launches browser that uses persistent storage located at `userDataDir` and returns the only context. Closing this context will automatically close the browser. @@ -4273,7 +4265,6 @@ Launches browser that uses persistent storage located at `userDataDir` and retur - `username` <[string]> Optional username to use if HTTP proxy requires authentication. - `password` <[string]> Optional password to use if HTTP proxy requires authentication. - `downloadsPath` <[string]> If specified, accepted downloads are downloaded into this folder. Otherwise, temporary folder is created and is deleted when browser is closed. - - `artifactsPath` <[string]> Specifies a folder for various artifacts like downloads, videos and traces. If not specified, artifacts are not collected. - `chromiumSandbox` <[boolean]> Enable Chromium sandboxing. Defaults to `true`. - `firefoxUserPrefs` <[Object]<[string], [string]|[number]|[boolean]>> Firefox user preferences. Learn more about the Firefox user preferences at [`about:config`](https://support.mozilla.org/en-US/kb/about-config-editor-firefox). - `handleSIGINT` <[boolean]> Close the browser process on Ctrl-C. Defaults to `true`. diff --git a/packages/installation-tests/screencast.js b/packages/installation-tests/screencast.js index fe3522710e195..ef99798d0bd6c 100644 --- a/packages/installation-tests/screencast.js +++ b/packages/installation-tests/screencast.js @@ -27,17 +27,14 @@ if (process.argv[3] === 'all') success = ['chromium', 'firefox', 'webkit']; const playwright = require(requireName); -const path = require('path'); const fs = require('fs'); (async () => { for (const browserType of success) { try { - const browser = await playwright[browserType].launch({ - artifactsPath: __dirname, - }); + const browser = await playwright[browserType].launch({}); const context = await browser.newContext({ - recordVideos: true, + videosPath: __dirname, videoSize: {width: 320, height: 240}, }); await context.newPage(); diff --git a/src/client/browser.ts b/src/client/browser.ts index 26ee39c04107f..53b0f05865afe 100644 --- a/src/client/browser.ts +++ b/src/client/browser.ts @@ -47,6 +47,10 @@ export class Browser extends ChannelOwner { const logger = options.logger; return this._wrapApiCall('browser.newContext', async () => { + if (this._isRemote && options.videosPath) + throw new Error(`"videosPath" is not supported in connected browser`); + if (this._isRemote && options._tracePath) + throw new Error(`"_tracePath" is not supported in connected browser`); if (options.extraHTTPHeaders) validateHeaders(options.extraHTTPHeaders); const contextOptions: channels.BrowserNewContextParams = { diff --git a/src/client/types.ts b/src/client/types.ts index 5559c358d35d5..9891da5ef54a2 100644 --- a/src/client/types.ts +++ b/src/client/types.ts @@ -82,7 +82,6 @@ export type LaunchServerOptions = { password?: string }, downloadsPath?: string, - artifactsPath?: string, chromiumSandbox?: boolean, port?: number, logger?: Logger, diff --git a/src/protocol/channels.ts b/src/protocol/channels.ts index 2a006b0e5955c..979a33a842685 100644 --- a/src/protocol/channels.ts +++ b/src/protocol/channels.ts @@ -168,7 +168,6 @@ export type BrowserTypeLaunchParams = { password?: string, }, downloadsPath?: string, - artifactsPath?: string, firefoxUserPrefs?: any, chromiumSandbox?: boolean, slowMo?: number, @@ -195,7 +194,6 @@ export type BrowserTypeLaunchOptions = { password?: string, }, downloadsPath?: string, - artifactsPath?: string, firefoxUserPrefs?: any, chromiumSandbox?: boolean, slowMo?: number, @@ -226,7 +224,6 @@ export type BrowserTypeLaunchPersistentContextParams = { password?: string, }, downloadsPath?: string, - artifactsPath?: string, chromiumSandbox?: boolean, slowMo?: number, noDefaultViewport?: boolean, @@ -260,8 +257,13 @@ export type BrowserTypeLaunchPersistentContextParams = { hasTouch?: boolean, colorScheme?: 'light' | 'dark' | 'no-preference', acceptDownloads?: boolean, - relativeArtifactsPath?: string, - recordTrace?: boolean, + _traceResourcesPath?: string, + _tracePath?: string, + videosPath?: string, + videoSize?: { + width: number, + height: number, + }, }; export type BrowserTypeLaunchPersistentContextOptions = { executablePath?: string, @@ -285,7 +287,6 @@ export type BrowserTypeLaunchPersistentContextOptions = { password?: string, }, downloadsPath?: string, - artifactsPath?: string, chromiumSandbox?: boolean, slowMo?: number, noDefaultViewport?: boolean, @@ -319,8 +320,13 @@ export type BrowserTypeLaunchPersistentContextOptions = { hasTouch?: boolean, colorScheme?: 'light' | 'dark' | 'no-preference', acceptDownloads?: boolean, - relativeArtifactsPath?: string, - recordTrace?: boolean, + _traceResourcesPath?: string, + _tracePath?: string, + videosPath?: string, + videoSize?: { + width: number, + height: number, + }, }; export type BrowserTypeLaunchPersistentContextResult = { context: BrowserContextChannel, @@ -375,9 +381,9 @@ export type BrowserNewContextParams = { hasTouch?: boolean, colorScheme?: 'dark' | 'light' | 'no-preference', acceptDownloads?: boolean, - relativeArtifactsPath?: string, - recordTrace?: boolean, - recordVideos?: boolean, + _traceResourcesPath?: string, + _tracePath?: string, + videosPath?: string, videoSize?: { width: number, height: number, @@ -415,9 +421,9 @@ export type BrowserNewContextOptions = { hasTouch?: boolean, colorScheme?: 'dark' | 'light' | 'no-preference', acceptDownloads?: boolean, - relativeArtifactsPath?: string, - recordTrace?: boolean, - recordVideos?: boolean, + _traceResourcesPath?: string, + _tracePath?: string, + videosPath?: string, videoSize?: { width: number, height: number, diff --git a/src/protocol/protocol.yml b/src/protocol/protocol.yml index a221d95e0b32c..a2eaef2e1454a 100644 --- a/src/protocol/protocol.yml +++ b/src/protocol/protocol.yml @@ -220,7 +220,6 @@ BrowserType: username: string? password: string? downloadsPath: string? - artifactsPath: string? firefoxUserPrefs: json? chromiumSandbox: boolean? slowMo: number? @@ -259,7 +258,6 @@ BrowserType: username: string? password: string? downloadsPath: string? - artifactsPath: string? chromiumSandbox: boolean? slowMo: number? noDefaultViewport: boolean? @@ -306,8 +304,14 @@ BrowserType: - dark - no-preference acceptDownloads: boolean? - relativeArtifactsPath: string? - recordTrace: boolean? + _traceResourcesPath: string? + _tracePath: string? + videosPath: string? + videoSize: + type: object? + properties: + width: number + height: number returns: context: BrowserContext @@ -369,9 +373,9 @@ Browser: - light - no-preference acceptDownloads: boolean? - relativeArtifactsPath: string? - recordTrace: boolean? - recordVideos: boolean? + _traceResourcesPath: string? + _tracePath: string? + videosPath: string? videoSize: type: object? properties: diff --git a/src/protocol/validator.ts b/src/protocol/validator.ts index 53a8ee21f0b24..7b58002ca8534 100644 --- a/src/protocol/validator.ts +++ b/src/protocol/validator.ts @@ -121,7 +121,6 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { password: tOptional(tString), })), downloadsPath: tOptional(tString), - artifactsPath: tOptional(tString), firefoxUserPrefs: tOptional(tAny), chromiumSandbox: tOptional(tBoolean), slowMo: tOptional(tNumber), @@ -149,7 +148,6 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { password: tOptional(tString), })), downloadsPath: tOptional(tString), - artifactsPath: tOptional(tString), chromiumSandbox: tOptional(tBoolean), slowMo: tOptional(tNumber), noDefaultViewport: tOptional(tBoolean), @@ -183,8 +181,13 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { hasTouch: tOptional(tBoolean), colorScheme: tOptional(tEnum(['light', 'dark', 'no-preference'])), acceptDownloads: tOptional(tBoolean), - relativeArtifactsPath: tOptional(tString), - recordTrace: tOptional(tBoolean), + _traceResourcesPath: tOptional(tString), + _tracePath: tOptional(tString), + videosPath: tOptional(tString), + videoSize: tOptional(tObject({ + width: tNumber, + height: tNumber, + })), }); scheme.BrowserCloseParams = tOptional(tObject({})); scheme.BrowserNewContextParams = tObject({ @@ -219,9 +222,9 @@ export function createScheme(tChannel: (name: string) => Validator): Scheme { hasTouch: tOptional(tBoolean), colorScheme: tOptional(tEnum(['dark', 'light', 'no-preference'])), acceptDownloads: tOptional(tBoolean), - relativeArtifactsPath: tOptional(tString), - recordTrace: tOptional(tBoolean), - recordVideos: tOptional(tBoolean), + _traceResourcesPath: tOptional(tString), + _tracePath: tOptional(tString), + videosPath: tOptional(tString), videoSize: tOptional(tObject({ width: tNumber, height: tNumber, diff --git a/src/server/browser.ts b/src/server/browser.ts index ab1bd92ee0d6b..b6f53ecfdbdb7 100644 --- a/src/server/browser.ts +++ b/src/server/browser.ts @@ -31,7 +31,6 @@ export interface BrowserProcess { export type BrowserOptions = types.UIOptions & { name: string, - artifactsPath?: string, downloadsPath?: string, headful?: boolean, persistent?: types.BrowserContextOptions, // Undefined means no persistent context. diff --git a/src/server/browserContext.ts b/src/server/browserContext.ts index 455c53b25094f..732603134a691 100644 --- a/src/server/browserContext.ts +++ b/src/server/browserContext.ts @@ -94,7 +94,6 @@ export abstract class BrowserContext extends EventEmitter { readonly _browserContextId: string | undefined; private _selectors?: Selectors; readonly _actionListeners = new Set(); - readonly _artifactsPath?: string; constructor(browser: Browser, options: types.BrowserContextOptions, browserContextId: string | undefined) { super(); @@ -102,11 +101,6 @@ export abstract class BrowserContext extends EventEmitter { this._options = options; this._browserContextId = browserContextId; this._isPersistentContext = !browserContextId; - if (browser._options.artifactsPath) { - this._artifactsPath = browser._options.artifactsPath; - if (options.relativeArtifactsPath) - this._artifactsPath = path.join(this._artifactsPath, options.relativeArtifactsPath); - } this._closePromise = new Promise(fulfill => this._closePromiseFulfill = fulfill); } @@ -123,9 +117,9 @@ export abstract class BrowserContext extends EventEmitter { await listener.onContextCreated(this); } - async _ensureArtifactsPath() { - if (this._artifactsPath) - await mkdirIfNeeded(path.join(this._artifactsPath, 'dummy')); + async _ensureVideosPath() { + if (this._options.videosPath) + await mkdirIfNeeded(path.join(this._options.videosPath, 'dummy')); } _browserClosed() { @@ -299,10 +293,8 @@ export function validateBrowserContextOptions(options: types.BrowserContextOptio if (!options.viewport && !options.noDefaultViewport) options.viewport = { width: 1280, height: 720 }; verifyGeolocation(options.geolocation); - if (options.recordTrace && !browserOptions.artifactsPath) - throw new Error(`"recordTrace" option requires "artifactsPath" to be specified`); - if (options.recordVideos && !browserOptions.artifactsPath) - throw new Error(`"recordVideos" option requires "artifactsPath" to be specified`); + if (options.videoSize && !options.videosPath) + throw new Error(`"videoSize" option requires "videosPath" to be specified`); } export function verifyGeolocation(geolocation?: types.Geolocation) { diff --git a/src/server/browserType.ts b/src/server/browserType.ts index 7aaf61de97992..d5caba695aeba 100644 --- a/src/server/browserType.ts +++ b/src/server/browserType.ts @@ -92,7 +92,6 @@ export abstract class BrowserType { slowMo: options.slowMo, persistent, headful: !options.headless, - artifactsPath: options.artifactsPath, downloadsPath, browserProcess, proxy: options.proxy, @@ -132,7 +131,7 @@ export abstract class BrowserType { } return dir; }; - // TODO: use artifactsPath for downloads. + // TODO: add downloadsPath to newContext(). const downloadsPath = await ensurePath(DOWNLOADS_FOLDER, options.downloadsPath); if (!userDataDir) { diff --git a/src/server/chromium/crPage.ts b/src/server/chromium/crPage.ts index 428b8415ba027..c58ce78c37064 100644 --- a/src/server/chromium/crPage.ts +++ b/src/server/chromium/crPage.ts @@ -458,11 +458,11 @@ class FrameSession { promises.push(this._evaluateOnNewDocument(source)); for (const source of this._crPage._page._evaluateOnNewDocumentSources) promises.push(this._evaluateOnNewDocument(source)); - if (this._isMainFrame() && this._crPage._browserContext._options.recordVideos) { + if (this._isMainFrame() && this._crPage._browserContext._options.videosPath) { const size = this._crPage._browserContext._options.videoSize || this._crPage._browserContext._options.viewport || { width: 1280, height: 720 }; const screencastId = createGuid(); - const outputFile = path.join(this._crPage._browserContext._artifactsPath!, screencastId + '.webm'); - promises.push(this._crPage._browserContext._ensureArtifactsPath().then(() => { + const outputFile = path.join(this._crPage._browserContext._options.videosPath, screencastId + '.webm'); + promises.push(this._crPage._browserContext._ensureVideosPath().then(() => { return this._startScreencast(screencastId, { ...size, outputFile, diff --git a/src/server/firefox/ffBrowser.ts b/src/server/firefox/ffBrowser.ts index 7783f108aa018..fff69d3b8a502 100644 --- a/src/server/firefox/ffBrowser.ts +++ b/src/server/firefox/ffBrowser.ts @@ -229,12 +229,12 @@ export class FFBrowserContext extends BrowserContext { promises.push(this.setOffline(this._options.offline)); if (this._options.colorScheme) promises.push(this._browser._connection.send('Browser.setColorScheme', { browserContextId, colorScheme: this._options.colorScheme })); - if (this._options.recordVideos) { + if (this._options.videosPath) { const size = this._options.videoSize || this._options.viewport || { width: 1280, height: 720 }; - promises.push(this._ensureArtifactsPath().then(() => { + promises.push(this._ensureVideosPath().then(() => { return this._browser._connection.send('Browser.setScreencastOptions', { ...size, - dir: this._artifactsPath!, + dir: this._options.videosPath!, browserContextId: this._browserContextId }); })); diff --git a/src/server/types.ts b/src/server/types.ts index a05cf352dbe02..9cc9681c01764 100644 --- a/src/server/types.ts +++ b/src/server/types.ts @@ -238,10 +238,10 @@ export type BrowserContextOptions = { hasTouch?: boolean, colorScheme?: ColorScheme, acceptDownloads?: boolean, - recordVideos?: boolean, + videosPath?: string, videoSize?: Size, - recordTrace?: boolean, - relativeArtifactsPath?: string, + _tracePath?: string, + _traceResourcesPath?: string, }; export type EnvArray = { name: string, value: string }[]; @@ -259,7 +259,6 @@ type LaunchOptionsBase = { headless?: boolean, devtools?: boolean, proxy?: ProxySettings, - artifactsPath?: string, downloadsPath?: string, chromiumSandbox?: boolean, slowMo?: number, diff --git a/src/server/webkit/wkPage.ts b/src/server/webkit/wkPage.ts index aab0669a4506b..a687384c92b85 100644 --- a/src/server/webkit/wkPage.ts +++ b/src/server/webkit/wkPage.ts @@ -113,10 +113,10 @@ export class WKPage implements PageDelegate { for (const [key, value] of this._browserContext._permissions) this._grantPermissions(key, value); } - if (this._browserContext._options.recordVideos) { + if (this._browserContext._options.videosPath) { const size = this._browserContext._options.videoSize || this._browserContext._options.viewport || { width: 1280, height: 720 }; - const outputFile = path.join(this._browserContext._artifactsPath!, createGuid() + '.webm'); - promises.push(this._browserContext._ensureArtifactsPath().then(() => { + const outputFile = path.join(this._browserContext._options.videosPath, createGuid() + '.webm'); + promises.push(this._browserContext._ensureVideosPath().then(() => { return this.startScreencast({ ...size, outputFile, diff --git a/src/trace/tracer.ts b/src/trace/tracer.ts index 4c2c2e824e7ff..2c951c4220c33 100644 --- a/src/trace/tracer.ts +++ b/src/trace/tracer.ts @@ -40,11 +40,10 @@ class Tracer implements ContextListener { private _contextTracers = new Map(); async onContextCreated(context: BrowserContext): Promise { - if (!context._options.recordTrace) + if (!context._options._tracePath) return; - const traceStorageDir = path.join(context._browser._options.artifactsPath!, 'trace-resources'); - const traceFile = path.join(context._artifactsPath!, 'playwright.trace'); - const contextTracer = new ContextTracer(context, traceStorageDir, traceFile); + const traceStorageDir = context._options._traceResourcesPath || path.join(path.dirname(context._options._tracePath), 'trace-resources'); + const contextTracer = new ContextTracer(context, traceStorageDir, context._options._tracePath); this._contextTracers.set(context, contextTracer); } diff --git a/test/fixtures.ts b/test/fixtures.ts index 1527694564803..b70847e4c80bc 100644 --- a/test/fixtures.ts +++ b/test/fixtures.ts @@ -14,7 +14,6 @@ * limitations under the License. */ -import { config } from '@playwright/test-runner'; import assert from 'assert'; import childProcess from 'child_process'; import fs from 'fs'; @@ -84,7 +83,6 @@ fixtures.overrideWorkerFixture('defaultBrowserOptions', async ({ browserName, he handleSIGINT: false, slowMo, headless: !headful, - artifactsPath: config.outputDir, }); }); diff --git a/test/playwright.fixtures.ts b/test/playwright.fixtures.ts index aff1f585d2524..43e08af6e94aa 100644 --- a/test/playwright.fixtures.ts +++ b/test/playwright.fixtures.ts @@ -16,6 +16,7 @@ import { config, fixtures as baseFixtures } from '@playwright/test-runner'; import type { Browser, BrowserContext, BrowserContextOptions, BrowserType, LaunchOptions, Page } from '../index'; +import * as path from 'path'; // Parameter declarations ------------------------------------------------------ @@ -106,7 +107,6 @@ fixtures.defineWorkerFixture('defaultBrowserOptions', async ({ headful, slowMo } handleSIGINT: false, slowMo, headless: !headful, - artifactsPath: config.outputDir, }); }); @@ -152,13 +152,13 @@ fixtures.defineWorkerFixture('isLinux', async ({platform}, test) => { // Test fixtures definitions --------------------------------------------------- -fixtures.defineTestFixture('defaultContextOptions', async ({ testRelativeArtifactsPath, trace, testInfo }, runTest) => { +fixtures.defineTestFixture('defaultContextOptions', async ({ testOutputPath, trace, testInfo }, runTest) => { if (trace || testInfo.retry) { await runTest({ - relativeArtifactsPath: testRelativeArtifactsPath, - recordTrace: true, - recordVideos: true, - }); + _traceResourcesPath: path.join(config.outputDir, 'trace-resources'), + _tracePath: testOutputPath('playwright.trace'), + videosPath: testOutputPath(''), + } as any); } else { await runTest({}); } diff --git a/test/screencast.spec.ts b/test/screencast.spec.ts index 913b15a55d01f..2d07d172d8fdd 100644 --- a/test/screencast.spec.ts +++ b/test/screencast.spec.ts @@ -143,23 +143,18 @@ function findVideos(videoDir: string) { describe('screencast', suite => { suite.slow(); }, () => { - it('should require artifactsPath', async ({browserType, defaultBrowserOptions}) => { - const browser = await browserType.launch({ - ...defaultBrowserOptions, - artifactsPath: undefined, - }); - const error = await browser.newContext({ recordVideos: true }).catch(e => e); - expect(error.message).toContain('"recordVideos" option requires "artifactsPath" to be specified'); - await browser.close(); + it('videoSize should require videosPath', async ({browser}) => { + const error = await browser.newContext({ videoSize: { width: 100, height: 100 } }).catch(e => e); + expect(error.message).toContain('"videoSize" option requires "videosPath" to be specified'); }); it('should capture static page', (test, { browserName }) => { test.fixme(browserName === 'firefox', 'Always clips to square'); - }, async ({browser, testRelativeArtifactsPath, testOutputPath}) => { + }, async ({browser, testOutputPath}) => { + const videosPath = testOutputPath(''); const size = { width: 320, height: 240 }; const context = await browser.newContext({ - relativeArtifactsPath: testRelativeArtifactsPath, - recordVideos: true, + videosPath, viewport: size, videoSize: size }); @@ -169,7 +164,7 @@ describe('screencast', suite => { await new Promise(r => setTimeout(r, 1000)); await context.close(); - const videoFile = findVideo(testOutputPath('')); + const videoFile = findVideo(videosPath); const videoPlayer = new VideoPlayer(videoFile); const duration = videoPlayer.duration; expect(duration).toBeGreaterThan(0); @@ -187,10 +182,10 @@ describe('screencast', suite => { } }); - it('should capture navigation', async ({browser, server, testRelativeArtifactsPath, testOutputPath}) => { + it('should capture navigation', async ({browser, server, testOutputPath}) => { + const videosPath = testOutputPath(''); const context = await browser.newContext({ - relativeArtifactsPath: testRelativeArtifactsPath, - recordVideos: true, + videosPath, videoSize: { width: 1280, height: 720 } }); const page = await context.newPage(); @@ -201,7 +196,7 @@ describe('screencast', suite => { await new Promise(r => setTimeout(r, 1000)); await context.close(); - const videoFile = findVideo(testOutputPath('')); + const videoFile = findVideo(videosPath); const videoPlayer = new VideoPlayer(videoFile); const duration = videoPlayer.duration; expect(duration).toBeGreaterThan(0); @@ -220,12 +215,12 @@ describe('screencast', suite => { it('should capture css transformation', (test, { browserName, platform, headful }) => { test.fail(browserName === 'webkit' && platform === 'win32', 'Does not work on WebKit Windows'); test.fixme(headful, 'Fails on headful'); - }, async ({browser, server, testRelativeArtifactsPath, testOutputPath}) => { + }, async ({browser, server, testOutputPath}) => { + const videosPath = testOutputPath(''); const size = { width: 320, height: 240 }; // Set viewport equal to screencast frame size to avoid scaling. const context = await browser.newContext({ - relativeArtifactsPath: testRelativeArtifactsPath, - recordVideos: true, + videosPath, videoSize: size, viewport: size, }); @@ -235,7 +230,7 @@ describe('screencast', suite => { await new Promise(r => setTimeout(r, 1000)); await context.close(); - const videoFile = findVideo(testOutputPath('')); + const videoFile = findVideo(videosPath); const videoPlayer = new VideoPlayer(videoFile); const duration = videoPlayer.duration; expect(duration).toBeGreaterThan(0); @@ -246,10 +241,10 @@ describe('screencast', suite => { } }); - it('should work for popups', async ({browser, testRelativeArtifactsPath, testOutputPath, server}) => { + it('should work for popups', async ({browser, testOutputPath, server}) => { + const videosPath = testOutputPath(''); const context = await browser.newContext({ - relativeArtifactsPath: testRelativeArtifactsPath, - recordVideos: true, + videosPath, videoSize: { width: 320, height: 240 } }); @@ -262,16 +257,16 @@ describe('screencast', suite => { await new Promise(r => setTimeout(r, 1000)); await context.close(); - const videoFiles = findVideos(testOutputPath('')); + const videoFiles = findVideos(videosPath); expect(videoFiles.length).toBe(2); }); it('should scale frames down to the requested size ', (test, parameters) => { test.fixme(parameters.headful, 'Fails on headful'); - }, async ({browser, testRelativeArtifactsPath, testOutputPath, server}) => { + }, async ({browser, testOutputPath, server}) => { + const videosPath = testOutputPath(''); const context = await browser.newContext({ - relativeArtifactsPath: testRelativeArtifactsPath, - recordVideos: true, + videosPath, viewport: {width: 640, height: 480}, // Set size to 1/2 of the viewport. videoSize: { width: 320, height: 240 }, @@ -290,7 +285,7 @@ describe('screencast', suite => { await new Promise(r => setTimeout(r, 1000)); await context.close(); - const videoFile = findVideo(testOutputPath('')); + const videoFile = findVideo(videosPath); const videoPlayer = new VideoPlayer(videoFile); const duration = videoPlayer.duration; expect(duration).toBeGreaterThan(0); @@ -313,11 +308,11 @@ describe('screencast', suite => { } }); - it('should use viewport as default size', async ({browser, testRelativeArtifactsPath, testOutputPath}) => { + it('should use viewport as default size', async ({browser, testOutputPath}) => { + const videosPath = testOutputPath(''); const size = {width: 800, height: 600}; const context = await browser.newContext({ - relativeArtifactsPath: testRelativeArtifactsPath, - recordVideos: true, + videosPath, viewport: size, }); @@ -325,25 +320,54 @@ describe('screencast', suite => { await new Promise(r => setTimeout(r, 1000)); await context.close(); - const videoFile = findVideo(testOutputPath('')); + const videoFile = findVideo(videosPath); const videoPlayer = new VideoPlayer(videoFile); expect(await videoPlayer.videoWidth).toBe(size.width); expect(await videoPlayer.videoHeight).toBe(size.height); }); - it('should be 1280x720 by default', async ({browser, testRelativeArtifactsPath, testOutputPath}) => { + it('should be 1280x720 by default', async ({browser, testOutputPath}) => { + const videosPath = testOutputPath(''); const context = await browser.newContext({ - relativeArtifactsPath: testRelativeArtifactsPath, - recordVideos: true, + videosPath, }); await context.newPage(); await new Promise(r => setTimeout(r, 1000)); await context.close(); - const videoFile = findVideo(testOutputPath('')); + const videoFile = findVideo(videosPath); const videoPlayer = new VideoPlayer(videoFile); expect(await videoPlayer.videoWidth).toBe(1280); expect(await videoPlayer.videoHeight).toBe(720); }); + + it('should capture static page in persistent context', test => { + test.fixme('We do not wait for the video finish when closing persistent context.'); + }, async ({launchPersistent, testOutputPath}) => { + const videosPath = testOutputPath(''); + const size = { width: 320, height: 240 }; + const { context, page } = await launchPersistent({ + videosPath, + viewport: size, + videoSize: size + }); + + await page.evaluate(() => document.body.style.backgroundColor = 'red'); + await new Promise(r => setTimeout(r, 1000)); + await context.close(); + + const videoFile = findVideo(videosPath); + const videoPlayer = new VideoPlayer(videoFile); + const duration = videoPlayer.duration; + expect(duration).toBeGreaterThan(0); + + expect(videoPlayer.videoWidth).toBe(320); + expect(videoPlayer.videoHeight).toBe(240); + + { + const pixels = videoPlayer.seekLastFrame().data; + expectAll(pixels, almostRed); + } + }); }); diff --git a/test/trace.spec.ts b/test/trace.spec.ts index 7eb870fe94bae..96a8f0f5ad55f 100644 --- a/test/trace.spec.ts +++ b/test/trace.spec.ts @@ -19,21 +19,16 @@ import type * as trace from '../types/trace'; import * as path from 'path'; import * as fs from 'fs'; -it('should record trace', async ({browserType, defaultBrowserOptions, server, testOutputPath}) => { - const artifactsPath = testOutputPath('trace'); - const browser = await browserType.launch({ - ...defaultBrowserOptions, - artifactsPath, - }); - const context = await browser.newContext({ recordTrace: true }); +it('should record trace', async ({browser, testOutputPath, server}) => { + const artifactsPath = testOutputPath(''); + const tracePath = path.join(artifactsPath, 'playwright.trace'); + const context = await browser.newContext({ _tracePath: tracePath } as any); const page = await context.newPage(); const url = server.PREFIX + '/snapshot/snapshot-with-css.html'; await page.goto(url); await context.close(); - await browser.close(); - const traceFile = path.join(artifactsPath, 'playwright.trace'); - const traceFileContent = await fs.promises.readFile(traceFile, 'utf8'); + const traceFileContent = await fs.promises.readFile(tracePath, 'utf8'); const traceEvents = traceFileContent.split('\n').filter(line => !!line).map(line => JSON.parse(line)) as trace.TraceEvent[]; const contextEvent = traceEvents.find(event => event.type === 'context-created') as trace.ContextCreatedTraceEvent; @@ -54,13 +49,3 @@ it('should record trace', async ({browserType, defaultBrowserOptions, server, te expect(gotoEvent.snapshot).toBeTruthy(); expect(fs.existsSync(path.join(artifactsPath, 'trace-resources', gotoEvent.snapshot!.sha1))).toBe(true); }); - -it('should require artifactsPath', async ({browserType, defaultBrowserOptions}) => { - const browser = await browserType.launch({ - ...defaultBrowserOptions, - artifactsPath: undefined, - }); - const error = await browser.newContext({ recordTrace: true }).catch(e => e); - expect(error.message).toContain('"recordTrace" option requires "artifactsPath" to be specified'); - await browser.close(); -}); diff --git a/utils/doclint/check_public_api/JSBuilder.js b/utils/doclint/check_public_api/JSBuilder.js index 0c01f4710083b..4da2c06390ed8 100644 --- a/utils/doclint/check_public_api/JSBuilder.js +++ b/utils/doclint/check_public_api/JSBuilder.js @@ -306,6 +306,7 @@ function checkSources(sources) { for (const innerType of type.types) { let innerProps = getTypeProperties(innerType); props = props.filter(p => !innerProps.find(e => e.getName() === p.getName())); + props = props.filter(p => p.getName() !== '_tracePath' && p.getName() !== '_traceResourcesPath'); props.push(...innerProps); } return props;