diff --git a/packages/puppeteer-core/src/api/Page.ts b/packages/puppeteer-core/src/api/Page.ts index be796c59754..b49f2bed895 100644 --- a/packages/puppeteer-core/src/api/Page.ts +++ b/packages/puppeteer-core/src/api/Page.ts @@ -2535,57 +2535,32 @@ export abstract class Page extends EventEmitter { break; } } - if (options.quality) { - assert( - options.type === 'jpeg' || options.type === 'webp', - `options.quality is unsupported for the ${options.type} screenshots` - ); - assert( - typeof options.quality === 'number', - `Expected options.quality to be a number but found ${typeof options.quality}` - ); - assert( - Number.isInteger(options.quality), - 'Expected options.quality to be an integer' - ); - assert( - options.quality >= 0 && options.quality <= 100, - `Expected options.quality to be between 0 and 100 (inclusive), got ${options.quality}` - ); + if (options.quality !== undefined) { + if (options.quality < 0 && options.quality > 100) { + throw new Error( + `Expected 'quality' (${options.quality}) to be between 0 and 100, inclusive.` + ); + } + if ( + options.type === undefined || + !['jpeg', 'webp'].includes(options.type) + ) { + throw new Error( + `${options.type ?? 'png'} screenshots do not support 'quality'.` + ); + } } assert( !options.clip || !options.fullPage, - 'options.clip and options.fullPage are exclusive' + "'clip' and 'fullPage' are exclusive" ); if (options.clip) { - assert( - typeof options.clip.x === 'number', - `Expected options.clip.x to be a number but found ${typeof options.clip - .x}` - ); - assert( - typeof options.clip.y === 'number', - `Expected options.clip.y to be a number but found ${typeof options.clip - .y}` - ); - assert( - typeof options.clip.width === 'number', - `Expected options.clip.width to be a number but found ${typeof options - .clip.width}` - ); - assert( - typeof options.clip.height === 'number', - `Expected options.clip.height to be a number but found ${typeof options - .clip.height}` - ); - assert( - options.clip.width !== 0, - 'Expected options.clip.width not to be 0.' - ); - assert( - options.clip.height !== 0, - 'Expected options.clip.height not to be 0.' - ); + if (options.clip.width <= 0) { + throw new Error("'width' in 'clip' must be positive."); + } + if (options.clip.height <= 0) { + throw new Error("'height' in 'clip' must be positive."); + } } setDefaultScreenshotOptions(options); diff --git a/packages/puppeteer-core/src/bidi/Page.ts b/packages/puppeteer-core/src/bidi/Page.ts index 31247c79b78..d715483403d 100644 --- a/packages/puppeteer-core/src/bidi/Page.ts +++ b/packages/puppeteer-core/src/bidi/Page.ts @@ -650,7 +650,8 @@ export class BidiPage extends Page { override async _screenshot( options: Readonly ): Promise { - const {clip, type, captureBeyondViewport, allowViewportExpansion} = options; + const {clip, type, captureBeyondViewport, allowViewportExpansion, quality} = + options; if (captureBeyondViewport && !allowViewportExpansion) { throw new Error( `BiDi does not support 'captureBeyondViewport'. Use 'allowViewportExpansion'.` @@ -665,12 +666,6 @@ export class BidiPage extends Page { if (options.fromSurface !== undefined && !options.fromSurface) { throw new Error(`BiDi does not support 'fromSurface'.`); } - if (options.quality !== undefined) { - throw new Error(`BiDi does not support 'quality'.`); - } - if (type === 'webp' || type === 'jpeg') { - throw new Error(`BiDi only supports 'png' type.`); - } if (clip !== undefined && clip.scale !== undefined && clip.scale !== 1) { throw new Error(`BiDi does not support 'scale' in 'clip'.`); } @@ -678,6 +673,10 @@ export class BidiPage extends Page { result: {data}, } = await this.#connection.send('browsingContext.captureScreenshot', { context: this.mainFrame()._id, + format: { + type: `image/${type}`, + ...(quality === undefined ? {} : {quality: quality / 100}), + }, clip: clip && { type: 'viewport', ...clip, diff --git a/packages/puppeteer-core/src/cdp/Page.ts b/packages/puppeteer-core/src/cdp/Page.ts index dcdb7461da3..069dcfb63c2 100644 --- a/packages/puppeteer-core/src/cdp/Page.ts +++ b/packages/puppeteer-core/src/cdp/Page.ts @@ -1091,7 +1091,7 @@ export class CdpPage extends Page { const {data} = await this.#client.send('Page.captureScreenshot', { format: type, ...(optimizeForSpeed ? {optimizeForSpeed} : {}), - ...(quality !== undefined ? {quality} : {}), + ...(quality !== undefined ? {quality: Math.round(quality)} : {}), clip: clip && { ...clip, scale: clip.scale ?? 1, diff --git a/test/src/screenshot.spec.ts b/test/src/screenshot.spec.ts index 6abcbeb44a0..49b837cdb38 100644 --- a/test/src/screenshot.spec.ts +++ b/test/src/screenshot.spec.ts @@ -357,6 +357,17 @@ describe('Screenshots', function () { const screenshot = await elementHandle.screenshot(); expect(screenshot).toBeGolden('screenshot-element-fractional-offset.png'); }); + it('should work with webp', async () => { + const {page, server} = await getTestState(); + + await page.setViewport({width: 100, height: 100}); + await page.goto(server.PREFIX + '/grid.html'); + const screenshot = await page.screenshot({ + type: 'webp', + }); + + expect(screenshot).toBeInstanceOf(Buffer); + }); }); describe('Cdp', () => { @@ -379,17 +390,6 @@ describe('Screenshots', function () { }); expect(screenshot).toBeGolden('white.jpg'); }); - it('should work with webp', async () => { - const {page, server} = await getTestState(); - - await page.setViewport({width: 100, height: 100}); - await page.goto(server.PREFIX + '/grid.html'); - const screenshot = await page.screenshot({ - type: 'webp', - }); - - expect(screenshot).toBeInstanceOf(Buffer); - }); it('should work in "fromSurface: false" mode', async () => { const {page, server} = await getTestState();