import { describe, it, expect, vi } from 'vitest'
import { saveScreenshot } from '../../src/node/saveScreenshot.js'
import { getContextManager } from '../../src/session/context.js'
vi.mock('node:fs/promises', () => ({
default: {
access: vi.fn().mockResolvedValue(undefined),
writeFile: vi.fn()
}
}))
vi.mock('../../src/session/context.js', () => ({
getContextManager: vi.fn().mockReturnValue({
getCurrentContext: vi.fn().mockResolvedValue('context'),
findParentContext: vi.fn().mockResolvedValue({ data: 'bidi screenshot' })
})
}))
const browserClassic = {
isBidi: false,
takeScreenshot: vi.fn().mockResolvedValue(btoa('classic screenshot'))
} as unknown as WebdriverIO.Browser
const browserBidi = {
isBidi: true,
$: vi.fn().mockReturnValue({
getElement: vi.fn().mockResolvedValue({ elementId: 'elementId' })
}),
takeElementScreenshot: vi.fn().mockResolvedValue(btoa('bidi iframe screenshot')),
browsingContextGetTree: vi.fn().mockResolvedValue({ contexts: [] }),
browsingContextCaptureScreenshot: vi.fn().mockResolvedValue({ data: btoa('bidi screenshot') })
} as unknown as WebdriverIO.Browser
describe('saveScreenshot', () => {
describe('WebDriver Classic mode', () => {
it('should save a screenshot of the browser viewport', async () => {
const screenshot = await saveScreenshot.call(browserClassic, 'screenshot.png')
expect(screenshot.toString()).toBe('classic screenshot')
})
it('should fail if options are provided', async () => {
await expect(saveScreenshot.call(browserClassic, 'screenshot.png', { fullPage: true })).rejects.toThrow()
})
})
describe('WebDriver Bidi mode', () => {
it('should save a screenshot of an iframe', async () => {
const screenshot = await saveScreenshot.call(browserBidi, 'screenshot.png')
expect(screenshot.toString()).toBe('bidi iframe screenshot')
})
it('should save a screenshot of the full page', async () => {
const contextManager = getContextManager(browserBidi)
vi.mocked(contextManager.findParentContext).mockReturnValue(undefined)
const screenshot = await saveScreenshot.call(browserBidi, 'screenshot.png', { fullPage: true })
expect(screenshot.toString()).toBe('bidi screenshot')
expect(browserBidi.browsingContextCaptureScreenshot).toHaveBeenCalledWith({
context: 'context',
origin: 'document',
format: {
type: 'image/png',
quality: undefined
},
clip: undefined
})
})
it('should save a screenshot of a specific rectangle', async () => {
const screenshot = await saveScreenshot.call(browserBidi, 'screenshot.png', { clip: { x: 10, y: 10, width: 100, height: 100 } })
expect(screenshot.toString()).toBe('bidi screenshot')
expect(browserBidi.browsingContextCaptureScreenshot).toHaveBeenCalledWith({
context: 'context',
origin: 'viewport',
clip: {
type: 'box',
x: 10,
y: 10,
width: 100,
height: 100
},
format: {
type: 'image/png',
quality: undefined
}
})
})
it('should throw an error if the image format is invalid', async () => {
await expect(saveScreenshot.call(browserBidi, 'screenshot.png', { format: 'invalid' })).rejects.toThrow()
})
it('should throw an error if the file extension is invalid', async () => {
await expect(saveScreenshot.call(browserBidi, 'screenshot.jpeg', { format: 'png' })).rejects.toThrow()
})
it('should throw an error if the file extension is invalid for JPEG format', async () => {
await saveScreenshot.call(browserBidi, 'screenshot.jpeg')
await expect(saveScreenshot.call(browserBidi, 'screenshot.exe', { format: 'jpeg' })).rejects.toThrow()
})
it('should throw an error if the quality is invalid', async () => {
await expect(saveScreenshot.call(browserBidi, 'screenshot.png', { quality: 101 }))
.rejects.toThrow(/Invalid quality, use a number between 0 and 100,/)
await expect(saveScreenshot.call(browserBidi, 'screenshot.png', { quality: 50 }))
.rejects.toThrow(/Invalid option "quality" for PNG format/)
})
it('should throw an error if the clip is invalid', async () => {
await expect(saveScreenshot.call(browserBidi, 'screenshot.png', { clip: { x: 'invalid' } })).rejects.toThrow()
})
})
})