Skip to content

Commit d9f5163

Browse files
authored
feat(browser): add screenshot.save option (#7777)
1 parent b67d307 commit d9f5163

File tree

5 files changed

+56
-10
lines changed

5 files changed

+56
-10
lines changed

docs/guide/browser/context.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,11 @@ export const page: {
105105
The `getBy*` API is explained at [Locators API](/guide/browser/locators).
106106
:::
107107
108+
::: warning WARNING <Version>3.1.2</Version>
109+
Note that `screenshot` will always return a base64 string if `save` is set to `false`.
110+
The `path` is also ignored in that case.
111+
:::
112+
108113
## `cdp`
109114
110115
The `cdp` export returns the current Chrome DevTools Protocol session. It is mostly useful to library authors to build tools on top of it.

docs/guide/browser/locators.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -769,6 +769,7 @@ await languages.selectOptions([
769769
### screenshot
770770

771771
```ts
772+
function screenshot(options: LocatorScreenshotOptions & { save: false }): Promise<string>
772773
function screenshot(options: LocatorScreenshotOptions & { base64: true }): Promise<{
773774
path: string
774775
base64: string
@@ -797,6 +798,11 @@ const { path, base64 } = await button.screenshot({
797798
// bas64 - base64 encoded string of the screenshot
798799
```
799800

801+
::: warning WARNING <Version>3.1.2</Version>
802+
Note that `screenshot` will always return a base64 string if `save` is set to `false`.
803+
The `path` is also ignored in that case.
804+
:::
805+
800806
### query
801807

802808
```ts

packages/browser/context.d.ts

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,12 +29,19 @@ export interface ScreenshotOptions {
2929
element?: Element | Locator
3030
/**
3131
* Path relative to the current test file.
32+
* @default `__screenshots__/${testFileName}/${testName}.png`
3233
*/
3334
path?: string
3435
/**
3536
* Will also return the base64 encoded screenshot alongside the path.
3637
*/
3738
base64?: boolean
39+
/**
40+
* Keep the screenshot on the file system. If file is not saved,
41+
* `page.screenshot` always returns `base64` screenshot.
42+
* @default true
43+
*/
44+
save?: boolean
3845
}
3946

4047
export interface BrowserCommands {
@@ -552,11 +559,16 @@ export interface BrowserPage extends LocatorSelectors {
552559
* Make a screenshot of the test iframe or a specific element.
553560
* @returns Path to the screenshot file or path and base64.
554561
*/
562+
screenshot(options: Omit<ScreenshotOptions, 'save'> & { save: false }): Promise<string>
555563
screenshot(options: Omit<ScreenshotOptions, 'base64'> & { base64: true }): Promise<{
556564
path: string
557565
base64: string
558566
}>
559-
screenshot(options?: ScreenshotOptions): Promise<string>
567+
screenshot(options?: Omit<ScreenshotOptions, 'base64'>): Promise<string>
568+
screenshot(options?: ScreenshotOptions): Promise<string | {
569+
path: string
570+
base64: string
571+
}>
560572
/**
561573
* Extend default `page` object with custom methods.
562574
*/

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

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import type { BrowserCommand, ResolvedConfig } from 'vitest/node'
22
import type { ScreenshotOptions } from '../../../context'
3-
import { mkdir } from 'node:fs/promises'
3+
import { mkdir, rm } from 'node:fs/promises'
44
import { normalize } from 'node:path'
55
import { basename, dirname, relative, resolve } from 'pathe'
66
import { PlaywrightBrowserProvider } from '../providers/playwright'
@@ -15,6 +15,12 @@ export const screenshot: BrowserCommand<[string, ScreenshotOptions]> = async (
1515
throw new Error(`Cannot take a screenshot without a test path`)
1616
}
1717

18+
options.save ??= true
19+
20+
if (!options.save) {
21+
options.base64 = true
22+
}
23+
1824
const path = options.path
1925
? resolve(dirname(context.testPath), options.path)
2026
: resolveScreenshotPath(
@@ -31,28 +37,28 @@ export const screenshot: BrowserCommand<[string, ScreenshotOptions]> = async (
3137
const element = context.iframe.locator(`${selector}`)
3238
const buffer = await element.screenshot({
3339
...config,
34-
path: savePath,
40+
path: options.save ? savePath : undefined,
3541
})
3642
return returnResult(options, path, buffer)
3743
}
3844

3945
const buffer = await context.iframe.locator('body').screenshot({
4046
...options,
41-
path: savePath,
47+
path: options.save ? savePath : undefined,
4248
})
4349
return returnResult(options, path, buffer)
4450
}
4551

4652
if (context.provider instanceof WebdriverBrowserProvider) {
4753
const page = context.provider.browser!
48-
if (!options.element) {
49-
const body = await page.$('body')
50-
const buffer = await body.saveScreenshot(savePath)
51-
return returnResult(options, path, buffer)
52-
}
54+
const element = !options.element
55+
? await page.$('body')
56+
: await page.$(`${options.element}`)
5357

54-
const element = await page.$(`${options.element}`)
5558
const buffer = await element.saveScreenshot(savePath)
59+
if (!options.save) {
60+
await rm(savePath, { force: true })
61+
}
5662
return returnResult(options, path, buffer)
5763
}
5864

@@ -84,6 +90,9 @@ function returnResult(
8490
path: string,
8591
buffer: Buffer,
8692
) {
93+
if (!options.save) {
94+
return buffer.toString('base64')
95+
}
8796
if (options.base64) {
8897
return { path, base64: buffer.toString('base64') }
8998
}

test/browser/test/dom.test.ts

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,20 @@ describe('dom related activity', () => {
6565
expect(base64).toBeTypeOf('string')
6666
})
6767

68+
test('doesn\'t save base64', async () => {
69+
const wrapper = createWrapper()
70+
const div = createNode()
71+
wrapper.appendChild(div)
72+
73+
const base64 = await page.screenshot({
74+
element: wrapper,
75+
save: false,
76+
})
77+
expect(base64).toBeTypeOf('string')
78+
expect(base64).not.toContain('__screenshots__')
79+
expect(base64).not.toContain('dom.test.ts')
80+
})
81+
6882
test('shadow dom screenshot', async () => {
6983
const wrapper = createWrapper()
7084
const div = createNode()

0 commit comments

Comments
 (0)