7 Commits

24 changed files with 151 additions and 109 deletions

View File

@@ -137,7 +137,10 @@ Playwright MCP server supports following arguments. They can be provided in the
--ignore-https-errors ignore https errors
--isolated keep the browser profile in memory, do not save
it to disk.
--no-image-responses do not send image responses to the client.
--image-responses <mode> whether to send image responses to the client.
Can be "allow", "omit", or "auto". Defaults to
"auto", which sends images if the client can
display them.
--no-sandbox disable the sandbox for all process types that
are normally sandboxed.
--output-dir <path> path to the directory for output files.

4
config.d.ts vendored
View File

@@ -117,7 +117,7 @@ export type Config = {
};
/**
* Do not send image responses to the client.
* Whether to send image responses to the client. Can be "allow", "omit", or "auto". Defaults to "auto", which sends images if the client can display them.
*/
noImageResponses?: boolean;
imageResponses?: 'allow' | 'omit' | 'auto';
};

View File

@@ -1,4 +1,4 @@
Generate test for scenario:
Use Playwright tools to generate test for scenario:
## GitHub PR Checks Navigation Checklist

View File

@@ -15,5 +15,5 @@
* limitations under the License.
*/
import { createConnection } from './lib/index';
import { createConnection } from './lib/index.js';
export { createConnection };

30
package-lock.json generated
View File

@@ -1,17 +1,17 @@
{
"name": "@playwright/mcp",
"version": "0.0.26",
"version": "0.0.27",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@playwright/mcp",
"version": "0.0.26",
"version": "0.0.27",
"license": "Apache-2.0",
"dependencies": {
"@modelcontextprotocol/sdk": "^1.11.0",
"commander": "^13.1.0",
"playwright": "1.53.0-alpha-1746832516000",
"playwright": "1.53.0-alpha-2025-05-27",
"zod-to-json-schema": "^3.24.4"
},
"bin": {
@@ -20,7 +20,7 @@
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.19.0",
"@playwright/test": "1.53.0-alpha-1746832516000",
"@playwright/test": "1.53.0-alpha-2025-05-27",
"@stylistic/eslint-plugin": "^3.0.1",
"@types/node": "^22.13.10",
"@typescript-eslint/eslint-plugin": "^8.26.1",
@@ -286,13 +286,13 @@
}
},
"node_modules/@playwright/test": {
"version": "1.53.0-alpha-1746832516000",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.53.0-alpha-1746832516000.tgz",
"integrity": "sha512-Sec+6uzpA4MfwmQqJFBFVazffynqVwLO5swDxG7WoqgpUdn9gQX4K4tDG64SV6f4nOpwdM5LKTasPSXu02nn/Q==",
"version": "1.53.0-alpha-2025-05-27",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.53.0-alpha-2025-05-27.tgz",
"integrity": "sha512-G2zG56kEQOWhk3nQyPKH5u41jyQw5jx+Kga5huUi7RjBjPEnNtiCMNXMNGCh6dDYCIyQkLJvz/o1H/QN26HLsg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
"playwright": "1.53.0-alpha-1746832516000"
"playwright": "1.53.0-alpha-2025-05-27"
},
"bin": {
"playwright": "cli.js"
@@ -3298,12 +3298,12 @@
}
},
"node_modules/playwright": {
"version": "1.53.0-alpha-1746832516000",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.53.0-alpha-1746832516000.tgz",
"integrity": "sha512-kcC1B2XJr4VaDAcVzi61SbYGkodq1QIqQXuPieXsNgZZ7cEKWzO2sI42yp2yie6wlCx0oLkSS2Q6jWSRVRLeaw==",
"version": "1.53.0-alpha-2025-05-27",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.53.0-alpha-2025-05-27.tgz",
"integrity": "sha512-CD0BTwV5javEJ3hf3rhFJEvR3ZoWsu4HUQFfLH2mtVVe+grGPCP55FnlOjpDnJ5pP4Kibe/ZcmgPDg56ic/y9g==",
"license": "Apache-2.0",
"dependencies": {
"playwright-core": "1.53.0-alpha-1746832516000"
"playwright-core": "1.53.0-alpha-2025-05-27"
},
"bin": {
"playwright": "cli.js"
@@ -3316,9 +3316,9 @@
}
},
"node_modules/playwright-core": {
"version": "1.53.0-alpha-1746832516000",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.53.0-alpha-1746832516000.tgz",
"integrity": "sha512-4O98y4zV0rOP6CepMLC/VGuzqGaR1sS9AVh+i0CghWMQHM/8bxPJI8W38QndO0JU0V5nBD6j7DQeNt1mJ+CZ+g==",
"version": "1.53.0-alpha-2025-05-27",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.53.0-alpha-2025-05-27.tgz",
"integrity": "sha512-uVxs7YjENoBMFyQhsZWImIBuo/oX7Mu63djhQN3qFz/NdXA/rOAnP73XzfB+VJNwRMKgIOtqHQgjOG3Rl/lm0A==",
"license": "Apache-2.0",
"bin": {
"playwright-core": "cli.js"

View File

@@ -1,6 +1,6 @@
{
"name": "@playwright/mcp",
"version": "0.0.26",
"version": "0.0.27",
"description": "Playwright Tools for MCP",
"type": "module",
"repository": {
@@ -37,13 +37,13 @@
"dependencies": {
"@modelcontextprotocol/sdk": "^1.11.0",
"commander": "^13.1.0",
"playwright": "1.53.0-alpha-1746832516000",
"playwright": "1.53.0-alpha-2025-05-27",
"zod-to-json-schema": "^3.24.4"
},
"devDependencies": {
"@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.19.0",
"@playwright/test": "1.53.0-alpha-1746832516000",
"@playwright/test": "1.53.0-alpha-2025-05-27",
"@stylistic/eslint-plugin": "^3.0.1",
"@types/node": "^22.13.10",
"@typescript-eslint/eslint-plugin": "^8.26.1",

View File

@@ -29,7 +29,14 @@ export default defineConfig<TestOptions>({
{ name: 'chrome' },
{ name: 'msedge', use: { mcpBrowser: 'msedge' } },
{ name: 'chromium', use: { mcpBrowser: 'chromium' } },
...process.env.MCP_IN_DOCKER ? [{ name: 'chromium-docker', use: { mcpBrowser: 'chromium', mcpMode: 'docker' as const } }] : [],
...process.env.MCP_IN_DOCKER ? [{
name: 'chromium-docker',
grep: /browser_navigate|browser_click/,
use: {
mcpBrowser: 'chromium',
mcpMode: 'docker' as const
}
}] : [],
{ name: 'firefox', use: { mcpBrowser: 'firefox' } },
{ name: 'webkit', use: { mcpBrowser: 'webkit' } },
],

View File

@@ -38,7 +38,7 @@ export type CLIOptions = {
host?: string;
ignoreHttpsErrors?: boolean;
isolated?: boolean;
imageResponses: boolean;
imageResponses?: 'allow' | 'omit' | 'auto';
sandbox: boolean;
outputDir?: string;
port?: number;
@@ -94,11 +94,13 @@ export async function resolveCLIConfig(cliOptions: CLIOptions): Promise<FullConf
// Derive artifact output directory from config.outputDir
if (result.saveTrace)
result.browser.launchOptions.tracesDir = path.join(result.outputDir, 'traces');
if (result.browser.browserName === 'chromium')
(result.browser.launchOptions as any).cdpPort = await findFreePort();
return result;
}
export async function configFromCLIOptions(cliOptions: CLIOptions): Promise<Config> {
let browserName: 'chromium' | 'firefox' | 'webkit';
let browserName: 'chromium' | 'firefox' | 'webkit' | undefined;
let channel: string | undefined;
switch (cliOptions.browser) {
case 'chrome':
@@ -119,9 +121,6 @@ export async function configFromCLIOptions(cliOptions: CLIOptions): Promise<Conf
case 'webkit':
browserName = 'webkit';
break;
default:
browserName = 'chromium';
channel = 'chrome';
}
// Launch options
@@ -131,13 +130,9 @@ export async function configFromCLIOptions(cliOptions: CLIOptions): Promise<Conf
headless: cliOptions.headless,
};
if (browserName === 'chromium') {
(launchOptions as any).cdpPort = await findFreePort();
if (!cliOptions.sandbox) {
// --no-sandbox was passed, disable the sandbox
launchOptions.chromiumSandbox = false;
}
}
// --no-sandbox was passed, disable the sandbox
if (!cliOptions.sandbox)
launchOptions.chromiumSandbox = false;
if (cliOptions.proxyServer) {
launchOptions.proxy = {
@@ -193,13 +188,9 @@ export async function configFromCLIOptions(cliOptions: CLIOptions): Promise<Conf
},
saveTrace: cliOptions.saveTrace,
outputDir: cliOptions.outputDir,
imageResponses: cliOptions.imageResponses,
};
if (!cliOptions.imageResponses) {
// --no-image-responses was passed, disable image responses
result.noImageResponses = true;
}
return result;
}

View File

@@ -92,8 +92,7 @@ export class Connection {
await new Promise<void>(resolve => {
this.server.oninitialized = () => resolve();
});
if (this.server.getClientVersion()?.name.includes('cursor'))
this.context.config.noImageResponses = true;
this.context.clientVersion = this.server.getClientVersion();
}
async close() {

View File

@@ -48,12 +48,21 @@ export class Context {
private _modalStates: (ModalState & { tab: Tab })[] = [];
private _pendingAction: PendingAction | undefined;
private _downloads: { download: playwright.Download, finished: boolean, outputFile: string }[] = [];
clientVersion: { name: string; version: string; } | undefined;
constructor(tools: Tool[], config: FullConfig) {
this.tools = tools;
this.config = config;
}
clientSupportsImages(): boolean {
if (this.config.imageResponses === 'allow')
return true;
if (this.config.imageResponses === 'omit')
return false;
return !this.clientVersion?.name.includes('cursor');
}
modalStates(): ModalState[] {
return this._modalStates;
}

View File

@@ -40,9 +40,6 @@ export class PageSnapshot {
}
private async _build() {
// FIXME: Rountrip evaluate to ensure _snapshotForAI works.
// This probably broke once we moved off locator snapshots
await this._page.evaluate(() => 1);
const snapshot = await callOnPageNoTrace(this._page, page => (page as PageEx)._snapshotForAI());
this._text = [
`- Page Snapshot`,
@@ -52,7 +49,7 @@ export class PageSnapshot {
].join('\n');
}
refLocator(ref: string): playwright.Locator {
return this._page.locator(`aria-ref=${ref}`);
refLocator(params: { element: string, ref: string }): playwright.Locator {
return this._page.locator(`aria-ref=${params.ref}`).describe(params.element);
}
}

View File

@@ -40,7 +40,7 @@ program
.option('--host <host>', 'host to bind server to. Default is localhost. Use 0.0.0.0 to bind to all interfaces.')
.option('--ignore-https-errors', 'ignore https errors')
.option('--isolated', 'keep the browser profile in memory, do not save it to disk.')
.option('--no-image-responses', 'do not send image responses to the client.')
.option('--image-responses <mode>', 'whether to send image responses to the client. Can be "allow", "omit", or "auto". Defaults to "auto", which sends images if the client can display them.')
.option('--no-sandbox', 'disable the sandbox for all process types that are normally sandboxed.')
.option('--output-dir <path>', 'path to the directory for output files.')
.option('--port <port>', 'port to listen on for SSE transport.')

View File

@@ -57,14 +57,14 @@ const screenshot = defineTool({
`// Screenshot ${isElementScreenshot ? params.element : 'viewport'} and save it as ${fileName}`,
];
const locator = params.ref ? snapshot.refLocator(params.ref) : null;
const locator = params.ref ? snapshot.refLocator({ element: params.element || '', ref: params.ref }) : null;
if (locator)
code.push(`await page.${await generateLocator(locator)}.screenshot(${javascript.formatObject(options)});`);
else
code.push(`await page.screenshot(${javascript.formatObject(options)});`);
const includeBase64 = !context.config.noImageResponses;
const includeBase64 = context.clientSupportsImages();
const action = async () => {
const screenshot = locator ? await locator.screenshot(options) : await tab.page.screenshot(options);
return {

View File

@@ -58,7 +58,7 @@ const click = defineTool({
handle: async (context, params) => {
const tab = context.currentTabOrDie();
const locator = tab.snapshotOrDie().refLocator(params.ref);
const locator = tab.snapshotOrDie().refLocator(params);
const code = [
`// Click ${params.element}`,
@@ -91,8 +91,8 @@ const drag = defineTool({
handle: async (context, params) => {
const snapshot = context.currentTabOrDie().snapshotOrDie();
const startLocator = snapshot.refLocator(params.startRef);
const endLocator = snapshot.refLocator(params.endRef);
const startLocator = snapshot.refLocator({ ref: params.startRef, element: params.startElement });
const endLocator = snapshot.refLocator({ ref: params.endRef, element: params.endElement });
const code = [
`// Drag ${params.startElement} to ${params.endElement}`,
@@ -120,7 +120,7 @@ const hover = defineTool({
handle: async (context, params) => {
const snapshot = context.currentTabOrDie().snapshotOrDie();
const locator = snapshot.refLocator(params.ref);
const locator = snapshot.refLocator(params);
const code = [
`// Hover over ${params.element}`,
@@ -154,7 +154,7 @@ const type = defineTool({
handle: async (context, params) => {
const snapshot = context.currentTabOrDie().snapshotOrDie();
const locator = snapshot.refLocator(params.ref);
const locator = snapshot.refLocator(params);
const code: string[] = [];
const steps: (() => Promise<void>)[] = [];
@@ -200,7 +200,7 @@ const selectOption = defineTool({
handle: async (context, params) => {
const snapshot = context.currentTabOrDie().snapshotOrDie();
const locator = snapshot.refLocator(params.ref);
const locator = snapshot.refLocator(params);
const code = [
`// Select options [${params.values.join(', ')}] in ${params.element}`,

View File

@@ -78,9 +78,9 @@ export function sanitizeForFilePath(s: string) {
}
export async function generateLocator(locator: playwright.Locator): Promise<string> {
return (locator as any)._frame._wrapApiCall(() => (locator as any)._generateLocatorString(), true);
return (locator as any)._generateLocatorString();
}
export async function callOnPageNoTrace<T>(page: playwright.Page, callback: (page: playwright.Page) => Promise<T>): Promise<T> {
return await (page as any)._wrapApiCall(() => callback(page), true);
return await (page as any)._wrapApiCall(() => callback(page), { internal: true });
}

View File

@@ -19,7 +19,7 @@ import fs from 'node:fs';
import { Config } from '../config.js';
import { test, expect } from './fixtures.js';
test('config user data dir', async ({ startClient, localOutputPath, server }) => {
test('config user data dir', async ({ startClient, server }, testInfo) => {
server.setContent('/', `
<title>Title</title>
<body>Hello, world!</body>
@@ -27,10 +27,10 @@ test('config user data dir', async ({ startClient, localOutputPath, server }) =>
const config: Config = {
browser: {
userDataDir: localOutputPath('user-data-dir'),
userDataDir: testInfo.outputPath('user-data-dir'),
},
};
const configPath = localOutputPath('config.json');
const configPath = testInfo.outputPath('config.json');
await fs.promises.writeFile(configPath, JSON.stringify(config, null, 2));
const client = await startClient({ args: ['--config', configPath] });
@@ -42,3 +42,22 @@ test('config user data dir', async ({ startClient, localOutputPath, server }) =>
const files = await fs.promises.readdir(config.browser!.userDataDir!);
expect(files.length).toBeGreaterThan(0);
});
test.describe(() => {
test.use({ mcpBrowser: '' });
test('browserName', { annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright-mcp/issues/458' } }, async ({ startClient }, testInfo) => {
const config: Config = {
browser: {
browserName: 'firefox',
},
};
const configPath = testInfo.outputPath('config.json');
await fs.promises.writeFile(configPath, JSON.stringify(config, null, 2));
const client = await startClient({ args: ['--config', configPath] });
expect(await client.callTool({
name: 'browser_navigate',
arguments: { url: 'data:text/html,<script>document.title = navigator.userAgent</script>' },
})).toContainTextContent(`Firefox`);
});
});

View File

@@ -16,9 +16,8 @@
import { test, expect } from './fixtures.js';
import fs from 'fs/promises';
import path from 'path';
test('browser_file_upload', async ({ client, localOutputPath, server }) => {
test('browser_file_upload', async ({ client, server }, testInfo) => {
server.setContent('/', `
<input type="file" />
<button>Button</button>
@@ -54,7 +53,7 @@ The tool "browser_file_upload" can only be used when there is related modal stat
})).toContainTextContent(`### Modal state
- [File chooser]: can be handled by the "browser_file_upload" tool`);
const filePath = localOutputPath('test.txt');
const filePath = testInfo.outputPath('test.txt');
await fs.writeFile(filePath, 'Hello, world!');
{
@@ -101,10 +100,9 @@ The tool "browser_file_upload" can only be used when there is related modal stat
}
});
test('clicking on download link emits download', async ({ startClient, localOutputPath, server }) => {
const outputDir = localOutputPath('output');
test('clicking on download link emits download', async ({ startClient, server }, testInfo) => {
const client = await startClient({
config: { outputDir },
config: { outputDir: testInfo.outputPath('output') },
});
server.setContent('/', `<a href="/download" download="test.txt">Download</a>`, 'text/html');
@@ -123,13 +121,12 @@ test('clicking on download link emits download', async ({ startClient, localOutp
});
await expect.poll(() => client.callTool({ name: 'browser_snapshot' })).toContainTextContent(`
### Downloads
- Downloaded file test.txt to ${path.join(outputDir, 'test.txt')}`);
- Downloaded file test.txt to ${testInfo.outputPath('output', 'test.txt')}`);
});
test('navigating to download link emits download', async ({ startClient, localOutputPath, mcpBrowser, server }) => {
const outputDir = localOutputPath('output');
test('navigating to download link emits download', async ({ startClient, server, mcpBrowser }, testInfo) => {
const client = await startClient({
args: ['--output-dir', outputDir],
config: { outputDir: testInfo.outputPath('output') },
});
test.skip(mcpBrowser === 'webkit' && process.platform === 'linux', 'https://github.com/microsoft/playwright/blob/8e08fdb52c27bb75de9bf87627bf740fadab2122/tests/library/download.spec.ts#L436');

View File

@@ -46,7 +46,6 @@ type TestFixtures = {
server: TestServer;
httpsServer: TestServer;
mcpHeadless: boolean;
localOutputPath: (filePath: string) => string;
};
type WorkerFixtures = {
@@ -129,13 +128,6 @@ export const test = baseTest.extend<TestFixtures & TestOptions, WorkerFixtures>(
mcpMode: [undefined, { option: true }],
localOutputPath: async ({ mcpMode }, use, testInfo) => {
await use(filePath => {
test.skip(mcpMode === 'docker', 'Mounting files is not supported in docker mode');
return testInfo.outputPath(filePath);
});
},
_workerServers: [async ({}, use, workerInfo) => {
const port = 8907 + workerInfo.workerIndex * 4;
const server = await TestServer.create(port);

View File

@@ -104,8 +104,8 @@ test('isolated context', async ({ startClient, server }) => {
expect(response2).toContainTextContent(`Storage: NO`);
});
test('isolated context with storage state', async ({ startClient, server, localOutputPath }) => {
const storageStatePath = localOutputPath('storage-state.json');
test('isolated context with storage state', async ({ startClient, server }, testInfo) => {
const storageStatePath = testInfo.outputPath('storage-state.json');
await fs.promises.writeFile(storageStatePath, JSON.stringify({
origins: [
{

28
tests/library.spec.ts Normal file
View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import { test, expect } from './fixtures.js';
import fs from 'node:fs/promises';
import child_process from 'node:child_process';
test('library can be used from CommonJS', { annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright-mcp/issues/456' } }, async ({}, testInfo) => {
const file = testInfo.outputPath('main.cjs');
await fs.writeFile(file, `
import('@playwright/mcp')
.then(playwrightMCP => playwrightMCP.createConnection())
.then(() => console.log('OK'));
`);
expect(child_process.execSync(`node ${file}`, { encoding: 'utf-8' })).toContain('OK');
});

View File

@@ -30,10 +30,9 @@ test('save as pdf unavailable', async ({ startClient, server }) => {
})).toHaveTextContent(/Tool \"browser_pdf_save\" not found/);
});
test('save as pdf', async ({ startClient, mcpBrowser, server, localOutputPath }) => {
const outputDir = localOutputPath('output');
test('save as pdf', async ({ startClient, mcpBrowser, server }, testInfo) => {
const client = await startClient({
config: { outputDir },
config: { outputDir: testInfo.outputPath('output') },
});
test.skip(!!mcpBrowser && !['chromium', 'chrome', 'msedge'].includes(mcpBrowser), 'Save as PDF is only supported in Chromium.');
@@ -49,9 +48,9 @@ test('save as pdf', async ({ startClient, mcpBrowser, server, localOutputPath })
expect(response).toHaveTextContent(/Save page as.*page-[^:]+.pdf/);
});
test('save as pdf (filename: output.pdf)', async ({ startClient, mcpBrowser, server, localOutputPath }) => {
test('save as pdf (filename: output.pdf)', async ({ startClient, mcpBrowser, server }, testInfo) => {
const outputDir = testInfo.outputPath('output');
test.skip(!!mcpBrowser && !['chromium', 'chrome', 'msedge'].includes(mcpBrowser), 'Save as PDF is only supported in Chromium.');
const outputDir = localOutputPath('output');
const client = await startClient({
config: { outputDir },
});

View File

@@ -18,10 +18,9 @@ import fs from 'fs';
import { test, expect } from './fixtures.js';
test('browser_take_screenshot (viewport)', async ({ startClient, server, localOutputPath }) => {
const outputDir = localOutputPath('output');
test('browser_take_screenshot (viewport)', async ({ startClient, server }, testInfo) => {
const client = await startClient({
args: ['--output-dir', outputDir],
config: { outputDir: testInfo.outputPath('output') },
});
expect(await client.callTool({
name: 'browser_navigate',
@@ -45,10 +44,9 @@ test('browser_take_screenshot (viewport)', async ({ startClient, server, localOu
});
});
test('browser_take_screenshot (element)', async ({ startClient, server, localOutputPath }) => {
const outputDir = localOutputPath('output');
test('browser_take_screenshot (element)', async ({ startClient, server }, testInfo) => {
const client = await startClient({
args: ['--output-dir', outputDir],
config: { outputDir: testInfo.outputPath('output') },
});
expect(await client.callTool({
name: 'browser_navigate',
@@ -76,10 +74,10 @@ test('browser_take_screenshot (element)', async ({ startClient, server, localOut
});
});
test('--output-dir should work', async ({ startClient, localOutputPath, server }) => {
const outputDir = localOutputPath('output');
test('--output-dir should work', async ({ startClient, server }, testInfo) => {
const outputDir = testInfo.outputPath('output');
const client = await startClient({
args: ['--output-dir', outputDir],
config: { outputDir },
});
expect(await client.callTool({
name: 'browser_navigate',
@@ -97,9 +95,9 @@ test('--output-dir should work', async ({ startClient, localOutputPath, server }
});
for (const raw of [undefined, true]) {
test(`browser_take_screenshot (raw: ${raw})`, async ({ startClient, localOutputPath, server }) => {
test(`browser_take_screenshot (raw: ${raw})`, async ({ startClient, server }, testInfo) => {
const outputDir = testInfo.outputPath('output');
const ext = raw ? 'png' : 'jpeg';
const outputDir = localOutputPath('output');
const client = await startClient({
config: { outputDir },
});
@@ -138,8 +136,8 @@ for (const raw of [undefined, true]) {
}
test('browser_take_screenshot (filename: "output.jpeg")', async ({ startClient, localOutputPath, server }) => {
const outputDir = localOutputPath('output');
test('browser_take_screenshot (filename: "output.jpeg")', async ({ startClient, server }, testInfo) => {
const outputDir = testInfo.outputPath('output');
const client = await startClient({
config: { outputDir },
});
@@ -174,11 +172,12 @@ test('browser_take_screenshot (filename: "output.jpeg")', async ({ startClient,
expect(files[0]).toMatch(/^output\.jpeg$/);
});
test('browser_take_screenshot (noImageResponses)', async ({ startClient, server, localOutputPath }) => {
test('browser_take_screenshot (imageResponses=omit)', async ({ startClient, server }, testInfo) => {
const outputDir = testInfo.outputPath('output');
const client = await startClient({
config: {
outputDir: localOutputPath('output'),
noImageResponses: true,
outputDir,
imageResponses: 'omit',
},
});
@@ -203,8 +202,9 @@ test('browser_take_screenshot (noImageResponses)', async ({ startClient, server,
});
});
test('browser_take_screenshot (cursor)', async ({ startClient, server, localOutputPath }) => {
const outputDir = localOutputPath('output');
test('browser_take_screenshot (cursor)', async ({ startClient, server }, testInfo) => {
const outputDir = testInfo.outputPath('output');
const client = await startClient({
clientName: 'cursor:vscode',
config: { outputDir },

View File

@@ -65,8 +65,8 @@ test('streamable http transport', async ({ serverEndpoint }) => {
expect(transport.sessionId, 'has session support').toBeDefined();
});
test('sse transport via public API', async ({ server, localOutputPath }) => {
const userDataDir = localOutputPath('user-data-dir');
test('sse transport via public API', async ({ server }, testInfo) => {
const userDataDir = testInfo.outputPath('user-data-dir');
const sessions = new Map<string, SSEServerTransport>();
const mcpServer = http.createServer(async (req, res) => {
if (req.method === 'GET') {

View File

@@ -19,8 +19,9 @@ import path from 'path';
import { test, expect } from './fixtures.js';
test('check that trace is saved', async ({ startClient, server, localOutputPath }) => {
const outputDir = localOutputPath('output');
test('check that trace is saved', async ({ startClient, server }, testInfo) => {
const outputDir = testInfo.outputPath('output');
const client = await startClient({
args: ['--save-trace', `--output-dir=${outputDir}`],
});