mirror of
https://github.com/microsoft/playwright-mcp.git
synced 2025-07-26 16:42:27 +08:00
chore: allow specifying output dir (#285)
Ref: https://github.com/microsoft/playwright-mcp/issues/279
This commit is contained in:
parent
6e76d5e550
commit
697a69a8c2
5
config.d.ts
vendored
5
config.d.ts
vendored
@ -80,4 +80,9 @@ export type Config = {
|
|||||||
* Run server that uses screenshots (Aria snapshots are used by default).
|
* Run server that uses screenshots (Aria snapshots are used by default).
|
||||||
*/
|
*/
|
||||||
vision?: boolean;
|
vision?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The directory to save output files.
|
||||||
|
*/
|
||||||
|
outputDir?: string;
|
||||||
};
|
};
|
||||||
|
@ -14,8 +14,12 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import fs from 'fs';
|
||||||
import net from 'net';
|
import net from 'net';
|
||||||
import os from 'os';
|
import os from 'os';
|
||||||
|
import path from 'path';
|
||||||
|
|
||||||
|
import { sanitizeForFilePath } from './tools/utils';
|
||||||
|
|
||||||
import type { Config } from '../config';
|
import type { Config } from '../config';
|
||||||
import type { LaunchOptions, BrowserContextOptions } from 'playwright';
|
import type { LaunchOptions, BrowserContextOptions } from 'playwright';
|
||||||
@ -84,3 +88,10 @@ async function findFreePort() {
|
|||||||
server.on('error', reject);
|
server.on('error', reject);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export async function outputFile(config: Config, name: string): Promise<string> {
|
||||||
|
const result = config.outputDir ?? os.tmpdir();
|
||||||
|
await fs.promises.mkdir(result, { recursive: true });
|
||||||
|
const fileName = sanitizeForFilePath(name);
|
||||||
|
return path.join(result, fileName);
|
||||||
|
}
|
||||||
|
@ -14,14 +14,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import os from 'os';
|
|
||||||
import path from 'path';
|
|
||||||
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
import { defineTool } from './tool';
|
import { defineTool } from './tool';
|
||||||
|
|
||||||
import { sanitizeForFilePath } from './utils';
|
|
||||||
import * as javascript from '../javascript';
|
import * as javascript from '../javascript';
|
||||||
|
import { outputFile } from '../config';
|
||||||
|
|
||||||
const pdf = defineTool({
|
const pdf = defineTool({
|
||||||
capability: 'pdf',
|
capability: 'pdf',
|
||||||
@ -34,7 +31,7 @@ const pdf = defineTool({
|
|||||||
|
|
||||||
handle: async context => {
|
handle: async context => {
|
||||||
const tab = context.currentTabOrDie();
|
const tab = context.currentTabOrDie();
|
||||||
const fileName = path.join(os.tmpdir(), sanitizeForFilePath(`page-${new Date().toISOString()}`)) + '.pdf';
|
const fileName = await outputFile(context.config, `page-${new Date().toISOString()}'.pdf'`);
|
||||||
|
|
||||||
const code = [
|
const code = [
|
||||||
`// Save page as ${fileName}`,
|
`// Save page as ${fileName}`,
|
||||||
|
@ -14,14 +14,11 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import path from 'path';
|
|
||||||
import os from 'os';
|
|
||||||
|
|
||||||
import { z } from 'zod';
|
import { z } from 'zod';
|
||||||
|
|
||||||
import { sanitizeForFilePath } from './utils';
|
|
||||||
import { defineTool } from './tool';
|
import { defineTool } from './tool';
|
||||||
import * as javascript from '../javascript';
|
import * as javascript from '../javascript';
|
||||||
|
import { outputFile } from '../config';
|
||||||
|
|
||||||
import type * as playwright from 'playwright';
|
import type * as playwright from 'playwright';
|
||||||
|
|
||||||
@ -232,7 +229,7 @@ const screenshot = defineTool({
|
|||||||
const tab = context.currentTabOrDie();
|
const tab = context.currentTabOrDie();
|
||||||
const snapshot = tab.snapshotOrDie();
|
const snapshot = tab.snapshotOrDie();
|
||||||
const fileType = params.raw ? 'png' : 'jpeg';
|
const fileType = params.raw ? 'png' : 'jpeg';
|
||||||
const fileName = path.join(os.tmpdir(), sanitizeForFilePath(`page-${new Date().toISOString()}`)) + `.${fileType}`;
|
const fileName = await outputFile(context.config, `page-${new Date().toISOString()}.${fileType}`);
|
||||||
const options: playwright.PageScreenshotOptions = { type: fileType, quality: fileType === 'png' ? undefined : 50, scale: 'css', path: fileName };
|
const options: playwright.PageScreenshotOptions = { type: fileType, quality: fileType === 'png' ? undefined : 50, scale: 'css', path: fileName };
|
||||||
const isElementScreenshot = params.element && params.ref;
|
const isElementScreenshot = params.element && params.ref;
|
||||||
|
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import fs from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import { chromium } from 'playwright';
|
import { chromium } from 'playwright';
|
||||||
|
|
||||||
@ -23,10 +24,12 @@ import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|||||||
import { spawn } from 'child_process';
|
import { spawn } from 'child_process';
|
||||||
import { TestServer } from './testserver';
|
import { TestServer } from './testserver';
|
||||||
|
|
||||||
|
import type { Config } from '../config';
|
||||||
|
|
||||||
type TestFixtures = {
|
type TestFixtures = {
|
||||||
client: Client;
|
client: Client;
|
||||||
visionClient: Client;
|
visionClient: Client;
|
||||||
startClient: (options?: { args?: string[] }) => Promise<Client>;
|
startClient: (options?: { args?: string[], config?: Config }) => Promise<Client>;
|
||||||
wsEndpoint: string;
|
wsEndpoint: string;
|
||||||
cdpEndpoint: string;
|
cdpEndpoint: string;
|
||||||
server: TestServer;
|
server: TestServer;
|
||||||
@ -61,6 +64,11 @@ export const test = baseTest.extend<TestFixtures, WorkerFixtures>({
|
|||||||
args.push(`--browser=${mcpBrowser}`);
|
args.push(`--browser=${mcpBrowser}`);
|
||||||
if (options?.args)
|
if (options?.args)
|
||||||
args.push(...options.args);
|
args.push(...options.args);
|
||||||
|
if (options?.config) {
|
||||||
|
const configFile = testInfo.outputPath('config.json');
|
||||||
|
await fs.promises.writeFile(configFile, JSON.stringify(options.config, null, 2));
|
||||||
|
args.push(`--config=${configFile}`);
|
||||||
|
}
|
||||||
const transport = new StdioClientTransport({
|
const transport = new StdioClientTransport({
|
||||||
command: 'node',
|
command: 'node',
|
||||||
args: [path.join(__dirname, '../cli.js'), ...args],
|
args: [path.join(__dirname, '../cli.js'), ...args],
|
||||||
|
@ -14,6 +14,8 @@
|
|||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import fs from 'fs';
|
||||||
|
|
||||||
import { test, expect } from './fixtures';
|
import { test, expect } from './fixtures';
|
||||||
|
|
||||||
test('browser_take_screenshot (viewport)', async ({ client }) => {
|
test('browser_take_screenshot (viewport)', async ({ client }) => {
|
||||||
@ -70,3 +72,24 @@ test('browser_take_screenshot (element)', async ({ client }) => {
|
|||||||
],
|
],
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test('browser_take_screenshot (outputDir)', async ({ startClient }, testInfo) => {
|
||||||
|
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`);
|
||||||
|
|
||||||
|
await client.callTool({
|
||||||
|
name: 'browser_take_screenshot',
|
||||||
|
arguments: {},
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(fs.existsSync(outputDir)).toBeTruthy();
|
||||||
|
expect([...fs.readdirSync(outputDir)]).toHaveLength(1);
|
||||||
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user