From cd84b4702a1b3cd7840e92f645cccc99014f6b30 Mon Sep 17 00:00:00 2001 From: Rui Figueira Date: Thu, 22 Oct 2026 12:54:22 +0100 Subject: [PATCH 1/6] chore(puppeteer): upgrade to puppeteer v25.10.0 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Move submodules/puppeteer from puppeteer-v24.40.0 to puppeteer-v25.10.0 (Chrome 146 -> 152). Patch updates: - Rebase sessionId onto the new CdpBrowser._create/constructor parameters (blocklist, allowlist, logger). - BrowserConnector: keep the CDP-only Workers path, pass the logger, headers and wsOptions through to BrowserWebSocketTransport, and drop the new channel/DevToolsActivePort branch. - util: environment.value.fs is gone upstream. Write `path` output with a single environment.value.writeFile call in Workers. - cdp/Frame: import Realm from api/Realm.js, not the Node entry point. The old import pulled @puppeteer/browsers into the shipped types. Wrapper updates: - Provide the new environment file helpers (readFile, writeFile, openFileForWriting, createWriteStream, mkdir) from node:fs. - Mirror upstream _connectToCdpBrowser in connectToCDPBrowser and replace the removed debugError helper with debug(DEBUG_PREFIXES.error). - Give the top-level connect/launch/... exports explicit types so the declarations do not reference the Node entry point. - Follow the ESM-only output move from lib/esm/puppeteer to lib/puppeteer. - Bump devtools-protocol to 0.0.1666840 to match puppeteer-core. - copy_types: match the new ConnectOptions headers docs, hide wsOptions and drop the BiDi debug prefixes from the shipped declarations. - generate_worker_tests: upstream renamed *.spec.ts to *.test.ts. Update the exclude list and per-file rewrites, exclude the Node-only followSymlinks suite, alias ../mocha-utils.js for cdp/ suites, and drop sameParty from the cookie rewrites. beep-boop-🤖 --- package-lock.json | 8 +- packages/puppeteer-cloudflare/package.json | 2 +- .../cloudflare/WorkersWebSocketTransport.ts | 6 +- .../src/cloudflare/utils.ts | 21 ++- packages/puppeteer-cloudflare/src/index.ts | 38 +++- .../tests/package-lock.json | 4 +- .../puppeteer-cloudflare/tsconfig.types.json | 2 +- .../puppeteer-cloudflare/utils/copy_types.js | 27 ++- .../utils/generate_worker_tests.js | 112 ++++++------ packages/puppeteer-cloudflare/vite.config.ts | 10 +- patches/puppeteer.patch | 164 ++++++++++-------- submodules/puppeteer | 2 +- 12 files changed, 245 insertions(+), 151 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4f4ba3ce5..c1218f3e8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8130,7 +8130,7 @@ "@types/debug": "^4.1.12", "@types/node": "^18.17.15", "debug": "^4.4.3", - "devtools-protocol": "0.0.1581282", + "devtools-protocol": "0.0.1666840", "mitt": "3.0.1", "parsel-js": "1.2.2", "rxjs": "7.8.2", @@ -8197,9 +8197,9 @@ "license": "MIT" }, "packages/puppeteer-cloudflare/node_modules/devtools-protocol": { - "version": "0.0.1581282", - "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1581282.tgz", - "integrity": "sha512-nv7iKtNZQshSW2hKzYNr46nM/Cfh5SEvE2oV0/SEGgc9XupIY5ggf84Cz8eJIkBce7S3bmTAauFD6aysMpnqsQ==", + "version": "0.0.1666840", + "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1666840.tgz", + "integrity": "sha512-gCcO42XCHKEs7Ag0S7aGYsnJ7hlgrO3qderYqeiY0Eqk+0GFfuvT13IA0hHreJTa2KCdDVyGMeOhdMNmrrTjVg==", "license": "BSD-3-Clause" }, "packages/puppeteer-cloudflare/node_modules/parsel-js": { diff --git a/packages/puppeteer-cloudflare/package.json b/packages/puppeteer-cloudflare/package.json index a8da96041..23c57b29a 100644 --- a/packages/puppeteer-cloudflare/package.json +++ b/packages/puppeteer-cloudflare/package.json @@ -53,7 +53,7 @@ "@types/debug": "^4.1.12", "@types/node": "^18.17.15", "debug": "^4.4.3", - "devtools-protocol": "0.0.1581282", + "devtools-protocol": "0.0.1666840", "mitt": "3.0.1", "parsel-js": "1.2.2", "rxjs": "7.8.2", diff --git a/packages/puppeteer-cloudflare/src/cloudflare/WorkersWebSocketTransport.ts b/packages/puppeteer-cloudflare/src/cloudflare/WorkersWebSocketTransport.ts index 1349eb038..b0157bc07 100644 --- a/packages/puppeteer-cloudflare/src/cloudflare/WorkersWebSocketTransport.ts +++ b/packages/puppeteer-cloudflare/src/cloudflare/WorkersWebSocketTransport.ts @@ -4,7 +4,7 @@ * SPDX-License-Identifier: Apache-2.0 */ import type {ConnectionTransport} from 'puppeteer-core/lib/common/ConnectionTransport.js'; -import {debugError} from 'puppeteer-core/lib/common/util.js'; +import {DEBUG_PREFIXES, debug} from 'puppeteer-core/lib/common/Debug.js'; import {packageVersion} from '../packageVersion.js'; import type {BrowserWorker} from './BrowserWorker.js'; @@ -76,7 +76,9 @@ export class WorkersWebSocketTransport implements ConnectionTransport { }); this.ws.addEventListener('error', e => { const message = (e as ErrorEvent).message || 'Unknown error'; - debugError(`WebSocket error: SessionID: ${sessionId} - ${message}`); + debug(DEBUG_PREFIXES.error)?.( + `WebSocket error: SessionID: ${sessionId} - ${message}` + ); }); } diff --git a/packages/puppeteer-cloudflare/src/cloudflare/utils.ts b/packages/puppeteer-cloudflare/src/cloudflare/utils.ts index 3d8bd1f74..643d09bd9 100644 --- a/packages/puppeteer-cloudflare/src/cloudflare/utils.ts +++ b/packages/puppeteer-cloudflare/src/cloudflare/utils.ts @@ -9,7 +9,8 @@ import {CdpBrowser} from 'puppeteer-core/lib/cdp/Browser.js'; import {Connection} from 'puppeteer-core/lib/cdp/Connection.js'; import type {ConnectionTransport} from 'puppeteer-core/lib/common/ConnectionTransport.js'; import type {ConnectOptions} from 'puppeteer-core/lib/common/ConnectOptions.js'; -import {debugError} from 'puppeteer-core/lib/common/util.js'; +import {DEBUG_PREFIXES, debug} from 'puppeteer-core/lib/common/Debug.js'; +import {createIncrementalIdGenerator} from 'puppeteer-core/lib/util/incremental-id-generator.js'; /** * Users should never call this directly; it's called when calling * `puppeteer.connect` with `protocol: 'cdp'`. @@ -23,6 +24,7 @@ export async function connectToCDPBrowser( const { acceptInsecureCerts = false, networkEnabled = true, + issuesEnabled = true, defaultViewport = DEFAULT_VIEWPORT, downloadBehavior, targetFilter, @@ -30,6 +32,10 @@ export async function connectToCDPBrowser( slowMo = 0, protocolTimeout, handleDevToolsAsPage, + idGenerator = createIncrementalIdGenerator(), + blocklist, + allowlist, + logger = debug, sessionId = 'unknown', } = options; @@ -37,7 +43,10 @@ export async function connectToCDPBrowser( '', connectionTransport, slowMo, - protocolTimeout + protocolTimeout, + /* rawErrors */ false, + idGenerator, + logger ); const {browserContextIds} = await connection.send( @@ -51,13 +60,19 @@ export async function connectToCDPBrowser( downloadBehavior, undefined, () => { - return connection.send('Browser.close').catch(debugError); + return connection.send('Browser.close').catch(error => { + logger?.(DEBUG_PREFIXES.error)?.(error); + }); }, targetFilter, isPageTarget, undefined, networkEnabled, + issuesEnabled, handleDevToolsAsPage, + blocklist, + allowlist, + logger, sessionId ); return browser; diff --git a/packages/puppeteer-cloudflare/src/index.ts b/packages/puppeteer-cloudflare/src/index.ts index 5a2a4064b..6f7ecf74d 100644 --- a/packages/puppeteer-cloudflare/src/index.ts +++ b/packages/puppeteer-cloudflare/src/index.ts @@ -11,9 +11,31 @@ import {environment} from 'puppeteer-core/lib/environment.js'; // ProtocolMapping.Commands so session.send('Cloudflare.*', ...) is typed. import './cloudflare/protocol.js'; -Object.defineProperties(environment.value, { - fs: {value: fs}, - path: {value: path}, +// Wire puppeteer-core's file helpers to the Workers node:fs implementation. +// Used for `path` options, e.g. page.pdf({path}) and page.screenshot({path}). +Object.assign(environment.value, { + path, + readFile: (filePath: string, encoding?: 'utf8' | 'ascii') => { + return fs.promises.readFile(filePath, encoding ? {encoding} : undefined); + }, + writeFile: async (filePath: string, data: Uint8Array | string) => { + await fs.promises.writeFile(filePath, data); + }, + openFileForWriting: (filePath: string) => { + return fs.promises.open(filePath, 'w+'); + }, + createWriteStream: ( + filePath: string, + options?: {encoding?: BufferEncoding; overwrite?: boolean}, + ) => { + return fs.createWriteStream(filePath, { + encoding: options?.encoding, + flags: options?.overwrite === false ? 'wx' : 'w', + }); + }, + mkdir: async (dirPath: string, options?: {recursive?: boolean}) => { + await fs.promises.mkdir(dirPath, options); + }, }); export * from 'puppeteer-core/lib/api/api.js'; export * from 'puppeteer-core/lib/common/common.js'; @@ -24,7 +46,15 @@ export * from './cloudflare/protocol.js'; const puppeteer = new PuppeteerWorkers(); -export const {connect, history, launch, limits, sessions, acquire} = puppeteer; +// Explicit types keep the emitted declarations pointing at PuppeteerWorkers. +// Inferred types would reference puppeteer-core's Node entry point, which pulls +// in Node-only modules such as @puppeteer/browsers. +export const connect: PuppeteerWorkers['connect'] = puppeteer.connect; +export const history: PuppeteerWorkers['history'] = puppeteer.history; +export const launch: PuppeteerWorkers['launch'] = puppeteer.launch; +export const limits: PuppeteerWorkers['limits'] = puppeteer.limits; +export const sessions: PuppeteerWorkers['sessions'] = puppeteer.sessions; +export const acquire: PuppeteerWorkers['acquire'] = puppeteer.acquire; export * from './cloudflare/PuppeteerWorkers.js'; diff --git a/packages/puppeteer-cloudflare/tests/package-lock.json b/packages/puppeteer-cloudflare/tests/package-lock.json index 74d2426ed..5053ccae7 100644 --- a/packages/puppeteer-cloudflare/tests/package-lock.json +++ b/packages/puppeteer-cloudflare/tests/package-lock.json @@ -32,7 +32,7 @@ "@types/debug": "^4.1.12", "@types/node": "^18.17.15", "debug": "^4.4.3", - "devtools-protocol": "0.0.1581282", + "devtools-protocol": "0.0.1666840", "mitt": "3.0.1", "parsel-js": "1.2.2", "rxjs": "7.8.2", @@ -94,7 +94,7 @@ "license": "MIT" }, "../node_modules/devtools-protocol": { - "version": "0.0.1581282", + "version": "0.0.1666840", "license": "BSD-3-Clause" }, "../node_modules/parsel-js": { diff --git a/packages/puppeteer-cloudflare/tsconfig.types.json b/packages/puppeteer-cloudflare/tsconfig.types.json index 4fbec9018..b9e8597ed 100644 --- a/packages/puppeteer-cloudflare/tsconfig.types.json +++ b/packages/puppeteer-cloudflare/tsconfig.types.json @@ -9,7 +9,7 @@ "outDir": ".types", "paths": { "devtools-protocol/types/protocol-mapping.js": ["../../submodules/puppeteer/packages/puppeteer-core/node_modules/devtools-protocol/types/protocol-mapping.d.ts"], - "puppeteer-core/lib/*": ["../../submodules/puppeteer/packages/puppeteer-core/lib/esm/puppeteer/*"] + "puppeteer-core/lib/*": ["../../submodules/puppeteer/packages/puppeteer-core/lib/puppeteer/*"] }, "rootDir": "src" } diff --git a/packages/puppeteer-cloudflare/utils/copy_types.js b/packages/puppeteer-cloudflare/utils/copy_types.js index 31d843905..1b0a019ab 100644 --- a/packages/puppeteer-cloudflare/utils/copy_types.js +++ b/packages/puppeteer-cloudflare/utils/copy_types.js @@ -7,11 +7,11 @@ const generatedDir = path.join(packageDir, '.types'); const outputDir = path.join(packageDir, 'lib'); const puppeteerTypesDir = path.resolve( packageDir, - '../../submodules/puppeteer/packages/puppeteer-core/lib/esm/puppeteer' + '../../submodules/puppeteer/packages/puppeteer-core/lib/puppeteer' ); const thirdPartyTypesDir = path.resolve( packageDir, - '../../submodules/puppeteer/packages/puppeteer-core/lib/esm/third_party' + '../../submodules/puppeteer/packages/puppeteer-core/lib/third_party' ); function replaceExactlyOnce(contents, search, replacement, source) { @@ -61,9 +61,22 @@ export interface SupportedWebDriverCapabilities { * Headers to use for the web socket connection. * @remarks * Only works in the Node.js environment. + * + * @deprecated Use {@link WsOptions.headers} via + * {@link ConnectOptions.wsOptions} instead. When both are set, + * \`wsOptions.headers\` wins. */ headers?: Record; `; + const wsOptionsOption = ` /** + * Options for the WebSocket connection to the browser. + * + * @remarks + * Only used in the Node.js environment. The browser build has no ping frame + * API, so the keep-alive options are ignored there. + */ + wsOptions?: WsOptions; +`; contents = replaceExactlyOnce( contents, @@ -92,6 +105,7 @@ export interface SupportedWebDriverCapabilities { source ); contents = replaceExactlyOnce(contents, capabilitiesOption, '', source); + contents = replaceExactlyOnce(contents, wsOptionsOption, '', source); return replaceExactlyOnce(contents, headersOption, '', source); } @@ -121,6 +135,15 @@ function copyDeclarations( } if (relative === 'common/ConnectOptions.d.ts') { contents = sanitizeConnectOptions(contents, source); + } else if (relative === 'common/Debug.d.ts') { + // The Workers build has no BiDi, so drop its debug channel prefixes. + contents = replaceExactlyOnce( + contents, + ' readonly bidiSend: "puppeteer:webDriverBiDi:SEND ►";\n' + + ' readonly bidiReceive: "puppeteer:webDriverBiDi:RECV ◀";\n', + '', + source + ); } else if (relative === 'index-browser.d.ts') { contents = replaceExactlyOnce( contents, diff --git a/packages/puppeteer-cloudflare/utils/generate_worker_tests.js b/packages/puppeteer-cloudflare/utils/generate_worker_tests.js index 086eb7bcf..32c351d80 100644 --- a/packages/puppeteer-cloudflare/utils/generate_worker_tests.js +++ b/packages/puppeteer-cloudflare/utils/generate_worker_tests.js @@ -8,50 +8,51 @@ import {deleteDir, listFiles, writeFile} from './utils.js'; const basedir = path.dirname(fileURLToPath(import.meta.url)); const excludedFiles = [ - 'acceptInsecureCerts.spec.ts', - 'accessibility.spec.ts', - 'ariaqueryhandler.spec.ts', - 'autofill.spec.ts', - 'browser.spec.ts', - 'browsercontext-cookies.spec.ts', - 'browsercontext.spec.ts', - 'cdp/a11yLoaderId.spec.ts', - 'cdp/backendNodeId.spec.ts', - 'cdp/bfcache.spec.ts', - 'cdp/CDPSession.spec.ts', - 'cdp/devtools.spec.ts', - 'cdp/extensions.spec.ts', - 'cdp/heapSnapshot.spec.ts', - 'cdp/interventionHeaders.spec.ts', - 'cdp/network.spec.ts', - 'cdp/pdf.spec.ts', - 'cdp/pipe.spec.ts', - 'cdp/prerender.spec.ts', - 'cdp/queryObjects.spec.ts', - 'cdp/screencast.spec.ts', - 'cdp/TargetManager.spec.ts', - 'cdp/userDataDir.spec.ts', - 'chromiumonly.spec.ts', - 'connect.spec.ts', - 'debugInfo.spec.ts', - 'defaultbrowsercontext.spec.ts', - 'device-request-prompt.spec.ts', - 'download.spec.ts', - 'emulation.spec.ts', - 'fixtures.spec.ts', - 'headful.spec.ts', - 'idle_override.spec.ts', - 'ignorehttpserrors.spec.ts', - 'launcher.spec.ts', - 'network.spec.ts', - 'proxy.spec.ts', - 'requestinterception-experimental.spec.ts', - 'requestinterception.spec.ts', - 'screenshot.spec.ts', - 'stacktrace.spec.ts', - 'target.spec.ts', - 'waittask.spec.ts', - 'worker.spec.ts', + 'acceptInsecureCerts.test.ts', + 'accessibility.test.ts', + 'ariaqueryhandler.test.ts', + 'autofill.test.ts', + 'browser.test.ts', + 'browsercontext-cookies.test.ts', + 'browsercontext.test.ts', + 'cdp/a11yLoaderId.test.ts', + 'cdp/backendNodeId.test.ts', + 'cdp/bfcache.test.ts', + 'cdp/CDPSession.test.ts', + 'cdp/devtools.test.ts', + 'cdp/extensions.test.ts', + 'cdp/heapSnapshot.test.ts', + 'cdp/interventionHeaders.test.ts', + 'cdp/network.test.ts', + 'cdp/pdf.test.ts', + 'cdp/pipe.test.ts', + 'cdp/prerender.test.ts', + 'cdp/queryObjects.test.ts', + 'cdp/screencast.test.ts', + 'cdp/TargetManager.test.ts', + 'cdp/userDataDir.test.ts', + 'chromiumonly.test.ts', + 'connect.test.ts', + 'debugInfo.test.ts', + 'defaultbrowsercontext.test.ts', + 'device-request-prompt.test.ts', + 'download.test.ts', + 'emulation.test.ts', + 'fixtures.test.ts', + 'followSymlinks.test.ts', + 'headful.test.ts', + 'idle_override.test.ts', + 'ignorehttpserrors.test.ts', + 'launcher.test.ts', + 'network.test.ts', + 'proxy.test.ts', + 'requestinterception-experimental.test.ts', + 'requestinterception.test.ts', + 'screenshot.test.ts', + 'stacktrace.test.ts', + 'target.test.ts', + 'waittask.test.ts', + 'worker.test.ts', ]; const sourceTestsDir = path.join(basedir, '..', '..', '..', 'submodules', 'puppeteer', 'test', 'src'); @@ -118,7 +119,7 @@ function tracingTempDirectoryPlugin() { name: 'tracing-temp-directory', enforce: 'pre', transform(code, id) { - if (!id.endsWith('/tracing.spec.ts')) { + if (!id.endsWith('/tracing.test.ts')) { return; } return code.replaceAll('import.meta.dirname', JSON.stringify('/tmp')); @@ -131,13 +132,13 @@ function remoteTestServerPlugin() { name: 'remote-test-server', enforce: 'pre', transform(code, id) { - if (id.endsWith('/page.spec.ts')) { + if (id.endsWith('/page.test.ts')) { return code.replace( " it('should work with options parameter', async () => {\n const {page, server} = await getTestState();\n\n expect(\n await page.evaluate(() => {\n return navigator.userAgent;\n }),\n ).toContain('Mozilla');\n await page.setUserAgent({userAgent: 'foobar'});", " it('should work with options parameter', async () => {\n const {page, server} = await getTestState();\n\n await page.setUserAgent({userAgent: 'foobar'});", ); } - if (id.endsWith('/console.spec.ts')) { + if (id.endsWith('/console.test.ts')) { // Worker fixtures use HTTPS, so an HTTP URL tests mixed-content blocking // instead of the network failure and console location asserted upstream. // Browser Run's network proxy can surface the failed lookup as a reset. @@ -148,7 +149,7 @@ function remoteTestServerPlugin() { "expect(message.text()).atLeastOneToContain(['ERR_NAME_NOT_RESOLVED', 'ERR_CONNECTION_RESET']);", ); } - if (id.endsWith('/navigation.spec.ts')) { + if (id.endsWith('/navigation.test.ts')) { return code .replace( "it('should work when subframe issues window.stop()', async function () {", @@ -156,18 +157,18 @@ function remoteTestServerPlugin() { ) .replace('timeout: this.timeout() - 1000,', 'timeout: testInfo.timeout - 1000,'); } - if (!id.endsWith('/cookies.spec.ts')) { + if (!id.endsWith('/cookies.test.ts')) { return; } return code .replace( - "domain: 'localhost',\n path: '/',\n sameParty: false,\n expires: -1,\n httpOnly: false,\n secure: false,\n sourceScheme: 'Unset',", - "domain: new URL(server.EMPTY_PAGE).hostname,\n path: '/',\n sameParty: false,\n expires: -1,\n httpOnly: false,\n secure: new URL(server.EMPTY_PAGE).protocol === 'https:',\n sourceScheme: 'Unset',", + "domain: 'localhost',\n path: '/',\n expires: -1,\n httpOnly: false,\n secure: false,\n sourceScheme: 'Unset',", + "domain: new URL(server.EMPTY_PAGE).hostname,\n path: '/',\n expires: -1,\n httpOnly: false,\n secure: new URL(server.EMPTY_PAGE).protocol === 'https:',\n sourceScheme: 'Unset',", ) .replace( - "domain: 'localhost',\n path: '/',\n sameParty: false,\n expires: -1,\n size: 14,\n httpOnly: false,\n secure: false,\n session: true,\n sourceScheme: 'Unset',", - "domain: new URL(server.EMPTY_PAGE).hostname,\n path: '/',\n sameParty: false,\n expires: -1,\n size: 14,\n httpOnly: false,\n secure: new URL(server.EMPTY_PAGE).protocol === 'https:',\n session: true,\n sourceScheme: 'Unset',", + "domain: 'localhost',\n path: '/',\n expires: -1,\n size: 14,\n httpOnly: false,\n secure: false,\n session: true,\n sourceScheme: 'Unset',", + "domain: new URL(server.EMPTY_PAGE).hostname,\n path: '/',\n expires: -1,\n size: 14,\n httpOnly: false,\n secure: new URL(server.EMPTY_PAGE).protocol === 'https:',\n session: true,\n sourceScheme: 'Unset',", ) .replace( ' await expectCookieEquals(await page.cookies(), [\n {\n name: \'partitionCookie\',', @@ -278,6 +279,11 @@ ${[...testFiles, ...cloudflareTestFiles] basedir, '../tests/src/server/mocha-utils', ), + // Tests in subdirectories, e.g. cdp/, import it from the parent. + '../mocha-utils.js': path.resolve( + basedir, + '../tests/src/server/mocha-utils', + ), sinon: path.resolve(basedir, '../tests/src/server/mocks/sinon.ts'), }, diff --git a/packages/puppeteer-cloudflare/vite.config.ts b/packages/puppeteer-cloudflare/vite.config.ts index 1130d5e0e..d412eeca5 100644 --- a/packages/puppeteer-cloudflare/vite.config.ts +++ b/packages/puppeteer-cloudflare/vite.config.ts @@ -11,8 +11,8 @@ const baseDir = __dirname.replace(/\\/g, '/'); // Use **/ prefix to match anywhere in absolute paths const pathMappings = [ { glob: '**/packages/puppeteer-cloudflare/src/**', target: 'puppeteer-cloudflare' }, - { glob: '**/submodules/puppeteer/packages/puppeteer-core/lib/esm/puppeteer/**', target: 'puppeteer-core' }, - { glob: '**/submodules/puppeteer/packages/puppeteer-core/lib/esm/third_party/**', target: 'puppeteer-core/third_party' }, + { glob: '**/submodules/puppeteer/packages/puppeteer-core/lib/puppeteer/**', target: 'puppeteer-core' }, + { glob: '**/submodules/puppeteer/packages/puppeteer-core/lib/third_party/**', target: 'puppeteer-core/third_party' }, { glob: '**/submodules/puppeteer/packages/puppeteer-core/node_modules/**', target: 'puppeteer-core/node_modules' }, ]; @@ -91,15 +91,15 @@ export default defineConfig({ // The TypeScript is pre-compiled with `tsc` to handle decorators correctly { find: /^puppeteer-core\/lib\/esm\/puppeteer\/(.+)\.js$/, - replacement: path.resolve(baseDir, '../../submodules/puppeteer/packages/puppeteer-core/lib/esm/puppeteer/$1.js'), + replacement: path.resolve(baseDir, '../../submodules/puppeteer/packages/puppeteer-core/lib/puppeteer/$1.js'), }, { find: /^puppeteer-core\/lib\/(.+)\.js$/, - replacement: path.resolve(baseDir, '../../submodules/puppeteer/packages/puppeteer-core/lib/esm/puppeteer/$1.js'), + replacement: path.resolve(baseDir, '../../submodules/puppeteer/packages/puppeteer-core/lib/puppeteer/$1.js'), }, { find: /^puppeteer-core\/lib\//, - replacement: path.resolve(baseDir, '../../submodules/puppeteer/packages/puppeteer-core/lib/esm/puppeteer/'), + replacement: path.resolve(baseDir, '../../submodules/puppeteer/packages/puppeteer-core/lib/puppeteer/'), }, ], }, diff --git a/patches/puppeteer.patch b/patches/puppeteer.patch index 0a1882fe1..cefd3ec85 100644 --- a/patches/puppeteer.patch +++ b/patches/puppeteer.patch @@ -1,11 +1,11 @@ diff --git a/packages/puppeteer-core/src/api/Browser.ts b/packages/puppeteer-core/src/api/Browser.ts -index 6a441ee0789..48cd7c1bd79 100644 +index 712e1eeda53..99e7002dbdd 100644 --- a/packages/puppeteer-core/src/api/Browser.ts +++ b/packages/puppeteer-core/src/api/Browser.ts -@@ -727,4 +727,13 @@ export abstract class Browser extends EventEmitter { +@@ -903,4 +903,13 @@ export abstract class Browser extends EventEmitter { * @internal */ - abstract isNetworkEnabled(): boolean; + abstract isIssuesEnabled(): boolean; + + /** + * Browser Run session ID. @@ -17,53 +17,53 @@ index 6a441ee0789..48cd7c1bd79 100644 + } } diff --git a/packages/puppeteer-core/src/cdp/Browser.ts b/packages/puppeteer-core/src/cdp/Browser.ts -index 6d5c2fccde1..648968363ee 100644 +index 094caa838cb..19d5a867724 100644 --- a/packages/puppeteer-core/src/cdp/Browser.ts +++ b/packages/puppeteer-core/src/cdp/Browser.ts -@@ -68,6 +68,7 @@ export class CdpBrowser extends BrowserBase { - waitForInitiallyDiscoveredTargets = true, - networkEnabled = true, - handleDevToolsAsPage = false, +@@ -87,6 +87,7 @@ export class CdpBrowser extends BrowserBase { + blocklist: string[] | undefined = undefined, + allowlist: string[] | undefined = undefined, + logger: Logger, + sessionId?: string, ): Promise { const browser = new CdpBrowser( connection, -@@ -80,6 +81,7 @@ export class CdpBrowser extends BrowserBase { - waitForInitiallyDiscoveredTargets, - networkEnabled, - handleDevToolsAsPage, +@@ -103,6 +104,7 @@ export class CdpBrowser extends BrowserBase { + blocklist, + allowlist, + logger, + sessionId, ); - if (acceptInsecureCerts) { - await connection.send('Security.setIgnoreCertificateErrors', { -@@ -100,6 +102,8 @@ export class CdpBrowser extends BrowserBase { - #networkEnabled = true; - #targetManager: TargetManager; - #handleDevToolsAsPage = false; + + if (allowlist) { +@@ -139,6 +141,8 @@ export class CdpBrowser extends BrowserBase { + #version?: Deferred; + #hasNetworkRestrictions = false; + #subscriptions = new DisposableStack(); + // Keep the remote Browser Run session available for diagnostics. + #sessionId: string; constructor( connection: Connection, -@@ -112,6 +116,7 @@ export class CdpBrowser extends BrowserBase { - waitForInitiallyDiscoveredTargets = true, - networkEnabled = true, - handleDevToolsAsPage = false, +@@ -155,6 +159,7 @@ export class CdpBrowser extends BrowserBase { + blocklist: string[] | undefined = undefined, + allowlist: string[] | undefined = undefined, + logger: Logger, + sessionId?: string, ) { - super(); + super(logger); this.#networkEnabled = networkEnabled; -@@ -139,6 +144,7 @@ export class CdpBrowser extends BrowserBase { - new CdpBrowserContext(this.#connection, this, contextId), +@@ -197,6 +202,7 @@ export class CdpBrowser extends BrowserBase { + new CdpBrowserContext(this.#connection, this, contextId, logger), ); } + this.#sessionId = sessionId || 'unknown'; } #emitDisconnected = () => { -@@ -545,4 +551,12 @@ export class CdpBrowser extends BrowserBase { - override isNetworkEnabled(): boolean { - return this.#networkEnabled; +@@ -767,4 +773,12 @@ export class CdpBrowser extends BrowserBase { + override isIssuesEnabled(): boolean { + return this.#issuesEnabled; } + + /** @@ -74,11 +74,26 @@ index 6d5c2fccde1..648968363ee 100644 + return this.#sessionId; + } } +diff --git a/packages/puppeteer-core/src/cdp/Frame.ts b/packages/puppeteer-core/src/cdp/Frame.ts +index 6835dbd8253..0835458e8cf 100644 +--- a/packages/puppeteer-core/src/cdp/Frame.ts ++++ b/packages/puppeteer-core/src/cdp/Frame.ts +@@ -13,9 +13,9 @@ import type {SetContentWaitForOptions, WaitForOptions} from '../api/Frame.js'; + import {Frame, FrameEvent, throwIfDetached} from '../api/Frame.js'; + import type {HTTPResponse} from '../api/HTTPResponse.js'; + import type {WaitTimeoutOptions} from '../api/Page.js'; ++import type {Realm} from '../api/Realm.js'; + import {DEBUG_PREFIXES, type Logger} from '../common/Debug.js'; + import {UnsupportedOperation} from '../common/Errors.js'; +-import type {Realm} from '../puppeteer-core.js'; + import {Deferred} from '../util/Deferred.js'; + import {disposeSymbol} from '../util/disposable.js'; + import {isErrorLike} from '../util/ErrorLike.js'; diff --git a/packages/puppeteer-core/src/cdp/Page.ts b/packages/puppeteer-core/src/cdp/Page.ts -index fed1282dddf..a6eef18ed05 100644 +index 3a881be5fc2..648c40f87ee 100644 --- a/packages/puppeteer-core/src/cdp/Page.ts +++ b/packages/puppeteer-core/src/cdp/Page.ts -@@ -698,16 +698,36 @@ export class CdpPage extends Page { +@@ -742,16 +742,36 @@ export class CdpPage extends Page { if (!cookie.url && pageURL.startsWith('http')) { item.url = pageURL; } @@ -123,23 +138,24 @@ index fed1282dddf..a6eef18ed05 100644 } } diff --git a/packages/puppeteer-core/src/common/BrowserConnector.ts b/packages/puppeteer-core/src/common/BrowserConnector.ts -index bc7880ae451..86e22a0cc03 100644 +index 0836243b8eb..f78bb01b4a4 100644 --- a/packages/puppeteer-core/src/common/BrowserConnector.ts +++ b/packages/puppeteer-core/src/common/BrowserConnector.ts -@@ -5,22 +5,14 @@ - */ +@@ -6,23 +6,15 @@ + import {URLPattern} from '../../third_party/urlpattern-polyfill/urlpattern-polyfill.js'; import type {Browser} from '../api/Browser.js'; -import {_connectToBiDiBrowser} from '../bidi/BrowserConnector.js'; import {_connectToCdpBrowser} from '../cdp/BrowserConnector.js'; -import {environment, isNode} from '../environment.js'; import {assert} from '../util/assert.js'; import {isErrorLike} from '../util/ErrorLike.js'; - + +import {BrowserWebSocketTransport} from './BrowserWebSocketTransport.js'; import type {ConnectionTransport} from './ConnectionTransport.js'; import type {ConnectOptions} from './ConnectOptions.js'; - + import type {Logger} from './Debug.js'; + -const getWebSocketTransportClass = async () => { - return isNode - ? (await import('../node/NodeWebSocketTransport.js')).NodeWebSocketTransport @@ -150,7 +166,7 @@ index bc7880ae451..86e22a0cc03 100644 /** * Users should never call this directly; it's called when calling * `puppeteer.connect`. This method attaches Puppeteer to an existing browser instance. -@@ -33,21 +25,13 @@ export async function _connectToBrowser( +@@ -67,23 +59,14 @@ export async function _connectToBrowser( const {connectionTransport, endpointUrl} = await getConnectionTransport(options); @@ -159,6 +175,7 @@ index bc7880ae451..86e22a0cc03 100644 - connectionTransport, - endpointUrl, - options, +- options.logger, - ); - return bidiBrowser; - } else { @@ -166,6 +183,7 @@ index bc7880ae451..86e22a0cc03 100644 - connectionTransport, - endpointUrl, - options, +- options.logger, - ); - return cdpBrowser; - } @@ -174,24 +192,22 @@ index bc7880ae451..86e22a0cc03 100644 + connectionTransport, + endpointUrl, + options, ++ options.logger, + ); + return cdpBrowser; } /** -@@ -57,96 +41,35 @@ export async function _connectToBrowser( +@@ -94,7 +77,7 @@ export async function _connectToBrowser( async function getConnectionTransport( - options: ConnectOptions, + options: ConnectOptions & {logger: Logger}, ): Promise<{connectionTransport: ConnectionTransport; endpointUrl: string}> { -- const { -- browserWSEndpoint, -- browserURL, -- channel, -- transport, -- headers = {}, -- } = options; +- const {browserWSEndpoint, browserURL, channel, transport} = options; + const {browserWSEndpoint, browserURL, transport} = options; - + // `wsOptions.headers` supersedes the deprecated top-level `headers`. + const headers = options.wsOptions?.headers ?? options.headers ?? {}; + const wsOptions = options.wsOptions ?? {}; +@@ -102,18 +85,17 @@ async function getConnectionTransport( assert( Number(!!browserWSEndpoint) + Number(!!browserURL) + @@ -202,27 +218,31 @@ index bc7880ae451..86e22a0cc03 100644 - 'Exactly one of browserWSEndpoint, browserURL, transport or channel must be passed to puppeteer.connect', + 'Exactly one of browserWSEndpoint, browserURL or transport must be passed to puppeteer.connect', ); - + if (transport) { return {connectionTransport: transport, endpointUrl: ''}; } else if (browserWSEndpoint) { - const WebSocketClass = await getWebSocketTransportClass(); + // BrowserWebSocketTransport uses the WebSocket API available in Workers. const connectionTransport: ConnectionTransport = -- await WebSocketClass.create(browserWSEndpoint, headers); -+ await BrowserWebSocketTransport.create(browserWSEndpoint); - return { - connectionTransport: connectionTransport, - endpointUrl: browserWSEndpoint, +- await WebSocketClass.create( ++ await BrowserWebSocketTransport.create( + browserWSEndpoint, + headers, + options.logger, +@@ -125,9 +107,9 @@ async function getConnectionTransport( }; } else if (browserURL) { - const connectionURL = await getWSEndpoint(browserURL); + const connectionURL = await getWSEndpoint(browserURL, headers); - const WebSocketClass = await getWebSocketTransportClass(); + // Use the same Workers-compatible transport for discovered endpoints. const connectionTransport: ConnectionTransport = -- await WebSocketClass.create(connectionURL); -+ await BrowserWebSocketTransport.create(connectionURL); - return { +- await WebSocketClass.create( ++ await BrowserWebSocketTransport.create( + connectionURL, + headers, + options.logger, +@@ -137,59 +119,6 @@ async function getConnectionTransport( connectionTransport: connectionTransport, endpointUrl: connectionURL, }; @@ -243,10 +263,7 @@ index bc7880ae451..86e22a0cc03 100644 - ); - const portPath = join(userDataDir, 'DevToolsActivePort'); - try { -- const fileContent = await environment.value.fs.promises.readFile( -- portPath, -- 'ascii', -- ); +- const fileContent = await environment.value.readFile(portPath, 'ascii'); - const [rawPort, rawPath] = fileContent - .split('\n') - .map(line => { @@ -267,6 +284,8 @@ index bc7880ae451..86e22a0cc03 100644 - const connectionTransport = await WebSocketClass.create( - browserWSEndpoint, - headers, +- options.logger, +- wsOptions, - ); - return { - connectionTransport: connectionTransport, @@ -284,13 +303,13 @@ index bc7880ae451..86e22a0cc03 100644 throw new Error('Invalid connection options'); } diff --git a/packages/puppeteer-core/src/common/util.ts b/packages/puppeteer-core/src/common/util.ts -index 61ea5871dfe..d8f36286d12 100644 +index 1ddc8f540fd..34de0ed2948 100644 --- a/packages/puppeteer-core/src/common/util.ts +++ b/packages/puppeteer-core/src/common/util.ts -@@ -188,7 +188,13 @@ export function evaluationString( +@@ -183,7 +183,13 @@ export function evaluationString( return JSON.stringify(arg); } - + - return `(${fun})(${args.map(serializeArgument).join(',')})`; + // function is most likely bundled with wrangler, + // which uses esbuild with keepNames enabled. @@ -302,7 +321,7 @@ index 61ea5871dfe..d8f36286d12 100644 } /** -@@ -200,7 +206,24 @@ export async function getReadableAsTypedArray( +@@ -196,7 +202,21 @@ export async function getReadableAsTypedArray( ): Promise { const buffers: Uint8Array[] = []; const reader = readable.getReader(); @@ -311,28 +330,25 @@ index 61ea5871dfe..d8f36286d12 100644 + path && + globalThis.navigator?.userAgent === 'Cloudflare-Workers' + ) { -+ // Workers file handles do not preserve repeated writeFile append behavior. -+ await environment.value.fs.promises.writeFile(path, new Uint8Array()); ++ // Workers file handles do not preserve repeated writeFile append behavior, ++ // so write the full content once. + while (true) { + const {done, value} = await reader.read(); + if (done) { + break; + } -+ await environment.value.fs.promises.appendFile(path, value); ++ buffers.push(value); + } -+ const file = await environment.value.fs.promises.readFile(path); -+ return file.length === 0 -+ ? null -+ : new Uint8Array(file.buffer, file.byteOffset, file.byteLength); ++ await environment.value.writeFile(path, mergeUint8Arrays(buffers)); + } else if (path) { - const fileHandle = await environment.value.fs.promises.open(path, 'w+'); + const fileHandle = await environment.value.openFileForWriting(path); try { while (true) { diff --git a/packages/puppeteer-core/src/util/Function.ts b/packages/puppeteer-core/src/util/Function.ts index ae0f161c6d9..f0d5ae5f40c 100644 --- a/packages/puppeteer-core/src/util/Function.ts +++ b/packages/puppeteer-core/src/util/Function.ts -@@ -29,27 +29,29 @@ export const createFunction = ( +@@ -29,29 +29,31 @@ export const createFunction = ( */ export function stringifyFunction(fn: (...args: never) => unknown): string { let value = fn.toString(); @@ -377,3 +393,5 @@ index ae0f161c6d9..f0d5ae5f40c 100644 + ? `((__name => (${value}))(t => t))` + : value; } + + /** diff --git a/submodules/puppeteer b/submodules/puppeteer index 2f1762200..88b517ab3 160000 --- a/submodules/puppeteer +++ b/submodules/puppeteer @@ -1 +1 @@ -Subproject commit 2f176220024de0238d850d64aa6b07cb1e9b8e93 +Subproject commit 88b517ab3beb4a237b541cd18ada98ba43de71a7 From 1f5bbae0c8a9a931593344886e0b682bc6a9c7b6 Mon Sep 17 00:00:00 2001 From: Rui Figueira Date: Thu, 22 Oct 2026 12:59:37 +0100 Subject: [PATCH 2/6] docs(puppeteer): document the Node.js compatibility requirement MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit State that @cloudflare/puppeteer needs Node.js compatibility: on by default for compatibility dates of 2026-08-04 or later, and the nodejs_compat flag for earlier dates. Also document that file options (screenshot/pdf/tracing `path`) use the Workers virtual file system. They need a compatibility date of 2025-09-01 or later, or the enable_nodejs_fs_module flag, and files written to /tmp exist only for the current request. beep-boop-🤖 --- packages/puppeteer-cloudflare/README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/packages/puppeteer-cloudflare/README.md b/packages/puppeteer-cloudflare/README.md index 7fed401b3..b7255f8ed 100644 --- a/packages/puppeteer-cloudflare/README.md +++ b/packages/puppeteer-cloudflare/README.md @@ -16,13 +16,31 @@ npm install @cloudflare/puppeteer ## Configuration +`@cloudflare/puppeteer` needs [Node.js compatibility](https://developers.cloudflare.com/workers/runtime-apis/nodejs/#get-started). For a `compatibility_date` of `2026-08-04` or later, Workers enables Node.js compatibility by default. For an earlier date, you must add the `nodejs_compat` compatibility flag. + Add a browser binding to your Wrangler configuration: ```toml +compatibility_date = "2026-08-04" +browser = { binding = "MYBROWSER" } +``` + +If your `compatibility_date` is earlier than `2026-08-04`, also add the `nodejs_compat` flag: + +```toml +compatibility_date = "2026-08-03" compatibility_flags = ["nodejs_compat"] browser = { binding = "MYBROWSER" } ``` +Do not add the `no_nodejs_compat` flag. The package does not work without Node.js compatibility. + +### File options + +Options that read or write files use the [Workers virtual file system](https://developers.cloudflare.com/workers/runtime-apis/nodejs/fs/). Examples are `page.screenshot({path})`, `page.pdf({path})`, and `tracing.start({path})`. These options need a `compatibility_date` of `2025-09-01` or later, or the `enable_nodejs_fs_module` flag. + +Write files to `/tmp`. Files in `/tmp` exist only for the current request. + ## TypeScript The package types use the Browser Run types of the Workers runtime, for example `BrowserRun` and `BrowserRunAcquireGuardrails`. Your project gets these types from `wrangler types` with Wrangler 4.134.0 or later, or from `@cloudflare/workers-types` 5.20260917.1 or later. From d46b8786d28b97e7eabd38ddda1d931e3c9e3e41 Mon Sep 17 00:00:00 2001 From: Rui Figueira Date: Wed, 28 Oct 2026 10:12:58 +0000 Subject: [PATCH 3/6] fix(puppeteer): match output path globs inside dot directories MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit picomatch skips dot segments for `**` by default. When the repository lives under a dot directory (for example ~/.herdr/worktrees/...), no path mapping matched and vite fell back to `[name].js`. The build then wrote the modules to lib/submodules/... and lib/packages/... instead of lib/puppeteer-core/... and lib/puppeteer-cloudflare/..., so the `./internal/*` export pointed at type declarations only. Set `dot: true` so the mappings match any absolute path. beep-boop-🤖 --- packages/puppeteer-cloudflare/vite.config.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/puppeteer-cloudflare/vite.config.ts b/packages/puppeteer-cloudflare/vite.config.ts index d412eeca5..1f906ef76 100644 --- a/packages/puppeteer-cloudflare/vite.config.ts +++ b/packages/puppeteer-cloudflare/vite.config.ts @@ -18,7 +18,7 @@ const pathMappings = [ // Pre-compile globs to regexes (capture: true creates capture groups for **/*) const compiledMappings = pathMappings.map(({ glob, target }) => ({ - regex: picomatch.makeRe(glob, { capture: true }), + regex: picomatch.makeRe(glob, { capture: true, dot: true }), target, })); From 16dcaa9d7006415ce4596ff717d3cc62db7d160a Mon Sep 17 00:00:00 2001 From: Rui Figueira Date: Wed, 28 Oct 2026 10:14:54 +0000 Subject: [PATCH 4/6] test(puppeteer): use Browser.connected instead of isConnected() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit puppeteer v25 removed the deprecated Browser.isConnected() method (upstream f2cdffc4d4d). The keep_alive session test still called it, so it would fail at runtime with "browser.isConnected is not a function". wrangler bundles the tests without a type check, so test:bundle did not catch it. beep-boop-🤖 --- .../tests/src/browser-rendering/session-management.spec.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/puppeteer-cloudflare/tests/src/browser-rendering/session-management.spec.ts b/packages/puppeteer-cloudflare/tests/src/browser-rendering/session-management.spec.ts index 8edeaab0f..e1e20d8d8 100644 --- a/packages/puppeteer-cloudflare/tests/src/browser-rendering/session-management.spec.ts +++ b/packages/puppeteer-cloudflare/tests/src/browser-rendering/session-management.spec.ts @@ -336,13 +336,13 @@ test(`should keep a connected session open past keep_alive`, async () => { return setTimeout(resolve, 11000); }); await fetchSingleSession(env.BROWSER, sessionId); - expect(browser.isConnected()).toBe(true); + expect(browser.connected).toBe(true); await new Promise(resolve => { return setTimeout(resolve, 5000); }); await fetchSingleSession(env.BROWSER, sessionId); - expect(browser.isConnected()).toBe(true); + expect(browser.connected).toBe(true); } finally { await browser.close().catch(() => {}); } From c4badc973cd4bdc52582d2b4b5efef1bfd4b7c7b Mon Sep 17 00:00:00 2001 From: Rui Figueira Date: Wed, 28 Oct 2026 10:17:27 +0000 Subject: [PATCH 5/6] chore(puppeteer): drop the unused debug dependency MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit puppeteer-core v25 no longer uses the `debug` package (upstream 94d1e1c3dc8). Its Debug.ts uses util.debuglog in Node and console.log elsewhere. Nothing in the @cloudflare/puppeteer build imports `debug` now, so remove `debug` and `@types/debug` from the dependencies and drop the vite external. beep-boop-🤖 --- package-lock.json | 40 ------------------- packages/puppeteer-cloudflare/package.json | 2 - .../tests/package-lock.json | 32 --------------- packages/puppeteer-cloudflare/vite.config.ts | 1 - 4 files changed, 75 deletions(-) diff --git a/package-lock.json b/package-lock.json index c1218f3e8..4c411a030 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8127,9 +8127,7 @@ "version": "1.5.0-rc.0", "license": "Apache-2.0", "dependencies": { - "@types/debug": "^4.1.12", "@types/node": "^18.17.15", - "debug": "^4.4.3", "devtools-protocol": "0.0.1666840", "mitt": "3.0.1", "parsel-js": "1.2.2", @@ -8143,21 +8141,6 @@ "wrangler": "4.137.0" } }, - "packages/puppeteer-cloudflare/node_modules/@types/debug": { - "version": "4.1.13", - "resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.13.tgz", - "integrity": "sha512-KSVgmQmzMwPlmtljOomayoR89W4FynCAi3E8PPs7vmDVPe84hT+vGPKkJfThkmXs0x0jAaa9U8uW8bbfyS2fWw==", - "license": "MIT", - "dependencies": { - "@types/ms": "*" - } - }, - "packages/puppeteer-cloudflare/node_modules/@types/debug/node_modules/@types/ms": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@types/ms/-/ms-2.1.0.tgz", - "integrity": "sha512-GsCCIZDE/p3i96vtEqx+7dBUGXrc7zeSK3wwPHIaRThS+9OhWIXRqzs4d6k1SVU8g91DrNRWxWUGhp5KXQb2VA==", - "license": "MIT" - }, "packages/puppeteer-cloudflare/node_modules/@types/node": { "version": "18.19.130", "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.130.tgz", @@ -8173,29 +8156,6 @@ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", "license": "MIT" }, - "packages/puppeteer-cloudflare/node_modules/debug": { - "version": "4.4.3", - "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", - "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "packages/puppeteer-cloudflare/node_modules/debug/node_modules/ms": { - "version": "2.1.3", - "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", - "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "license": "MIT" - }, "packages/puppeteer-cloudflare/node_modules/devtools-protocol": { "version": "0.0.1666840", "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1666840.tgz", diff --git a/packages/puppeteer-cloudflare/package.json b/packages/puppeteer-cloudflare/package.json index 23c57b29a..60e2903c8 100644 --- a/packages/puppeteer-cloudflare/package.json +++ b/packages/puppeteer-cloudflare/package.json @@ -50,9 +50,7 @@ "test:merge": "cd tests && npx playwright merge-reports --reporter html ./all-blob-reports" }, "dependencies": { - "@types/debug": "^4.1.12", "@types/node": "^18.17.15", - "debug": "^4.4.3", "devtools-protocol": "0.0.1666840", "mitt": "3.0.1", "parsel-js": "1.2.2", diff --git a/packages/puppeteer-cloudflare/tests/package-lock.json b/packages/puppeteer-cloudflare/tests/package-lock.json index 5053ccae7..8f51d0721 100644 --- a/packages/puppeteer-cloudflare/tests/package-lock.json +++ b/packages/puppeteer-cloudflare/tests/package-lock.json @@ -29,9 +29,7 @@ "version": "1.5.0-rc.0", "license": "Apache-2.0", "dependencies": { - "@types/debug": "^4.1.12", "@types/node": "^18.17.15", - "debug": "^4.4.3", "devtools-protocol": "0.0.1666840", "mitt": "3.0.1", "parsel-js": "1.2.2", @@ -52,17 +50,6 @@ "vite": "^6.4.3" } }, - "../node_modules/@types/debug": { - "version": "4.1.13", - "license": "MIT", - "dependencies": { - "@types/ms": "*" - } - }, - "../node_modules/@types/debug/node_modules/@types/ms": { - "version": "2.1.0", - "license": "MIT" - }, "../node_modules/@types/node": { "version": "18.19.130", "license": "MIT", @@ -74,25 +61,6 @@ "version": "5.26.5", "license": "MIT" }, - "../node_modules/debug": { - "version": "4.4.3", - "license": "MIT", - "dependencies": { - "ms": "^2.1.3" - }, - "engines": { - "node": ">=6.0" - }, - "peerDependenciesMeta": { - "supports-color": { - "optional": true - } - } - }, - "../node_modules/debug/node_modules/ms": { - "version": "2.1.3", - "license": "MIT" - }, "../node_modules/devtools-protocol": { "version": "0.0.1666840", "license": "BSD-3-Clause" diff --git a/packages/puppeteer-cloudflare/vite.config.ts b/packages/puppeteer-cloudflare/vite.config.ts index 1f906ef76..747bdd5f3 100644 --- a/packages/puppeteer-cloudflare/vite.config.ts +++ b/packages/puppeteer-cloudflare/vite.config.ts @@ -143,7 +143,6 @@ export default defineConfig({ 'node:url', 'node:util', 'node:zlib', - 'debug', 'cloudflare:workers', /^chromium-bidi\/.*/, /^devtools-protocol\/.*/, From 5350cbbb51f38a47a1137b8184c0a27c01a27526 Mon Sep 17 00:00:00 2001 From: Rui Figueira Date: Wed, 28 Oct 2026 10:19:17 +0000 Subject: [PATCH 6/6] fix(puppeteer): update skipTests for the upstream v25 test suite MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit puppeteer v25 renamed its test files from *.spec.ts to *.test.ts. The skip list matches on the full title, and the full title starts with the test file path, so none of the 129 entries matched any more. The full suite would run every test that the list is meant to skip. Rename the file part of each entry. Every entry still resolves to an existing file and test title in puppeteer-v25.10.0. Also skip four new v25 tests that Browser Run cannot run: - Two network restriction tests and one dialog test connect a second client with browser.wsEndpoint(). Browser Run connects through the binding and a session ID, so puppeteer.connect() rejects the options. The skip list already skips the OOPIF reconnect tests for this reason. - Page.record uses Page.startScreenRecording, which is not available before Chrome 153. Puppeteer's TestExpectations.json also expects this test to fail on Chrome. beep-boop-🤖 --- .../tests/src/skipTests.ts | 269 +++++++++--------- 1 file changed, 140 insertions(+), 129 deletions(-) diff --git a/packages/puppeteer-cloudflare/tests/src/skipTests.ts b/packages/puppeteer-cloudflare/tests/src/skipTests.ts index 78de1bd20..4ed40a6b5 100644 --- a/packages/puppeteer-cloudflare/tests/src/skipTests.ts +++ b/packages/puppeteer-cloudflare/tests/src/skipTests.ts @@ -3,164 +3,175 @@ export const skipTests: string[] = [ // newer. Chrome 128 ignores windowBounds/background, lacks setContentsSize, // reports the fixed iframe element as non-clickable, and accepts the inline // script despite the Worker-hosted CSP setup. - "page.spec.ts > Page > Page.newPage > should open pages in a new window at the specified position", - "page.spec.ts > Page > Page.newPage > should open pages in a new window in maximized state", - "page.spec.ts > Page > Page.resize > should resize the browser window to fit page content", - "page.spec.ts > Page > Page.newPage > should create a background page", - "click.spec.ts > Page.click > should click the button with fixed position inside an iframe", - "page.spec.ts > Page > Page.addScriptTag > should throw when added with content to the CSP page", + "page.test.ts > Page > Page.newPage > should open pages in a new window at the specified position", + "page.test.ts > Page > Page.newPage > should open pages in a new window in maximized state", + "page.test.ts > Page > Page.resize > should resize the browser window to fit page content", + "page.test.ts > Page > Page.newPage > should create a background page", + "click.test.ts > Page.click > should click the button with fixed position inside an iframe", + "page.test.ts > Page > Page.addScriptTag > should throw when added with content to the CSP page", // Browser Run page navigator.userAgent returns Cloudflare-Workers, while CDP // Browser.getVersion and request headers use the stock or overridden Chrome // UA. The page UA ignores explicit UA overrides, although platform overrides // work, so upstream platform consistency, device emulation, and reset // assertions cannot hold. - "page.spec.ts > Page > Page.setUserAgent > should work with platform option without userAgent", - "page.spec.ts > Page > Page.setUserAgent > should restore original", - "page.spec.ts > Page > Page.setUserAgent > should emulate device user-agent", + "page.test.ts > Page > Page.setUserAgent > should work with platform option without userAgent", + "page.test.ts > Page > Page.setUserAgent > should restore original", + "page.test.ts > Page > Page.setUserAgent > should emulate device user-agent", // These match Puppeteer's own TestExpectations.json. This Worker runner // cannot represent expected failures, so it records them as explicit skips. - "coverage.spec.ts > Coverage specs > JSCoverage > should not hang when there is a debugger statement", - "evaluation.spec.ts > Evaluation specs > Page.evaluate > should transfer RegEx", - "evaluation.spec.ts > Evaluation specs > Page.evaluate > should return RegEx", - "navigation.spec.ts > navigation > Page.goto > should work when navigating to a URL with a client redirect", + "coverage.test.ts > Coverage specs > JSCoverage > should not hang when there is a debugger statement", + "evaluation.test.ts > Evaluation specs > Page.evaluate > should transfer RegEx", + "evaluation.test.ts > Evaluation specs > Page.evaluate > should return RegEx", + "navigation.test.ts > navigation > Page.goto > should work when navigating to a URL with a client redirect", - "oopif.spec.ts > OOPIF > should treat OOP iframes and normal iframes the same", - "oopif.spec.ts > OOPIF > should track navigations within OOP iframes", - "oopif.spec.ts > OOPIF > should support OOP iframes becoming normal iframes again", - "oopif.spec.ts > OOPIF > should support frames within OOP frames", - "oopif.spec.ts > OOPIF > should recover cross-origin frames on reconnect", - "oopif.spec.ts > OOPIF > should support OOP iframes getting detached", - "oopif.spec.ts > OOPIF > should support wait for navigation for transitions from local to OOPIF", - "oopif.spec.ts > OOPIF > should keep track of a frames OOP state", - "oopif.spec.ts > OOPIF > should support evaluating in oop iframes", - "oopif.spec.ts > OOPIF > should provide access to elements", - "oopif.spec.ts > OOPIF > should report oopif frames", - "oopif.spec.ts > OOPIF > should wait for inner OOPIFs", - "oopif.spec.ts > OOPIF > should load oopif iframes with subresources and request interception", - "oopif.spec.ts > OOPIF > should support frames within OOP iframes", - "oopif.spec.ts > OOPIF > clickablePoint, boundingBox, boxModel should work for elements inside OOPIFs", - "oopif.spec.ts > OOPIF > should detect existing OOPIFs when Puppeteer connects to an existing page", - "oopif.spec.ts > OOPIF > should support lazy OOP frames", - "oopif.spec.ts > OOPIF > should exposeFunction on a page with a PDF viewer", - "oopif.spec.ts > OOPIF > should evaluate on a page with a PDF viewer", - "oopif.spec.ts > OOPIF > should support evaluateOnNewDocument", - "oopif.spec.ts > OOPIF > should support removing evaluateOnNewDocument scripts", - "oopif.spec.ts > OOPIF > should support exposeFunction", - "oopif.spec.ts > OOPIF > should support removing exposed function", - "oopif.spec.ts > OOPIF > waitForFrame > should resolve immediately if the frame already exists", - "oopif.spec.ts > OOPIF > should report google.com frame", - "oopif.spec.ts > OOPIF > should expose events within OOPIFs", - "page.spec.ts > Page > Page.setUserAgent > should work", - "page.spec.ts > Page > Page.setUserAgent > should work for subframes", - "page.spec.ts > Page > Page.addScriptTag > should work with a path and type=module", - "page.spec.ts > Page > Page.addScriptTag > should work with a path", - "page.spec.ts > Page > Page.addScriptTag > should include sourcemap when path is provided", - "page.spec.ts > Page > Page.addStyleTag > should work with a path", - "page.spec.ts > Page > Page.addStyleTag > should include sourcemap when path is provided", - "elementhandle.spec.ts > ElementHandle specs > ElementHandle[Symbol.dispose] > should work", - "elementhandle.spec.ts > ElementHandle specs > ElementHandle[Symbol.asyncDispose] > should work", - "elementhandle.spec.ts > ElementHandle specs > ElementHandle.move > should work", - "cookies.spec.ts > Cookie specs > Page.cookies > should get a cookie", - "cookies.spec.ts > Cookie specs > Page.cookies > should get multiple cookies", - "cookies.spec.ts > Cookie specs > Page.setCookie > should set cookie with reasonable defaults", - "cookies.spec.ts > Cookie specs > Page.setCookie > should set a cookie with a path", - "cookies.spec.ts > Cookie specs > Page.setCookie > should set cookies from a frame", - "cookies.spec.ts > Cookie specs > Page.deleteCookie > should delete cookie for specified URL", - "locator.spec.ts > Locator > Locator.click > should time out", - "locator.spec.ts > Locator > Locator.click > should retry clicks on errors", - "locator.spec.ts > Locator > Locator.click > can be aborted", - "locator.spec.ts > Locator > Locator.race > can be aborted", - "locator.spec.ts > Locator > Locator.race > should time out when all locators do not match", - "locator.spec.ts > Locator > Locator.prototype.filter > should resolve as soon as the predicate matches", - "navigation.spec.ts > navigation > Page.goto > should fail when navigating to bad SSL", + "oopif.test.ts > OOPIF > should treat OOP iframes and normal iframes the same", + "oopif.test.ts > OOPIF > should track navigations within OOP iframes", + "oopif.test.ts > OOPIF > should support OOP iframes becoming normal iframes again", + "oopif.test.ts > OOPIF > should support frames within OOP frames", + "oopif.test.ts > OOPIF > should recover cross-origin frames on reconnect", + "oopif.test.ts > OOPIF > should support OOP iframes getting detached", + "oopif.test.ts > OOPIF > should support wait for navigation for transitions from local to OOPIF", + "oopif.test.ts > OOPIF > should keep track of a frames OOP state", + "oopif.test.ts > OOPIF > should support evaluating in oop iframes", + "oopif.test.ts > OOPIF > should provide access to elements", + "oopif.test.ts > OOPIF > should report oopif frames", + "oopif.test.ts > OOPIF > should wait for inner OOPIFs", + "oopif.test.ts > OOPIF > should load oopif iframes with subresources and request interception", + "oopif.test.ts > OOPIF > should support frames within OOP iframes", + "oopif.test.ts > OOPIF > clickablePoint, boundingBox, boxModel should work for elements inside OOPIFs", + "oopif.test.ts > OOPIF > should detect existing OOPIFs when Puppeteer connects to an existing page", + "oopif.test.ts > OOPIF > should support lazy OOP frames", + "oopif.test.ts > OOPIF > should exposeFunction on a page with a PDF viewer", + "oopif.test.ts > OOPIF > should evaluate on a page with a PDF viewer", + "oopif.test.ts > OOPIF > should support evaluateOnNewDocument", + "oopif.test.ts > OOPIF > should support removing evaluateOnNewDocument scripts", + "oopif.test.ts > OOPIF > should support exposeFunction", + "oopif.test.ts > OOPIF > should support removing exposed function", + "oopif.test.ts > OOPIF > waitForFrame > should resolve immediately if the frame already exists", + "oopif.test.ts > OOPIF > should report google.com frame", + "oopif.test.ts > OOPIF > should expose events within OOPIFs", + "page.test.ts > Page > Page.setUserAgent > should work", + "page.test.ts > Page > Page.setUserAgent > should work for subframes", + "page.test.ts > Page > Page.addScriptTag > should work with a path and type=module", + "page.test.ts > Page > Page.addScriptTag > should work with a path", + "page.test.ts > Page > Page.addScriptTag > should include sourcemap when path is provided", + "page.test.ts > Page > Page.addStyleTag > should work with a path", + "page.test.ts > Page > Page.addStyleTag > should include sourcemap when path is provided", + "elementhandle.test.ts > ElementHandle specs > ElementHandle[Symbol.dispose] > should work", + "elementhandle.test.ts > ElementHandle specs > ElementHandle[Symbol.asyncDispose] > should work", + "elementhandle.test.ts > ElementHandle specs > ElementHandle.move > should work", + "cookies.test.ts > Cookie specs > Page.cookies > should get a cookie", + "cookies.test.ts > Cookie specs > Page.cookies > should get multiple cookies", + "cookies.test.ts > Cookie specs > Page.setCookie > should set cookie with reasonable defaults", + "cookies.test.ts > Cookie specs > Page.setCookie > should set a cookie with a path", + "cookies.test.ts > Cookie specs > Page.setCookie > should set cookies from a frame", + "cookies.test.ts > Cookie specs > Page.deleteCookie > should delete cookie for specified URL", + "locator.test.ts > Locator > Locator.click > should time out", + "locator.test.ts > Locator > Locator.click > should retry clicks on errors", + "locator.test.ts > Locator > Locator.click > can be aborted", + "locator.test.ts > Locator > Locator.race > can be aborted", + "locator.test.ts > Locator > Locator.race > should time out when all locators do not match", + "locator.test.ts > Locator > Locator.prototype.filter > should resolve as soon as the predicate matches", + "navigation.test.ts > navigation > Page.goto > should fail when navigating to bad SSL", // Workers.dev always presents valid managed TLS, so the remote TestServer // cannot provide the invalid certificate required by this upstream test. - "navigation.spec.ts > navigation > Page.goto > should fail when navigating to bad SSL after redirects", - "navigation.spec.ts > navigation > Page.goto > should not leak listeners during navigation", - "navigation.spec.ts > navigation > Page.goto > should not leak listeners during bad navigation", - "navigation.spec.ts > navigation > Page.goto > should not leak listeners during navigation of 11 pages", - "navigation.spec.ts > navigation > Page.goto > should fail when navigating and show the url at the error message", - "coverage.spec.ts > Coverage specs > JSCoverage > should work with conditionals", - "coverage.spec.ts > Coverage specs > CSSCoverage > should work with complicated usecases", - "evaluation.spec.ts > Evaluation specs > Page.evaluate > should replace symbols with undefined", - "evaluation.spec.ts > Evaluation specs > Page.evaluate > should work for circular object", - "evaluation.spec.ts > Evaluation specs > Page.evaluate > should transfer 100Mb of data from page to node.js", - "evaluation.spec.ts > Evaluation specs > Page.evaluate > should return properly serialize objects with unknown type fields", - "jshandle.spec.ts > JSHandle > JSHandle.toString > should work with window subtypes", - "jshandle.spec.ts > JSHandle > JSHandle[Symbol.dispose] > should work", - "jshandle.spec.ts > JSHandle > JSHandle[Symbol.asyncDispose] > should work", - "jshandle.spec.ts > JSHandle > JSHandle.move > should work", - "dialog.spec.ts > Page.Events.Dialog > should fire", - "dialog.spec.ts > Page.Events.Dialog > should allow accepting prompts", - "frame.spec.ts > Frame specs > Frame Management > should handle nested frames", - "input.spec.ts > input tests > ElementHandle.uploadFile > should read the file", - "input.spec.ts > input tests > FileChooser.accept > should be able to read selected file", - "mouse.spec.ts > Mouse > should not throw if buttons are pressed twice", - "mouse.spec.ts > Mouse > should reset properly", - "drag-and-drop.spec.ts > Drag n' Drop > should drag and drop", - "keyboard.spec.ts > Keyboard > should send a character with sendCharacter in iframe", - "jshandle.spec.ts > JSHandle > JSHandle.jsonValue > should work with dates", - "jshandle.spec.ts > JSHandle > JSHandle.jsonValue > should not throw for circular objects", - "keyboard.spec.ts > Keyboard > ElementHandle.press should not support |text| option", - "page.spec.ts > Page > Page.pdf > can print to PDF and save to file", + "navigation.test.ts > navigation > Page.goto > should fail when navigating to bad SSL after redirects", + "navigation.test.ts > navigation > Page.goto > should not leak listeners during navigation", + "navigation.test.ts > navigation > Page.goto > should not leak listeners during bad navigation", + "navigation.test.ts > navigation > Page.goto > should not leak listeners during navigation of 11 pages", + "navigation.test.ts > navigation > Page.goto > should fail when navigating and show the url at the error message", + "coverage.test.ts > Coverage specs > JSCoverage > should work with conditionals", + "coverage.test.ts > Coverage specs > CSSCoverage > should work with complicated usecases", + "evaluation.test.ts > Evaluation specs > Page.evaluate > should replace symbols with undefined", + "evaluation.test.ts > Evaluation specs > Page.evaluate > should work for circular object", + "evaluation.test.ts > Evaluation specs > Page.evaluate > should transfer 100Mb of data from page to node.js", + "evaluation.test.ts > Evaluation specs > Page.evaluate > should return properly serialize objects with unknown type fields", + "jshandle.test.ts > JSHandle > JSHandle.toString > should work with window subtypes", + "jshandle.test.ts > JSHandle > JSHandle[Symbol.dispose] > should work", + "jshandle.test.ts > JSHandle > JSHandle[Symbol.asyncDispose] > should work", + "jshandle.test.ts > JSHandle > JSHandle.move > should work", + "dialog.test.ts > Page.Events.Dialog > should fire", + "dialog.test.ts > Page.Events.Dialog > should allow accepting prompts", + "frame.test.ts > Frame specs > Frame Management > should handle nested frames", + "input.test.ts > input tests > ElementHandle.uploadFile > should read the file", + "input.test.ts > input tests > FileChooser.accept > should be able to read selected file", + "mouse.test.ts > Mouse > should not throw if buttons are pressed twice", + "mouse.test.ts > Mouse > should reset properly", + "drag-and-drop.test.ts > Drag n' Drop > should drag and drop", + "keyboard.test.ts > Keyboard > should send a character with sendCharacter in iframe", + "jshandle.test.ts > JSHandle > JSHandle.jsonValue > should work with dates", + "jshandle.test.ts > JSHandle > JSHandle.jsonValue > should not throw for circular objects", + "keyboard.test.ts > Keyboard > ElementHandle.press should not support |text| option", + "page.test.ts > Page > Page.pdf > can print to PDF and save to file", // Browser Run shares a remote browser session across tests. Crashing a page // destroys that session rather than only the target under test. - "page.spec.ts > Page > Page.Events.error > should throw when page crashes", + "page.test.ts > Page > Page.Events.error > should throw when page crashes", // Worker isolates disable dynamic code generation. Puppeteer's custom query // registration path compiles user handlers with Function constructors. - "elementhandle.spec.ts > ElementHandle specs > Custom queries > should register and unregister", - "elementhandle.spec.ts > ElementHandle specs > Custom queries > should work for multiple elements", - "elementhandle.spec.ts > ElementHandle specs > Custom queries > should eval correctly", - "elementhandle.spec.ts > ElementHandle specs > Custom queries > should wait correctly with waitForSelector", - "elementhandle.spec.ts > ElementHandle specs > Custom queries > should wait correctly with waitForSelector on an element", - "elementhandle.spec.ts > ElementHandle specs > Custom queries > should work when both queryOne and queryAll are registered", - "elementhandle.spec.ts > ElementHandle specs > Custom queries > should eval when both queryOne and queryAll are registered", - "elementhandle.spec.ts > ElementHandle specs > Custom queries > should work with function shorthands", - "queryhandler.spec.ts > Query handler tests > Text selectors > in Page > should query existing element", - "queryhandler.spec.ts > Query handler tests > Text selectors > in Page > should return empty array for non-existing element", - "queryhandler.spec.ts > Query handler tests > Text selectors > in Page > should return first element", - "queryhandler.spec.ts > Query handler tests > Text selectors > in Page > should pierce shadow DOM", - "queryhandler.spec.ts > Query handler tests > Text selectors > in Page > should query deeply nested text", - "queryhandler.spec.ts > Query handler tests > Text selectors > in Page > should query inputs", - "queryhandler.spec.ts > Query handler tests > Text selectors > in Page > should not query radio", - "queryhandler.spec.ts > Query handler tests > Text selectors > in Page > should query text spanning multiple elements", - "queryhandler.spec.ts > Query handler tests > Text selectors > in Page > should clear caches", - "queryhandler.spec.ts > Query handler tests > Text selectors > in ElementHandles > should query existing element", - "queryhandler.spec.ts > Query handler tests > Text selectors > in ElementHandles > should return null for non-existing element", - "queryhandler.spec.ts > Query handler tests > P selectors > should work with custom selectors", - "queryhandler.spec.ts > Query handler tests > P selectors > should work with custom selectors with args", - "queryselector.spec.ts > querySelector > QueryAll > should have registered handler", - "queryselector.spec.ts > querySelector > QueryAll > $$ should query existing elements", - "queryselector.spec.ts > querySelector > QueryAll > $$ should return empty array for non-existing elements", - "queryselector.spec.ts > querySelector > QueryAll > $$eval should work", - "queryselector.spec.ts > querySelector > QueryAll > $$eval should accept extra arguments", - "queryselector.spec.ts > querySelector > QueryAll > $$eval should accept ElementHandles as arguments", - "queryselector.spec.ts > querySelector > QueryAll > $$eval should handle many elements", + "elementhandle.test.ts > ElementHandle specs > Custom queries > should register and unregister", + "elementhandle.test.ts > ElementHandle specs > Custom queries > should work for multiple elements", + "elementhandle.test.ts > ElementHandle specs > Custom queries > should eval correctly", + "elementhandle.test.ts > ElementHandle specs > Custom queries > should wait correctly with waitForSelector", + "elementhandle.test.ts > ElementHandle specs > Custom queries > should wait correctly with waitForSelector on an element", + "elementhandle.test.ts > ElementHandle specs > Custom queries > should work when both queryOne and queryAll are registered", + "elementhandle.test.ts > ElementHandle specs > Custom queries > should eval when both queryOne and queryAll are registered", + "elementhandle.test.ts > ElementHandle specs > Custom queries > should work with function shorthands", + "queryhandler.test.ts > Query handler tests > Text selectors > in Page > should query existing element", + "queryhandler.test.ts > Query handler tests > Text selectors > in Page > should return empty array for non-existing element", + "queryhandler.test.ts > Query handler tests > Text selectors > in Page > should return first element", + "queryhandler.test.ts > Query handler tests > Text selectors > in Page > should pierce shadow DOM", + "queryhandler.test.ts > Query handler tests > Text selectors > in Page > should query deeply nested text", + "queryhandler.test.ts > Query handler tests > Text selectors > in Page > should query inputs", + "queryhandler.test.ts > Query handler tests > Text selectors > in Page > should not query radio", + "queryhandler.test.ts > Query handler tests > Text selectors > in Page > should query text spanning multiple elements", + "queryhandler.test.ts > Query handler tests > Text selectors > in Page > should clear caches", + "queryhandler.test.ts > Query handler tests > Text selectors > in ElementHandles > should query existing element", + "queryhandler.test.ts > Query handler tests > Text selectors > in ElementHandles > should return null for non-existing element", + "queryhandler.test.ts > Query handler tests > P selectors > should work with custom selectors", + "queryhandler.test.ts > Query handler tests > P selectors > should work with custom selectors with args", + "queryselector.test.ts > querySelector > QueryAll > should have registered handler", + "queryselector.test.ts > querySelector > QueryAll > $$ should query existing elements", + "queryselector.test.ts > querySelector > QueryAll > $$ should return empty array for non-existing elements", + "queryselector.test.ts > querySelector > QueryAll > $$eval should work", + "queryselector.test.ts > querySelector > QueryAll > $$eval should accept extra arguments", + "queryselector.test.ts > querySelector > QueryAll > $$eval should accept ElementHandles as arguments", + "queryselector.test.ts > querySelector > QueryAll > $$eval should handle many elements", // These assertions depend on localhost URLs, socket failure modes, or // redirect history that the deployed workers.dev TestServer cannot match. - "evaluation.spec.ts > Evaluation specs > Frame.evaluate > should execute after cross-site navigation", - "navigation.spec.ts > navigation > Page.goto > should fail when main resources failed to load", - "navigation.spec.ts > navigation > Page.goBack > should work", + "evaluation.test.ts > Evaluation specs > Frame.evaluate > should execute after cross-site navigation", + "navigation.test.ts > navigation > Page.goto > should fail when main resources failed to load", + "navigation.test.ts > navigation > Page.goBack > should work", // Browser Run returns concrete CdpCDPSession objects from the bundled copy; // they cannot satisfy instanceof checks against the test bundle's copy. - "frame.spec.ts > Frame specs > Frame.client > should return the client instance", - "page.spec.ts > Page > Page.client > should return the client instance", + "frame.test.ts > Frame specs > Frame.client > should return the client instance", + "page.test.ts > Page > Page.client > should return the client instance", // The Worker bundle renames the injected helper, so createFunction3 is not // available under the identifier expected by this direct utility test. - "injected.spec.ts > PuppeteerUtil tests > createFunction tests > should work", + "injected.test.ts > PuppeteerUtil tests > createFunction tests > should work", // Serialized race candidates lose the concrete locator type required by // Locator.race and produce "Unknown locator for race candidate". - "locator.spec.ts > Locator > Locator.race > races multiple locators", - "locator.spec.ts > Locator > Locator.race > should not time out when one of the locators matches", + "locator.test.ts > Locator > Locator.race > races multiple locators", + "locator.test.ts > Locator > Locator.race > should not time out when one of the locators matches", // The generated Worker test has no Mocha context for this.timeout(). - "queryselector.spec.ts > querySelector > Page.$$eval > should handle many elements", + "queryselector.test.ts > querySelector > Page.$$eval > should handle many elements", // Bundling removes the source filename that this test requires in the stack. - "page.spec.ts > Page > Page.exposeFunction > should throw exception in page context", + "page.test.ts > Page > Page.exposeFunction > should throw exception in page context", + + // These tests connect a second client with browser.wsEndpoint(). Browser + // Run connects through the binding and a session ID, so the endpoint is + // empty and puppeteer.connect() rejects the options. + "cdp/network_restrictions.test.ts > Network Restrictions > should detach from targets violating blocklist when connecting to a running browser", + "cdp/network_restrictions.test.ts > Network Restrictions > should detach from targets violating allowlist when connecting to a running browser", + "dialog.test.ts > Page.Events.Dialog > should see dialogs handled by other connections", + + // Page.startScreenRecording is not available before Chrome 153. This matches + // Puppeteer's own TestExpectations.json. + "page.test.ts > Page > Page.record > should record page", ];