add browser console log capture and fix test contamination
- Add getLatestLogs function to capture and retrieve browser console logs - Support filtering by page, search string/regex, and count limit - Add clearAllLogs function to prevent log persistence across tests - Make console listeners synchronous using page _guid for immediate capture - Add critical test verifying extension reconnection after disconnectEverything - Preserve console logs across browser reconnections for stability
This commit is contained in:
+1
-1
@@ -6,7 +6,7 @@
|
|||||||
"watch": "pnpm -r watch",
|
"watch": "pnpm -r watch",
|
||||||
"build": "pnpm -r build",
|
"build": "pnpm -r build",
|
||||||
"agents.md": "agentsdotmd ./PLAYWRITER_AGENTS.md core.md typescript.md pnpm.md vitest.md changelog.md docs-writing.md github.md playwright.md zod.md gitchamber.md",
|
"agents.md": "agentsdotmd ./PLAYWRITER_AGENTS.md core.md typescript.md pnpm.md vitest.md changelog.md docs-writing.md github.md playwright.md zod.md gitchamber.md",
|
||||||
"release": "pnpm build && changeset"
|
"release": "pnpm build && "
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@changesets/cli": "^2.29.7",
|
"@changesets/cli": "^2.29.7",
|
||||||
|
|||||||
@@ -1,5 +1,22 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.0.10
|
||||||
|
|
||||||
|
### Patch Changes
|
||||||
|
|
||||||
|
- **Browser console log capture**: Added `getLatestLogs` function to capture and retrieve browser console logs
|
||||||
|
- Automatically captures up to 5000 logs per page
|
||||||
|
- Logs cleared on page reload/navigation
|
||||||
|
- Logs deleted when page is closed
|
||||||
|
- Supports filtering by page, search string/regex, and count limit
|
||||||
|
- **Fixed test contamination**: Added `clearAllLogs` function to prevent log persistence across tests
|
||||||
|
- **Improved console listener setup**: Made listeners synchronous using page `_guid` for immediate log capture
|
||||||
|
- **Critical reconnection test**: Added test verifying extension reconnection after `disconnectEverything()`
|
||||||
|
- Tests full disconnect/reconnect cycle
|
||||||
|
- Verifies MCP client can reconnect with `resetPlaywright()`
|
||||||
|
- Ensures pages are visible after reconnection
|
||||||
|
- **Persistent console listeners**: Console logs now persist across browser reconnections (not cleared in `resetConnection`)
|
||||||
|
|
||||||
## 0.0.9
|
## 0.0.9
|
||||||
|
|
||||||
### Patch Changes
|
### Patch Changes
|
||||||
|
|||||||
@@ -706,6 +706,143 @@ describe('MCP Server Tests', () => {
|
|||||||
await page.close()
|
await page.close()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('should be able to reconnect after disconnecting everything', async () => {
|
||||||
|
if (!browserContext) throw new Error('Browser not initialized')
|
||||||
|
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
||||||
|
|
||||||
|
// 1. Use the existing about:blank page from beforeAll
|
||||||
|
const pages = await browserContext.pages()
|
||||||
|
expect(pages.length).toBeGreaterThan(0)
|
||||||
|
const page = pages[0]
|
||||||
|
|
||||||
|
await page.goto('https://example.com/disconnect-test')
|
||||||
|
await page.waitForLoadState('networkidle')
|
||||||
|
await page.bringToFront()
|
||||||
|
|
||||||
|
// Enable extension on this page
|
||||||
|
const initialEnable = await serviceWorker.evaluate(async () => {
|
||||||
|
return await globalThis.toggleExtensionForActiveTab()
|
||||||
|
})
|
||||||
|
console.log('Initial enable result:', initialEnable)
|
||||||
|
expect(initialEnable.isConnected).toBe(true)
|
||||||
|
|
||||||
|
// Wait for extension to fully connect
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 500))
|
||||||
|
|
||||||
|
// Verify MCP can see the page
|
||||||
|
const beforeDisconnect = await client.callTool({
|
||||||
|
name: 'execute',
|
||||||
|
arguments: {
|
||||||
|
code: js`
|
||||||
|
const pages = context.pages();
|
||||||
|
console.log('Pages before disconnect:', pages.length);
|
||||||
|
const testPage = pages.find(p => p.url().includes('disconnect-test'));
|
||||||
|
console.log('Found test page:', !!testPage);
|
||||||
|
return { pagesCount: pages.length, foundTestPage: !!testPage };
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const beforeOutput = (beforeDisconnect as any).content[0].text
|
||||||
|
expect(beforeOutput).toContain('foundTestPage')
|
||||||
|
console.log('Before disconnect:', beforeOutput)
|
||||||
|
|
||||||
|
// 2. Disconnect everything
|
||||||
|
console.log('Calling disconnectEverything...')
|
||||||
|
await serviceWorker.evaluate(async () => {
|
||||||
|
await globalThis.disconnectEverything()
|
||||||
|
})
|
||||||
|
|
||||||
|
// Wait for disconnect to complete
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 500))
|
||||||
|
|
||||||
|
// 3. Verify MCP cannot see the page anymore
|
||||||
|
const afterDisconnect = await client.callTool({
|
||||||
|
name: 'execute',
|
||||||
|
arguments: {
|
||||||
|
code: js`
|
||||||
|
const pages = context.pages();
|
||||||
|
console.log('Pages after disconnect:', pages.length);
|
||||||
|
return { pagesCount: pages.length };
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const afterDisconnectOutput = (afterDisconnect as any).content[0].text
|
||||||
|
console.log('After disconnect:', afterDisconnectOutput)
|
||||||
|
expect(afterDisconnectOutput).toContain('Pages after disconnect: 0')
|
||||||
|
|
||||||
|
// 4. Re-enable extension on the same page
|
||||||
|
console.log('Re-enabling extension...')
|
||||||
|
await page.bringToFront()
|
||||||
|
const reconnectResult = await serviceWorker.evaluate(async () => {
|
||||||
|
console.log('About to call toggleExtensionForActiveTab')
|
||||||
|
const result = await globalThis.toggleExtensionForActiveTab()
|
||||||
|
console.log('toggleExtensionForActiveTab result:', result)
|
||||||
|
return result
|
||||||
|
})
|
||||||
|
|
||||||
|
console.log('Reconnect result:', reconnectResult)
|
||||||
|
expect(reconnectResult.isConnected).toBe(true)
|
||||||
|
|
||||||
|
// Wait for extension to fully reconnect and relay server to be ready
|
||||||
|
console.log('Waiting for reconnection to stabilize...')
|
||||||
|
await new Promise(resolve => setTimeout(resolve, 1000))
|
||||||
|
|
||||||
|
// 5. Reset the MCP client's playwright connection since it was closed by disconnectEverything
|
||||||
|
console.log('Resetting MCP playwright connection...')
|
||||||
|
const resetResult = await client.callTool({
|
||||||
|
name: 'execute',
|
||||||
|
arguments: {
|
||||||
|
code: js`
|
||||||
|
console.log('Resetting playwright connection');
|
||||||
|
const result = await resetPlaywright();
|
||||||
|
console.log('Reset complete, checking pages');
|
||||||
|
const pages = context.pages();
|
||||||
|
console.log('Pages after reset:', pages.length);
|
||||||
|
return { reset: true, pagesCount: pages.length };
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
console.log('Reset result:', (resetResult as any).content[0].text)
|
||||||
|
|
||||||
|
// 6. Verify MCP can see the page again
|
||||||
|
console.log('Attempting to access page via MCP...')
|
||||||
|
const afterReconnect = await client.callTool({
|
||||||
|
name: 'execute',
|
||||||
|
arguments: {
|
||||||
|
code: js`
|
||||||
|
console.log('Checking pages after reconnect...');
|
||||||
|
const pages = context.pages();
|
||||||
|
console.log('Pages after reconnect:', pages.length);
|
||||||
|
|
||||||
|
if (pages.length === 0) {
|
||||||
|
console.log('No pages found!');
|
||||||
|
return { pagesCount: 0, foundTestPage: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
const testPage = pages.find(p => p.url().includes('disconnect-test'));
|
||||||
|
console.log('Found test page after reconnect:', !!testPage);
|
||||||
|
|
||||||
|
if (testPage) {
|
||||||
|
console.log('Test page URL:', testPage.url());
|
||||||
|
return { pagesCount: pages.length, foundTestPage: true, url: testPage.url() };
|
||||||
|
}
|
||||||
|
|
||||||
|
return { pagesCount: pages.length, foundTestPage: false };
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const afterReconnectOutput = (afterReconnect as any).content[0].text
|
||||||
|
console.log('After reconnect:', afterReconnectOutput)
|
||||||
|
expect(afterReconnectOutput).toContain('foundTestPage')
|
||||||
|
expect(afterReconnectOutput).toContain('disconnect-test')
|
||||||
|
|
||||||
|
// Clean up - navigate page back to about:blank to not interfere with other tests
|
||||||
|
await page.goto('about:blank')
|
||||||
|
})
|
||||||
|
|
||||||
it('should capture browser console logs with getLatestLogs', async () => {
|
it('should capture browser console logs with getLatestLogs', async () => {
|
||||||
// Ensure clean state and clear any existing logs
|
// Ensure clean state and clear any existing logs
|
||||||
const resetResult = await client.callTool({
|
const resetResult = await client.callTool({
|
||||||
|
|||||||
@@ -248,8 +248,8 @@ async function resetConnection(): Promise<{ browser: Browser; page: Page; contex
|
|||||||
state.context = null
|
state.context = null
|
||||||
state.isConnected = false
|
state.isConnected = false
|
||||||
|
|
||||||
// Clear all browser logs on reset
|
// DO NOT clear browser logs on reset - logs should persist across reconnections
|
||||||
browserLogs.clear()
|
// browserLogs.clear()
|
||||||
|
|
||||||
await ensureRelayServer()
|
await ensureRelayServer()
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user