diff --git a/packages/playwright-core/src/tools/backend/context.ts b/packages/playwright-core/src/tools/backend/context.ts index 91eee5813f0d6..39f6456739657 100644 --- a/packages/playwright-core/src/tools/backend/context.ts +++ b/packages/playwright-core/src/tools/backend/context.ts @@ -15,6 +15,7 @@ */ import fs from 'fs'; +import os from 'os'; import path from 'path'; import { debug } from '../../utilsBundle'; @@ -366,7 +367,11 @@ export async function workspaceFile(options: ContextOptions, fileName: string, p export function outputDir(options: ContextOptions): string { if (options.config.outputDir) return path.resolve(options.config.outputDir); - return path.resolve(options.cwd, options.config.skillMode ? '.playwright-cli' : '.playwright-mcp'); + const subdir = options.config.skillMode ? '.playwright-cli' : '.playwright-mcp'; + const cwd = path.resolve(options.cwd); + if (cwd === path.parse(cwd).root) + return path.join(os.tmpdir(), subdir); + return path.resolve(cwd, subdir); } export async function outputFile(options: ContextOptions, fileName: string, flags: { origin: 'code' | 'llm' }): Promise { diff --git a/tests/mcp/config-resolve.spec.ts b/tests/mcp/config-resolve.spec.ts index f30681c6dc04c..1a0bf6a6deee8 100644 --- a/tests/mcp/config-resolve.spec.ts +++ b/tests/mcp/config-resolve.spec.ts @@ -15,11 +15,13 @@ */ import fs from 'fs'; +import os from 'os'; import path from 'path'; import { test, expect } from '@playwright/test'; import { resolveCLIConfigForCLI, resolveCLIConfigForMCP } from '../../packages/playwright-core/lib/tools/mcp/config'; +import { outputDir } from '../../packages/playwright-core/lib/tools/backend/context'; import type { Config } from '../../packages/playwright-core/src/tools/mcp/config.d'; @@ -464,3 +466,25 @@ test.describe('resolveCLIConfigForCLI - extension', () => { expect(config.browser.isolated).toBe(false); }); }); + +test.describe('outputDir', () => { + test('uses config.outputDir when set', () => { + const dir = outputDir({ config: { outputDir: '/tmp/custom' }, cwd: '/some/project' } as any); + expect(dir).toBe(path.resolve('/tmp/custom')); + }); + + test('uses cwd-relative .playwright-mcp by default', () => { + const dir = outputDir({ config: {}, cwd: '/some/project' } as any); + expect(dir).toBe(path.resolve('/some/project', '.playwright-mcp')); + }); + + test('falls back to tmpdir when cwd is filesystem root', () => { + const dir = outputDir({ config: {}, cwd: '/' } as any); + expect(dir).toBe(path.join(os.tmpdir(), '.playwright-mcp')); + }); + + test('uses .playwright-cli subdir in skillMode', () => { + const dir = outputDir({ config: { skillMode: true }, cwd: '/' } as any); + expect(dir).toBe(path.join(os.tmpdir(), '.playwright-cli')); + }); +});