Skip to content

Commit be32317

Browse files
authored
feat: add an option to return base64 from page.screenshot (#5993)
1 parent 62aa720 commit be32317

File tree

5 files changed

+74
-23
lines changed

5 files changed

+74
-23
lines changed

docs/guide/browser.md

+7-3
Original file line numberDiff line numberDiff line change
@@ -465,12 +465,16 @@ export const page: {
465465
/**
466466
* Change the size of iframe's viewport.
467467
*/
468-
viewport: (width: number | string, height: number | string) => Promise<void>
468+
viewport(width: number | string, height: number | string): Promise<void>
469469
/**
470470
* Make a screenshot of the test iframe or a specific element.
471-
* @returns Path to the screenshot file.
471+
* @returns Path to the screenshot file or path and base64.
472472
*/
473-
screenshot: (options?: ScreenshotOptions) => Promise<string>
473+
screenshot(options: Omit<ScreenshotOptions, 'base64'> & { base64: true }): Promise<{
474+
path: string
475+
base64: string
476+
}>
477+
screenshot(options?: ScreenshotOptions): Promise<string>
474478
}
475479

476480
export const cdp: () => CDPSession

eslint.config.js

+1
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,7 @@ export default antfu(
100100
'import/newline-after-import': 'off',
101101
'import/first': 'off',
102102
'unused-imports/no-unused-imports': 'off',
103+
'ts/method-signature-style': 'off',
103104
},
104105
},
105106
{

packages/browser/context.d.ts

+11-3
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,10 @@ export interface ScreenshotOptions {
2929
* Path relative to the `screenshotDirectory` in the test config.
3030
*/
3131
path?: string
32+
/**
33+
* Will also return the base64 encoded screenshot alongside the path.
34+
*/
35+
base64?: boolean
3236
}
3337

3438
export interface BrowserCommands {
@@ -245,12 +249,16 @@ export interface BrowserPage {
245249
/**
246250
* Change the size of iframe's viewport.
247251
*/
248-
viewport: (width: number, height: number) => Promise<void>
252+
viewport(width: number, height: number): Promise<void>
249253
/**
250254
* Make a screenshot of the test iframe or a specific element.
251-
* @returns Path to the screenshot file.
255+
* @returns Path to the screenshot file or path and base64.
252256
*/
253-
screenshot: (options?: ScreenshotOptions) => Promise<string>
257+
screenshot(options: Omit<ScreenshotOptions, 'base64'> & { base64: true }): Promise<{
258+
path: string
259+
base64: string
260+
}>
261+
screenshot(options?: ScreenshotOptions): Promise<string>
254262
}
255263

256264
export const page: BrowserPage

packages/browser/src/node/commands/screenshot.ts

+24-12
Original file line numberDiff line numberDiff line change
@@ -29,28 +29,29 @@ export const screenshot: BrowserCommand<[string, ScreenshotOptions]> = async (
2929
if (options.element) {
3030
const { element: elementXpath, ...config } = options
3131
const element = context.iframe.locator(`xpath=${elementXpath}`)
32-
await element.screenshot({ ...config, path: savePath })
32+
const buffer = await element.screenshot({ ...config, path: savePath })
33+
return returnResult(options, path, buffer)
3334
}
34-
else {
35-
await context.iframe.locator('body').screenshot({
36-
...options,
37-
path: savePath,
38-
})
39-
}
40-
return path
35+
36+
const buffer = await context.iframe.locator('body').screenshot({
37+
...options,
38+
path: savePath,
39+
})
40+
return returnResult(options, path, buffer)
4141
}
4242

4343
if (context.provider instanceof WebdriverBrowserProvider) {
4444
const page = context.provider.browser!
4545
if (!options.element) {
4646
const body = await page.$('body')
47-
await body.saveScreenshot(savePath)
48-
return path
47+
const buffer = await body.saveScreenshot(savePath)
48+
return returnResult(options, path, buffer)
4949
}
50+
5051
const xpath = `//${options.element}`
5152
const element = await page.$(xpath)
52-
await element.saveScreenshot(savePath)
53-
return path
53+
const buffer = await element.saveScreenshot(savePath)
54+
return returnResult(options, path, buffer)
5455
}
5556

5657
throw new Error(
@@ -75,3 +76,14 @@ function resolveScreenshotPath(
7576
}
7677
return resolve(dir, '__screenshots__', base, name)
7778
}
79+
80+
function returnResult(
81+
options: ScreenshotOptions,
82+
path: string,
83+
buffer: Buffer,
84+
) {
85+
if (options.base64) {
86+
return { path, base64: buffer.toString('base64') }
87+
}
88+
return path
89+
}

test/browser/test/dom.test.ts

+31-5
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,19 @@
1-
import { describe, expect, test } from 'vitest'
1+
import { beforeEach, describe, expect, test } from 'vitest'
22
import { page } from '@vitest/browser/context'
33
import { createNode } from '#src/createNode'
44
import '../src/button.css'
55

66
describe('dom related activity', () => {
7-
test('renders div', async () => {
7+
beforeEach(() => {
88
document.body.style.background = '#f3f3f3'
9-
const wrapper = document.createElement('div')
10-
wrapper.className = 'wrapper'
11-
document.body.appendChild(wrapper)
9+
document.body.replaceChildren()
10+
})
11+
12+
test('renders div', async () => {
13+
const wrapper = createWrapper()
1214
const div = createNode()
1315
wrapper.appendChild(div)
16+
1417
await expect.element(div).toHaveTextContent('Hello World!')
1518
const screenshotPath = await page.screenshot({
1619
element: wrapper,
@@ -19,4 +22,27 @@ describe('dom related activity', () => {
1922
/__screenshots__\/dom.test.ts\/dom-related-activity-renders-div-1.png/,
2023
)
2124
})
25+
26+
test('resolves base64 screenshot', async () => {
27+
const wrapper = createWrapper()
28+
const div = createNode()
29+
wrapper.appendChild(div)
30+
31+
const { path, base64 } = await page.screenshot({
32+
element: wrapper,
33+
base64: true,
34+
})
35+
expect(path).toMatch(
36+
/__screenshots__\/dom.test.ts\/dom-related-activity-resolves-base64-screenshot-1.png/,
37+
)
38+
expect(base64).toBeTypeOf('string')
39+
})
2240
})
41+
42+
function createWrapper() {
43+
document.body.style.background = '#f3f3f3'
44+
const wrapper = document.createElement('div')
45+
wrapper.className = 'wrapper'
46+
document.body.appendChild(wrapper)
47+
return wrapper
48+
}

0 commit comments

Comments
 (0)