mirror of
https://github.com/hanzoai/playwright.git
synced 2026-09-24 17:01:53 +00:00
fix(mcp): add missing .catch() on sessionLog write queue (#41234)
`SessionLog._sessionFileQueue` chains `appendFile` calls with no `.catch()`.
If a single write rejects (disk full, permissions), the chain stays permanently rejected and all future log entries are silently dropped for the rest of the MCP session.
Add `.catch(e => debug('pw:tools:error')(e))` to match the pattern in `logFile.ts:55`.
This was first introduced in <https://github.com/microsoft/playwright/commit/90e302ba39cf04812054fcd80f633a913dceb46e> (<https://github.com/microsoft/playwright/pull/37286>, 2025-09-03).
This commit is contained in:
@@ -17,6 +17,8 @@
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
import debug from 'debug';
|
||||
|
||||
import { outputFile } from './context';
|
||||
import { parseResponse } from './response';
|
||||
|
||||
@@ -60,6 +62,6 @@ export class SessionLog {
|
||||
}
|
||||
|
||||
lines.push('');
|
||||
this._sessionFileQueue = this._sessionFileQueue.then(() => fs.promises.appendFile(this._file, lines.join('\n')));
|
||||
this._sessionFileQueue = this._sessionFileQueue.then(() => fs.promises.appendFile(this._file, lines.join('\n'))).catch(e => debug('pw:tools:error')(e));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -84,6 +84,53 @@ test('session log should record tool calls', async ({ startClient, server, mcpBr
|
||||
`.trim()));
|
||||
});
|
||||
|
||||
test('session log should recover after write failure', async ({ startClient, server, mcpBrowser }, testInfo) => {
|
||||
test.skip(mcpBrowser === 'webkit');
|
||||
|
||||
const { client, stderr } = await startClient({
|
||||
args: [
|
||||
'--save-session',
|
||||
'--output-dir', testInfo.outputPath('output'),
|
||||
],
|
||||
});
|
||||
|
||||
server.setContent('/', `<title>Title</title><button>Submit</button>`, 'text/html');
|
||||
|
||||
// First call: logs successfully.
|
||||
await client.callTool({
|
||||
name: 'browser_navigate',
|
||||
arguments: { url: server.PREFIX },
|
||||
});
|
||||
|
||||
const output = stderr().split('\n').filter(line => line.startsWith('Session: '))[0];
|
||||
const sessionFolder = output.substring('Session: '.length);
|
||||
const sessionFile = path.join(sessionFolder, 'session.md');
|
||||
|
||||
// Wait for the first entry to be written.
|
||||
await expect.poll(() => readSessionLog(sessionFolder)).toContain('browser_navigate');
|
||||
|
||||
// Make the session file read-only so the next write fails.
|
||||
await fs.promises.chmod(sessionFile, 0o444);
|
||||
|
||||
// Second call: write fails (EACCES) but the chain should recover.
|
||||
await client.callTool({
|
||||
name: 'browser_click',
|
||||
arguments: { element: 'Submit button', target: 'e2' },
|
||||
});
|
||||
|
||||
// Restore write permission.
|
||||
await fs.promises.chmod(sessionFile, 0o644);
|
||||
|
||||
// Third call: without the fix the chain stays rejected and this is never logged.
|
||||
await client.callTool({
|
||||
name: 'browser_click',
|
||||
arguments: { element: 'Submit button', target: 'e2' },
|
||||
});
|
||||
|
||||
// Verify the third call was logged (chain recovered).
|
||||
await expect.poll(() => readSessionLog(sessionFolder)).toContain('browser_click');
|
||||
});
|
||||
|
||||
async function readSessionLog(sessionFolder: string): Promise<string> {
|
||||
return await fs.promises.readFile(path.join(sessionFolder, 'session.md'), 'utf8').catch(() => '');
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user