diff --git a/docs/api/puppeteer.screenshotoptions.md b/docs/api/puppeteer.screenshotoptions.md index 465711aa5e1..7f42d79458b 100644 --- a/docs/api/puppeteer.screenshotoptions.md +++ b/docs/api/puppeteer.screenshotoptions.md @@ -68,7 +68,7 @@ clip -Specifies the region of the page to clip. +Specifies the region of the page/element to clip. diff --git a/packages/puppeteer-core/src/api/ElementHandle.ts b/packages/puppeteer-core/src/api/ElementHandle.ts index 9b1326f998e..896cf5fe34d 100644 --- a/packages/puppeteer-core/src/api/ElementHandle.ts +++ b/packages/puppeteer-core/src/api/ElementHandle.ts @@ -1236,9 +1236,9 @@ export abstract class ElementHandle< this: ElementHandle, options: Readonly = {} ): Promise { - const {scrollIntoView = true} = options; + const {scrollIntoView = true, clip} = options; - let clip = await this.#nonEmptyVisibleBoundingBox(); + let elementClip = await this.#nonEmptyVisibleBoundingBox(); const page = this.frame.page(); @@ -1247,7 +1247,7 @@ export abstract class ElementHandle< await this.scrollIntoViewIfNeeded(); // We measure again just in case. - clip = await this.#nonEmptyVisibleBoundingBox(); + elementClip = await this.#nonEmptyVisibleBoundingBox(); } const [pageLeft, pageTop] = await this.evaluate(() => { @@ -1259,10 +1259,16 @@ export abstract class ElementHandle< window.visualViewport.pageTop, ] as const; }); - clip.x += pageLeft; - clip.y += pageTop; + elementClip.x += pageLeft; + elementClip.y += pageTop; + if (clip) { + elementClip.x += clip.x; + elementClip.y += clip.y; + elementClip.height = clip.height; + elementClip.width = clip.width; + } - return await page.screenshot({...options, clip}); + return await page.screenshot({...options, clip: elementClip}); } async #nonEmptyVisibleBoundingBox() { diff --git a/packages/puppeteer-core/src/api/Page.ts b/packages/puppeteer-core/src/api/Page.ts index 234745e47c9..b3d65103720 100644 --- a/packages/puppeteer-core/src/api/Page.ts +++ b/packages/puppeteer-core/src/api/Page.ts @@ -274,7 +274,7 @@ export interface ScreenshotOptions { */ path?: string; /** - * Specifies the region of the page to clip. + * Specifies the region of the page/element to clip. */ clip?: ScreenshotClip; /** diff --git a/test/golden-chrome/screenshot-element-clip.png b/test/golden-chrome/screenshot-element-clip.png new file mode 100644 index 00000000000..609952cd3d3 Binary files /dev/null and b/test/golden-chrome/screenshot-element-clip.png differ diff --git a/test/golden-firefox/screenshot-element-clip.png b/test/golden-firefox/screenshot-element-clip.png new file mode 100644 index 00000000000..609952cd3d3 Binary files /dev/null and b/test/golden-firefox/screenshot-element-clip.png differ diff --git a/test/src/screenshot.spec.ts b/test/src/screenshot.spec.ts index 9176d0c9204..9880581217b 100644 --- a/test/src/screenshot.spec.ts +++ b/test/src/screenshot.spec.ts @@ -393,6 +393,33 @@ describe('Screenshots', function () { await context.close(); }); + + it('should use element clip', async () => { + const {page} = await getTestState(); + + await page.setViewport({width: 500, height: 500}); + await page.setContent(` + something above + +
+ `); + using elementHandle = (await page.$('div'))!; + const screenshot = await elementHandle.screenshot({ + clip: { + x: 10, + y: 10, + width: 20, + height: 20, + }, + }); + expect(screenshot).toBeGolden('screenshot-element-clip.png'); + }); }); describe('Cdp', () => {