diff --git a/packages/playwright-core/src/server/bidi/bidiBrowser.ts b/packages/playwright-core/src/server/bidi/bidiBrowser.ts index f1d806332f5b2..22e30f0901f1e 100644 --- a/packages/playwright-core/src/server/bidi/bidiBrowser.ts +++ b/packages/playwright-core/src/server/bidi/bidiBrowser.ts @@ -215,6 +215,13 @@ export class BidiBrowserContext extends BrowserContext { const promises: Promise[] = [ super._initialize(), ]; + const downloadBehavior: bidi.Browser.DownloadBehavior = this._options.acceptDownloads === 'accept' ? + { type: 'allowed', destinationFolder: this._browser.options.downloadsPath } : + { type: 'denied' }; + promises.push(this._browser._browserSession.send('browser.setDownloadBehavior', { + downloadBehavior, + userContexts: [this._userContextId()], + })); promises.push(this.doUpdateDefaultViewport()); if (this._options.geolocation) promises.push(this.setGeolocation(this._options.geolocation)); diff --git a/packages/playwright-core/src/server/bidi/bidiPage.ts b/packages/playwright-core/src/server/bidi/bidiPage.ts index 237650d4b7dc6..eaf8f7ca3487a 100644 --- a/packages/playwright-core/src/server/bidi/bidiPage.ts +++ b/packages/playwright-core/src/server/bidi/bidiPage.ts @@ -254,7 +254,7 @@ export class BidiPage implements PageDelegate { if (!originPage) return; - this._browserContext._browser._downloadCreated(originPage, event.navigation, event.url, event.suggestedFilename); + this._browserContext._browser._downloadCreated(originPage, event.navigation, event.url, event.suggestedFilename, true); } private _onDownloadEnded(event: bidi.BrowsingContext.DownloadEndParams) { diff --git a/packages/playwright-core/src/server/bidi/third_party/bidiCommands.d.ts b/packages/playwright-core/src/server/bidi/third_party/bidiCommands.d.ts index f48ffe98259c0..1edc8868af027 100644 --- a/packages/playwright-core/src/server/bidi/third_party/bidiCommands.d.ts +++ b/packages/playwright-core/src/server/bidi/third_party/bidiCommands.d.ts @@ -50,6 +50,10 @@ export interface Commands { }; returnType: Bidi.Browser.RemoveUserContext; }; + 'browser.setDownloadBehavior': { + params: Bidi.Browser.SetDownloadBehaviorParameters; + returnType: Bidi.Browser.SetDownloadBehaviorResult; + } 'browsingContext.activate': { params: Bidi.BrowsingContext.ActivateParameters; diff --git a/packages/playwright-core/src/server/browser.ts b/packages/playwright-core/src/server/browser.ts index d974cbe7e44dd..1fd2b93228413 100644 --- a/packages/playwright-core/src/server/browser.ts +++ b/packages/playwright-core/src/server/browser.ts @@ -131,8 +131,8 @@ export abstract class Browser extends SdkObject { return this._contextForReuse?.context; } - _downloadCreated(page: Page, uuid: string, url: string, suggestedFilename?: string) { - const download = new Download(page, this.options.downloadsPath || '', uuid, url, suggestedFilename); + _downloadCreated(page: Page, uuid: string, url: string, suggestedFilename?: string, useSuggestedFilename?: boolean) { + const download = new Download(page, this.options.downloadsPath || '', uuid, url, suggestedFilename, useSuggestedFilename); this._downloads.set(uuid, download); } diff --git a/packages/playwright-core/src/server/download.ts b/packages/playwright-core/src/server/download.ts index 5ba6ed8ef0a27..5b70771c66c85 100644 --- a/packages/playwright-core/src/server/download.ts +++ b/packages/playwright-core/src/server/download.ts @@ -26,9 +26,10 @@ export class Download { private _page: Page; private _suggestedFilename: string | undefined; - constructor(page: Page, downloadsPath: string, uuid: string, url: string, suggestedFilename?: string) { + constructor(page: Page, downloadsPath: string, uuid: string, url: string, suggestedFilename?: string, useSuggestedFilename?: boolean) { const unaccessibleErrorMessage = page.browserContext._options.acceptDownloads === 'deny' ? 'Pass { acceptDownloads: true } when you are creating your browser context.' : undefined; - this.artifact = new Artifact(page, path.join(downloadsPath, uuid), unaccessibleErrorMessage, () => { + const downloadPath = path.join(downloadsPath, useSuggestedFilename ? suggestedFilename! : uuid); + this.artifact = new Artifact(page, downloadPath, unaccessibleErrorMessage, () => { return this._page.browserContext.cancelDownload(uuid); }); this._page = page; diff --git a/tests/bidi/expectations/moz-firefox-nightly-library.txt b/tests/bidi/expectations/moz-firefox-nightly-library.txt index fe9e7e6ea751f..e0280875e0c8a 100644 --- a/tests/bidi/expectations/moz-firefox-nightly-library.txt +++ b/tests/bidi/expectations/moz-firefox-nightly-library.txt @@ -58,9 +58,11 @@ library/browsercontext-viewport.spec.ts › should support touch with null viewp library/browsertype-connect.spec.ts › launchServer › should be able to connect 20 times to a single server without warnings [timeout] library/browsertype-connect.spec.ts › launchServer › should save download [fail] library/browsertype-connect.spec.ts › launchServer › should saveAs videos from remote browser [timeout] +library/browsertype-connect.spec.ts › launchServer › should upload a folder [fail] library/browsertype-connect.spec.ts › run-server › should be able to connect 20 times to a single server without warnings [timeout] library/browsertype-connect.spec.ts › run-server › should save download [fail] library/browsertype-connect.spec.ts › run-server › should saveAs videos from remote browser [timeout] +library/browsertype-connect.spec.ts › run-server › should upload a folder [fail] library/browsertype-launch.spec.ts › should reject if launched browser fails immediately [fail] library/capabilities.spec.ts › should play video @smoke [timeout] library/channels.spec.ts › should work with the domain module [timeout] @@ -90,7 +92,6 @@ library/chromium/launcher.spec.ts › should support request/response events whe library/debug-controller.spec.ts › should allow setting recorder mode only for specific browser [fail] library/debug-controller.spec.ts › should record [flaky] library/debug-controller.spec.ts › should work with browser._launchServer [flaky] -library/defaultbrowsercontext-1.spec.ts › should support acceptDownloads option [fail] library/defaultbrowsercontext-1.spec.ts › should support bypassCSP option [fail] library/defaultbrowsercontext-1.spec.ts › should support javascriptEnabled option [fail] library/defaultbrowsercontext-2.spec.ts › should have passed URL when launching with ignoreDefaultArgs: true [timeout] @@ -100,35 +101,9 @@ library/defaultbrowsercontext-2.spec.ts › should support forcedColors option [ library/defaultbrowsercontext-2.spec.ts › should support hasTouch option [fail] library/defaultbrowsercontext-2.spec.ts › should support reducedMotion option [fail] library/download.spec.ts › download event › should be able to cancel pending downloads [timeout] -library/download.spec.ts › download event › should create subdirectories when saving to non-existent user-specified path [fail] -library/download.spec.ts › download event › should delete downloads on browser gone [fail] -library/download.spec.ts › download event › should delete downloads on context destruction [fail] -library/download.spec.ts › download event › should delete file [fail] -library/download.spec.ts › download event › should download large binary.zip [fail] -library/download.spec.ts › download event › should emit download event from nested iframes [fail] -library/download.spec.ts › download event › should expose stream [fail] -library/download.spec.ts › download event › should not fail explicitly to cancel a download even if that is already finished [fail] library/download.spec.ts › download event › should report download path within page.on('download', …) handler for Blobs [timeout] -library/download.spec.ts › download event › should report download path within page.on('download', …) handler for Files [fail] -library/download.spec.ts › download event › should report download when navigation turns into download @smoke [fail] -library/download.spec.ts › download event › should report downloads for download attribute [fail] -library/download.spec.ts › download event › should report downloads with acceptDownloads: true [fail] -library/download.spec.ts › download event › should report downloads with interception [fail] library/download.spec.ts › download event › should report new window downloads [timeout] -library/download.spec.ts › download event › should report non-navigation downloads [fail] -library/download.spec.ts › download event › should save to overwritten filepath [fail] -library/download.spec.ts › download event › should save to two different paths with multiple saveAs calls [fail] -library/download.spec.ts › download event › should save to user-specified path without updating original path [fail] -library/download.spec.ts › download event › should work with Cross-Origin-Opener-Policy [fail] -library/download.spec.ts › should be able to download a inline PDF file via navigation [timeout] -library/download.spec.ts › should be able to download a inline PDF file via response interception [fail] -library/download.spec.ts › should be able to download a PDF file [fail] -library/download.spec.ts › should download successfully when routing [fail] -library/download.spec.ts › should save to user-specified path [fail] -library/downloads-path.spec.ts › downloads path › should accept downloads in persistent context [fail] -library/downloads-path.spec.ts › downloads path › should delete downloads when context closes [fail] -library/downloads-path.spec.ts › downloads path › should delete downloads when persistent context closes [fail] -library/downloads-path.spec.ts › downloads path › should keep downloadsPath folder [fail] +library/download.spec.ts › download event › should throw if browser dies [fail] library/emulation-focus.spec.ts › should focus popups by default [fail] library/emulation-focus.spec.ts › should focus with more than one page/context [fail] library/emulation-focus.spec.ts › should think that all pages are focused @smoke [fail]