chore: roll Playwright, remove localOutputDir (#471)

This commit is contained in:
Pavel Feldman 2025-05-24 11:44:57 -07:00 committed by GitHub
parent 13cd1b4bd9
commit f20ae22ec6
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
15 changed files with 73 additions and 77 deletions

View File

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

26
package-lock.json generated
View File

@ -11,7 +11,7 @@
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "^1.11.0", "@modelcontextprotocol/sdk": "^1.11.0",
"commander": "^13.1.0", "commander": "^13.1.0",
"playwright": "1.53.0-alpha-1746832516000", "playwright": "1.53.0-alpha-2025-05-23",
"zod-to-json-schema": "^3.24.4" "zod-to-json-schema": "^3.24.4"
}, },
"bin": { "bin": {
@ -20,7 +20,7 @@
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3.2.0", "@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.19.0", "@eslint/js": "^9.19.0",
"@playwright/test": "1.53.0-alpha-1746832516000", "@playwright/test": "1.53.0-alpha-2025-05-23",
"@stylistic/eslint-plugin": "^3.0.1", "@stylistic/eslint-plugin": "^3.0.1",
"@types/node": "^22.13.10", "@types/node": "^22.13.10",
"@typescript-eslint/eslint-plugin": "^8.26.1", "@typescript-eslint/eslint-plugin": "^8.26.1",
@ -286,13 +286,13 @@
} }
}, },
"node_modules/@playwright/test": { "node_modules/@playwright/test": {
"version": "1.53.0-alpha-1746832516000", "version": "1.53.0-alpha-2025-05-23",
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.53.0-alpha-1746832516000.tgz", "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.53.0-alpha-2025-05-23.tgz",
"integrity": "sha512-Sec+6uzpA4MfwmQqJFBFVazffynqVwLO5swDxG7WoqgpUdn9gQX4K4tDG64SV6f4nOpwdM5LKTasPSXu02nn/Q==", "integrity": "sha512-WdTIHB2I5IuBs8q/CSnjauuhm3o1sShdgO+lKCncRh0nD24PTyyUiE8yBrq4OazrX1toGHlawV1HwEIdrq+fcg==",
"dev": true, "dev": true,
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"playwright": "1.53.0-alpha-1746832516000" "playwright": "1.53.0-alpha-2025-05-23"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
@ -3298,12 +3298,12 @@
} }
}, },
"node_modules/playwright": { "node_modules/playwright": {
"version": "1.53.0-alpha-1746832516000", "version": "1.53.0-alpha-2025-05-23",
"resolved": "https://registry.npmjs.org/playwright/-/playwright-1.53.0-alpha-1746832516000.tgz", "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.53.0-alpha-2025-05-23.tgz",
"integrity": "sha512-kcC1B2XJr4VaDAcVzi61SbYGkodq1QIqQXuPieXsNgZZ7cEKWzO2sI42yp2yie6wlCx0oLkSS2Q6jWSRVRLeaw==", "integrity": "sha512-86hfHKdPcBAjDguEb6doNG76uj2fUbFBCCqew4/0KwOnLrpAPJ2Uyeygt+zsj2k9ok+n7NWtsbpxSmXj6kYieA==",
"license": "Apache-2.0", "license": "Apache-2.0",
"dependencies": { "dependencies": {
"playwright-core": "1.53.0-alpha-1746832516000" "playwright-core": "1.53.0-alpha-2025-05-23"
}, },
"bin": { "bin": {
"playwright": "cli.js" "playwright": "cli.js"
@ -3316,9 +3316,9 @@
} }
}, },
"node_modules/playwright-core": { "node_modules/playwright-core": {
"version": "1.53.0-alpha-1746832516000", "version": "1.53.0-alpha-2025-05-23",
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.53.0-alpha-1746832516000.tgz", "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.53.0-alpha-2025-05-23.tgz",
"integrity": "sha512-4O98y4zV0rOP6CepMLC/VGuzqGaR1sS9AVh+i0CghWMQHM/8bxPJI8W38QndO0JU0V5nBD6j7DQeNt1mJ+CZ+g==", "integrity": "sha512-60XHM1EGJl5ugdUwMNYbmJoj6zTAAZO0Rr5OTApFwj2gqQC5vERbB6XewD8a2MbxAMXVaZThKFcABr1VZi6NkQ==",
"license": "Apache-2.0", "license": "Apache-2.0",
"bin": { "bin": {
"playwright-core": "cli.js" "playwright-core": "cli.js"

View File

@ -37,13 +37,13 @@
"dependencies": { "dependencies": {
"@modelcontextprotocol/sdk": "^1.11.0", "@modelcontextprotocol/sdk": "^1.11.0",
"commander": "^13.1.0", "commander": "^13.1.0",
"playwright": "1.53.0-alpha-1746832516000", "playwright": "1.53.0-alpha-2025-05-23",
"zod-to-json-schema": "^3.24.4" "zod-to-json-schema": "^3.24.4"
}, },
"devDependencies": { "devDependencies": {
"@eslint/eslintrc": "^3.2.0", "@eslint/eslintrc": "^3.2.0",
"@eslint/js": "^9.19.0", "@eslint/js": "^9.19.0",
"@playwright/test": "1.53.0-alpha-1746832516000", "@playwright/test": "1.53.0-alpha-2025-05-23",
"@stylistic/eslint-plugin": "^3.0.1", "@stylistic/eslint-plugin": "^3.0.1",
"@types/node": "^22.13.10", "@types/node": "^22.13.10",
"@typescript-eslint/eslint-plugin": "^8.26.1", "@typescript-eslint/eslint-plugin": "^8.26.1",

View File

@ -29,7 +29,14 @@ export default defineConfig<TestOptions>({
{ name: 'chrome' }, { name: 'chrome' },
{ name: 'msedge', use: { mcpBrowser: 'msedge' } }, { name: 'msedge', use: { mcpBrowser: 'msedge' } },
{ name: 'chromium', use: { mcpBrowser: 'chromium' } }, { 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: 'firefox', use: { mcpBrowser: 'firefox' } },
{ name: 'webkit', use: { mcpBrowser: 'webkit' } }, { name: 'webkit', use: { mcpBrowser: 'webkit' } },
], ],

View File

@ -52,7 +52,7 @@ export class PageSnapshot {
].join('\n'); ].join('\n');
} }
refLocator(ref: string): playwright.Locator { refLocator(params: { element: string, ref: string }): playwright.Locator {
return this._page.locator(`aria-ref=${ref}`); return this._page.locator(`aria-ref=${params.ref}`);
} }
} }

View File

@ -57,7 +57,7 @@ const screenshot = defineTool({
`// Screenshot ${isElementScreenshot ? params.element : 'viewport'} and save it as ${fileName}`, `// 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) if (locator)
code.push(`await page.${await generateLocator(locator)}.screenshot(${javascript.formatObject(options)});`); code.push(`await page.${await generateLocator(locator)}.screenshot(${javascript.formatObject(options)});`);

View File

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

View File

@ -19,7 +19,7 @@ import fs from 'node:fs';
import { Config } from '../config.js'; import { Config } from '../config.js';
import { test, expect } from './fixtures.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('/', ` server.setContent('/', `
<title>Title</title> <title>Title</title>
<body>Hello, world!</body> <body>Hello, world!</body>
@ -27,10 +27,10 @@ test('config user data dir', async ({ startClient, localOutputPath, server }) =>
const config: Config = { const config: Config = {
browser: { 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)); await fs.promises.writeFile(configPath, JSON.stringify(config, null, 2));
const client = await startClient({ args: ['--config', configPath] }); const client = await startClient({ args: ['--config', configPath] });
@ -45,13 +45,13 @@ test('config user data dir', async ({ startClient, localOutputPath, server }) =>
test.describe(() => { test.describe(() => {
test.use({ mcpBrowser: '' }); test.use({ mcpBrowser: '' });
test('browserName', { annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright-mcp/issues/458' } }, async ({ startClient, localOutputPath }) => { test('browserName', { annotation: { type: 'issue', description: 'https://github.com/microsoft/playwright-mcp/issues/458' } }, async ({ startClient }, testInfo) => {
const config: Config = { const config: Config = {
browser: { browser: {
browserName: 'firefox', browserName: 'firefox',
}, },
}; };
const configPath = localOutputPath('config.json'); const configPath = testInfo.outputPath('config.json');
await fs.promises.writeFile(configPath, JSON.stringify(config, null, 2)); await fs.promises.writeFile(configPath, JSON.stringify(config, null, 2));
const client = await startClient({ args: ['--config', configPath] }); const client = await startClient({ args: ['--config', configPath] });

View File

@ -16,9 +16,8 @@
import { test, expect } from './fixtures.js'; import { test, expect } from './fixtures.js';
import fs from 'fs/promises'; 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('/', ` server.setContent('/', `
<input type="file" /> <input type="file" />
<button>Button</button> <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 })).toContainTextContent(`### Modal state
- [File chooser]: can be handled by the "browser_file_upload" tool`); - [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!'); 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 }) => { test('clicking on download link emits download', async ({ startClient, server }, testInfo) => {
const outputDir = localOutputPath('output');
const client = await startClient({ const client = await startClient({
config: { outputDir }, config: { outputDir: testInfo.outputPath('output') },
}); });
server.setContent('/', `<a href="/download" download="test.txt">Download</a>`, 'text/html'); 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(` await expect.poll(() => client.callTool({ name: 'browser_snapshot' })).toContainTextContent(`
### Downloads ### 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 }) => { test('navigating to download link emits download', async ({ startClient, server, mcpBrowser }, testInfo) => {
const outputDir = localOutputPath('output');
const client = await startClient({ 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'); 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; server: TestServer;
httpsServer: TestServer; httpsServer: TestServer;
mcpHeadless: boolean; mcpHeadless: boolean;
localOutputPath: (filePath: string) => string;
}; };
type WorkerFixtures = { type WorkerFixtures = {
@ -129,13 +128,6 @@ export const test = baseTest.extend<TestFixtures & TestOptions, WorkerFixtures>(
mcpMode: [undefined, { option: true }], 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) => { _workerServers: [async ({}, use, workerInfo) => {
const port = 8907 + workerInfo.workerIndex * 4; const port = 8907 + workerInfo.workerIndex * 4;
const server = await TestServer.create(port); const server = await TestServer.create(port);

View File

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

View File

@ -30,10 +30,9 @@ test('save as pdf unavailable', async ({ startClient, server }) => {
})).toHaveTextContent(/Tool \"browser_pdf_save\" not found/); })).toHaveTextContent(/Tool \"browser_pdf_save\" not found/);
}); });
test('save as pdf', async ({ startClient, mcpBrowser, server, localOutputPath }) => { test('save as pdf', async ({ startClient, mcpBrowser, server }, testInfo) => {
const outputDir = localOutputPath('output');
const client = await startClient({ 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.'); 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/); 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.'); test.skip(!!mcpBrowser && !['chromium', 'chrome', 'msedge'].includes(mcpBrowser), 'Save as PDF is only supported in Chromium.');
const outputDir = localOutputPath('output');
const client = await startClient({ const client = await startClient({
config: { outputDir }, config: { outputDir },
}); });

View File

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

View File

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

View File

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