mirror of
https://github.com/microsoft/playwright-mcp.git
synced 2025-07-26 08:32:26 +08:00
chore: support custom filename in screenshot function (#349)
This commit is contained in:
parent
09ba7989c3
commit
85c85bd2fb
@ -341,6 +341,7 @@ X Y coordinate space, based on the provided screenshot.
|
||||
- Description: Take a screenshot of the current page. You can't perform actions based on the screenshot, use browser_snapshot for actions.
|
||||
- Parameters:
|
||||
- `raw` (boolean, optional): Whether to return without compression (in PNG format). Default is false, which returns a JPEG image.
|
||||
- `filename` (string, optional): File name to save the screenshot to. Defaults to `page-{timestamp}.{png|jpeg}` if not specified.
|
||||
- `element` (string, optional): Human-readable element description used to obtain permission to screenshot the element. If not provided, the screenshot will be taken of viewport. If element is provided, ref must be provided too.
|
||||
- `ref` (string, optional): Exact target element reference from the page snapshot. If not provided, the screenshot will be taken of viewport. If ref is provided, element must be provided too.
|
||||
- Read-only: **true**
|
||||
@ -501,7 +502,8 @@ X Y coordinate space, based on the provided screenshot.
|
||||
- **browser_pdf_save**
|
||||
- Title: Save as PDF
|
||||
- Description: Save page as PDF
|
||||
- Parameters: None
|
||||
- Parameters:
|
||||
- `filename` (string, optional): File name to save the pdf to. Defaults to `page-{timestamp}.pdf` if not specified.
|
||||
- Read-only: **true**
|
||||
|
||||
### Utilities
|
||||
|
@ -20,6 +20,10 @@ import { defineTool } from './tool.js';
|
||||
import * as javascript from '../javascript.js';
|
||||
import { outputFile } from '../config.js';
|
||||
|
||||
const pdfSchema = z.object({
|
||||
filename: z.string().optional().describe('File name to save the pdf to. Defaults to `page-{timestamp}.pdf` if not specified.'),
|
||||
});
|
||||
|
||||
const pdf = defineTool({
|
||||
capability: 'pdf',
|
||||
|
||||
@ -27,13 +31,13 @@ const pdf = defineTool({
|
||||
name: 'browser_pdf_save',
|
||||
title: 'Save as PDF',
|
||||
description: 'Save page as PDF',
|
||||
inputSchema: z.object({}),
|
||||
inputSchema: pdfSchema,
|
||||
type: 'readOnly',
|
||||
},
|
||||
|
||||
handle: async context => {
|
||||
handle: async (context, params) => {
|
||||
const tab = context.currentTabOrDie();
|
||||
const fileName = await outputFile(context.config, `page-${new Date().toISOString()}.pdf`);
|
||||
const fileName = await outputFile(context.config, params.filename ?? `page-${new Date().toISOString()}.pdf`);
|
||||
|
||||
const code = [
|
||||
`// Save page as ${fileName}`,
|
||||
|
@ -220,6 +220,7 @@ const selectOption = defineTool({
|
||||
|
||||
const screenshotSchema = z.object({
|
||||
raw: z.boolean().optional().describe('Whether to return without compression (in PNG format). Default is false, which returns a JPEG image.'),
|
||||
filename: z.string().optional().describe('File name to save the screenshot to. Defaults to `page-{timestamp}.{png|jpeg}` if not specified.'),
|
||||
element: z.string().optional().describe('Human-readable element description used to obtain permission to screenshot the element. If not provided, the screenshot will be taken of viewport. If element is provided, ref must be provided too.'),
|
||||
ref: z.string().optional().describe('Exact target element reference from the page snapshot. If not provided, the screenshot will be taken of viewport. If ref is provided, element must be provided too.'),
|
||||
}).refine(data => {
|
||||
@ -243,7 +244,7 @@ const screenshot = defineTool({
|
||||
const tab = context.currentTabOrDie();
|
||||
const snapshot = tab.snapshotOrDie();
|
||||
const fileType = params.raw ? 'png' : 'jpeg';
|
||||
const fileName = await outputFile(context.config, `page-${new Date().toISOString()}.${fileType}`);
|
||||
const fileName = await outputFile(context.config, params.filename ?? `page-${new Date().toISOString()}.${fileType}`);
|
||||
const options: playwright.PageScreenshotOptions = { type: fileType, quality: fileType === 'png' ? undefined : 50, scale: 'css', path: fileName };
|
||||
const isElementScreenshot = params.element && params.ref;
|
||||
|
||||
|
@ -14,6 +14,8 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
|
||||
import { test, expect } from './fixtures.js';
|
||||
|
||||
test('save as pdf unavailable', async ({ startClient }) => {
|
||||
@ -45,3 +47,38 @@ test('save as pdf', async ({ client, mcpBrowser }) => {
|
||||
});
|
||||
expect(response).toHaveTextContent(/Save page as.*page-[^:]+.pdf/);
|
||||
});
|
||||
|
||||
test('save as pdf (filename: output.pdf)', async ({ startClient, mcpBrowser }, testInfo) => {
|
||||
test.skip(!!mcpBrowser && !['chromium', 'chrome', 'msedge'].includes(mcpBrowser), 'Save as PDF is only supported in Chromium.');
|
||||
const outputDir = testInfo.outputPath('output');
|
||||
const client = await startClient({
|
||||
config: { outputDir },
|
||||
});
|
||||
|
||||
expect(await client.callTool({
|
||||
name: 'browser_navigate',
|
||||
arguments: {
|
||||
url: 'data:text/html,<html><title>Title</title><body>Hello, world!</body></html>',
|
||||
},
|
||||
})).toContainTextContent(`- generic [ref=s1e2]: Hello, world!`);
|
||||
|
||||
expect(await client.callTool({
|
||||
name: 'browser_pdf_save',
|
||||
arguments: {
|
||||
filename: 'output.pdf',
|
||||
},
|
||||
})).toEqual({
|
||||
content: [
|
||||
{
|
||||
type: 'text',
|
||||
text: expect.stringContaining(`output.pdf`),
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const files = [...fs.readdirSync(outputDir)];
|
||||
|
||||
expect(fs.existsSync(outputDir)).toBeTruthy();
|
||||
expect(files).toHaveLength(1);
|
||||
expect(files[0]).toMatch(/^output.pdf$/);
|
||||
});
|
||||
|
@ -94,9 +94,54 @@ test('--output-dir should work', async ({ startClient, localOutputPath }) => {
|
||||
expect([...fs.readdirSync(outputDir)]).toHaveLength(1);
|
||||
});
|
||||
|
||||
for (const raw of [undefined, true]) {
|
||||
test(`browser_take_screenshot (raw: ${raw})`, async ({ startClient }, testInfo) => {
|
||||
const ext = raw ? 'png' : 'jpeg';
|
||||
const outputDir = testInfo.outputPath('output');
|
||||
const client = await startClient({
|
||||
config: { outputDir },
|
||||
});
|
||||
expect(await client.callTool({
|
||||
name: 'browser_navigate',
|
||||
arguments: {
|
||||
url: 'data:text/html,<html><title>Title</title><body>Hello, world!</body></html>',
|
||||
},
|
||||
})).toContainTextContent(`Navigate to data:text/html`);
|
||||
|
||||
test('browser_take_screenshot (outputDir)', async ({ startClient, localOutputPath }) => {
|
||||
const outputDir = localOutputPath('output');
|
||||
expect(await client.callTool({
|
||||
name: 'browser_take_screenshot',
|
||||
arguments: {
|
||||
raw,
|
||||
},
|
||||
})).toEqual({
|
||||
content: [
|
||||
{
|
||||
data: expect.any(String),
|
||||
mimeType: `image/${ext}`,
|
||||
type: 'image',
|
||||
},
|
||||
{
|
||||
text: expect.stringMatching(
|
||||
new RegExp(`page-\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}\\-\\d{3}Z\\.${ext}`)
|
||||
),
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const files = [...fs.readdirSync(outputDir)];
|
||||
|
||||
expect(fs.existsSync(outputDir)).toBeTruthy();
|
||||
expect(files).toHaveLength(1);
|
||||
expect(files[0]).toMatch(
|
||||
new RegExp(`^page-\\d{4}-\\d{2}-\\d{2}T\\d{2}-\\d{2}-\\d{2}-\\d{3}Z\\.${ext}$`)
|
||||
);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
test('browser_take_screenshot (filename: "output.jpeg")', async ({ startClient }, testInfo) => {
|
||||
const outputDir = testInfo.outputPath('output');
|
||||
const client = await startClient({
|
||||
config: { outputDir },
|
||||
});
|
||||
@ -107,13 +152,30 @@ test('browser_take_screenshot (outputDir)', async ({ startClient, localOutputPat
|
||||
},
|
||||
})).toContainTextContent(`Navigate to data:text/html`);
|
||||
|
||||
await client.callTool({
|
||||
expect(await client.callTool({
|
||||
name: 'browser_take_screenshot',
|
||||
arguments: {},
|
||||
arguments: {
|
||||
filename: 'output.jpeg',
|
||||
},
|
||||
})).toEqual({
|
||||
content: [
|
||||
{
|
||||
data: expect.any(String),
|
||||
mimeType: 'image/jpeg',
|
||||
type: 'image',
|
||||
},
|
||||
{
|
||||
text: expect.stringContaining(`output.jpeg`),
|
||||
type: 'text',
|
||||
},
|
||||
],
|
||||
});
|
||||
|
||||
const files = [...fs.readdirSync(outputDir)];
|
||||
|
||||
expect(fs.existsSync(outputDir)).toBeTruthy();
|
||||
expect([...fs.readdirSync(outputDir)]).toHaveLength(1);
|
||||
expect(files).toHaveLength(1);
|
||||
expect(files[0]).toMatch(/^output.jpeg$/);
|
||||
});
|
||||
|
||||
test('browser_take_screenshot (noImageResponses)', async ({ startClient }) => {
|
||||
|
Loading…
x
Reference in New Issue
Block a user