fix logs tests
This commit is contained in:
@@ -678,12 +678,7 @@ describe('MCP Server Tests', () => {
|
|||||||
if (!browserContext) throw new Error('Browser not initialized')
|
if (!browserContext) throw new Error('Browser not initialized')
|
||||||
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
const serviceWorker = await getExtensionServiceWorker(browserContext)
|
||||||
|
|
||||||
// 1. Ensure clean state (disconnected)
|
// 1. Open a new page (extension not yet enabled for it)
|
||||||
await serviceWorker.evaluate(async () => {
|
|
||||||
await globalThis.disconnectEverything()
|
|
||||||
})
|
|
||||||
|
|
||||||
// 2. Open page and navigate
|
|
||||||
const page = await browserContext.newPage()
|
const page = await browserContext.newPage()
|
||||||
const targetUrl = 'https://example.com/late-enable'
|
const targetUrl = 'https://example.com/late-enable'
|
||||||
await page.goto(targetUrl)
|
await page.goto(targetUrl)
|
||||||
@@ -692,12 +687,12 @@ describe('MCP Server Tests', () => {
|
|||||||
// Wait for load
|
// Wait for load
|
||||||
await page.waitForLoadState('networkidle')
|
await page.waitForLoadState('networkidle')
|
||||||
|
|
||||||
// 3. Enable extension
|
// 2. Enable extension for this page
|
||||||
await serviceWorker.evaluate(async () => {
|
await serviceWorker.evaluate(async () => {
|
||||||
await globalThis.toggleExtensionForActiveTab()
|
await globalThis.toggleExtensionForActiveTab()
|
||||||
})
|
})
|
||||||
|
|
||||||
// 4. Verify via CDP
|
// 3. Verify via CDP that the correct URL is shown
|
||||||
const browser = await chromium.connectOverCDP(getCdpUrl())
|
const browser = await chromium.connectOverCDP(getCdpUrl())
|
||||||
// Wait for sync
|
// Wait for sync
|
||||||
await new Promise(r => setTimeout(r, 1000))
|
await new Promise(r => setTimeout(r, 1000))
|
||||||
@@ -712,6 +707,25 @@ describe('MCP Server Tests', () => {
|
|||||||
})
|
})
|
||||||
|
|
||||||
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
|
||||||
|
const resetResult = await client.callTool({
|
||||||
|
name: 'execute',
|
||||||
|
arguments: {
|
||||||
|
code: js`
|
||||||
|
// Clear any existing logs from previous tests
|
||||||
|
clearAllLogs();
|
||||||
|
console.log('Cleared all existing logs');
|
||||||
|
|
||||||
|
// Verify connection is working
|
||||||
|
const pages = context.pages();
|
||||||
|
console.log('Current pages count:', pages.length);
|
||||||
|
|
||||||
|
return { success: true, pagesCount: pages.length };
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
console.log('Cleanup result:', resetResult)
|
||||||
|
|
||||||
// Create a new page for this test
|
// Create a new page for this test
|
||||||
await client.callTool({
|
await client.callTool({
|
||||||
name: 'execute',
|
name: 'execute',
|
||||||
@@ -844,6 +858,17 @@ describe('MCP Server Tests', () => {
|
|||||||
}, 30000)
|
}, 30000)
|
||||||
|
|
||||||
it('should keep logs separate between different pages', async () => {
|
it('should keep logs separate between different pages', async () => {
|
||||||
|
// Clear any existing logs from previous tests
|
||||||
|
await client.callTool({
|
||||||
|
name: 'execute',
|
||||||
|
arguments: {
|
||||||
|
code: js`
|
||||||
|
clearAllLogs();
|
||||||
|
console.log('Cleared all existing logs for second log test');
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
// Create two pages
|
// Create two pages
|
||||||
await client.callTool({
|
await client.callTool({
|
||||||
name: 'execute',
|
name: 'execute',
|
||||||
|
|||||||
+65
-42
@@ -58,6 +58,7 @@ interface VMContext {
|
|||||||
count?: number
|
count?: number
|
||||||
searchFilter?: string | RegExp
|
searchFilter?: string | RegExp
|
||||||
}) => Promise<string[]>
|
}) => Promise<string[]>
|
||||||
|
clearAllLogs: () => void
|
||||||
require: NodeRequire
|
require: NodeRequire
|
||||||
import: (specifier: string) => Promise<any>
|
import: (specifier: string) => Promise<any>
|
||||||
}
|
}
|
||||||
@@ -126,7 +127,7 @@ async function ensureConnection(): Promise<{ browser: Browser; page: Page }> {
|
|||||||
const contexts = browser.contexts()
|
const contexts = browser.contexts()
|
||||||
const context = contexts.length > 0 ? contexts[0] : await browser.newContext()
|
const context = contexts.length > 0 ? contexts[0] : await browser.newContext()
|
||||||
|
|
||||||
// Set up console listener for all pages
|
// Set up console listener for all future pages
|
||||||
context.on('page', (page) => {
|
context.on('page', (page) => {
|
||||||
setupPageConsoleListener(page)
|
setupPageConsoleListener(page)
|
||||||
})
|
})
|
||||||
@@ -134,8 +135,8 @@ async function ensureConnection(): Promise<{ browser: Browser; page: Page }> {
|
|||||||
const pages = context.pages()
|
const pages = context.pages()
|
||||||
const page = pages.length > 0 ? pages[0] : await context.newPage()
|
const page = pages.length > 0 ? pages[0] : await context.newPage()
|
||||||
|
|
||||||
// Set up console listener for existing pages
|
// Set up console listener for all existing pages (including the one we might have just created)
|
||||||
pages.forEach(p => setupPageConsoleListener(p))
|
context.pages().forEach(p => setupPageConsoleListener(p))
|
||||||
|
|
||||||
state.browser = browser
|
state.browser = browser
|
||||||
state.page = page
|
state.page = page
|
||||||
@@ -146,55 +147,68 @@ async function ensureConnection(): Promise<{ browser: Browser; page: Page }> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async function getPageTargetId(page: Page): Promise<string> {
|
async function getPageTargetId(page: Page): Promise<string> {
|
||||||
|
if (!page) {
|
||||||
|
throw new Error('Page is null or undefined')
|
||||||
|
}
|
||||||
|
|
||||||
|
// Always use internal _guid for consistency and speed
|
||||||
|
const guid = (page as any)._guid
|
||||||
|
if (guid) {
|
||||||
|
return guid
|
||||||
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Get CDP session and fetch target info
|
// Fallback to CDP if _guid is not available
|
||||||
const client = await page.context().newCDPSession(page)
|
const client = await page.context().newCDPSession(page)
|
||||||
const { targetInfo } = await client.send('Target.getTargetInfo')
|
const { targetInfo } = await client.send('Target.getTargetInfo')
|
||||||
await client.detach()
|
await client.detach()
|
||||||
|
|
||||||
return targetInfo.targetId
|
return targetInfo.targetId
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Fallback to using internal _guid if CDP fails
|
throw new Error(`Could not get page identifier: ${e}`)
|
||||||
const guid = (page as any)._guid
|
|
||||||
if (guid) {
|
|
||||||
return guid
|
|
||||||
}
|
|
||||||
throw new Error('Could not get page identifier')
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupPageConsoleListener(page: Page) {
|
function setupPageConsoleListener(page: Page) {
|
||||||
// Get targetId once when setting up the listener
|
// Get targetId synchronously using _guid
|
||||||
getPageTargetId(page).then(targetId => {
|
const targetId = (page as any)._guid as string | undefined
|
||||||
// Clear logs on navigation/reload
|
|
||||||
page.on('framenavigated', (frame) => {
|
if (!targetId) {
|
||||||
// Only clear if it's the main frame navigating (page reload/navigation)
|
// If no _guid, silently fail - this shouldn't happen in normal operation
|
||||||
if (frame === page.mainFrame()) {
|
return
|
||||||
browserLogs.set(targetId, [])
|
}
|
||||||
}
|
|
||||||
})
|
// Initialize logs array for this page
|
||||||
|
if (!browserLogs.has(targetId)) {
|
||||||
|
browserLogs.set(targetId, [])
|
||||||
|
}
|
||||||
|
|
||||||
|
// Clear logs on navigation/reload
|
||||||
|
page.on('framenavigated', (frame) => {
|
||||||
|
// Only clear if it's the main frame navigating (page reload/navigation)
|
||||||
|
if (frame === page.mainFrame()) {
|
||||||
|
browserLogs.set(targetId, [])
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
// Delete logs when page is closed
|
||||||
|
page.on('close', () => {
|
||||||
|
browserLogs.delete(targetId)
|
||||||
|
})
|
||||||
|
|
||||||
|
page.on('console', (msg) => {
|
||||||
|
const logEntry = `[${msg.type()}] ${msg.text()}`
|
||||||
|
|
||||||
// Delete logs when page is closed
|
// Get or create logs array for this page targetId
|
||||||
page.on('close', () => {
|
if (!browserLogs.has(targetId)) {
|
||||||
browserLogs.delete(targetId)
|
browserLogs.set(targetId, [])
|
||||||
})
|
}
|
||||||
|
const pageLogs = browserLogs.get(targetId)!
|
||||||
|
|
||||||
page.on('console', (msg) => {
|
pageLogs.push(logEntry)
|
||||||
const logEntry = `[${msg.type()}] ${msg.text()}`
|
if (pageLogs.length > MAX_LOGS_PER_PAGE) {
|
||||||
|
pageLogs.shift()
|
||||||
// Get or create logs array for this page targetId
|
}
|
||||||
if (!browserLogs.has(targetId)) {
|
|
||||||
browserLogs.set(targetId, [])
|
|
||||||
}
|
|
||||||
const pageLogs = browserLogs.get(targetId)!
|
|
||||||
|
|
||||||
pageLogs.push(logEntry)
|
|
||||||
if (pageLogs.length > MAX_LOGS_PER_PAGE) {
|
|
||||||
pageLogs.shift()
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}).catch(err => {
|
|
||||||
// Silently fail - page might be closed or CDP might not be available
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -233,6 +247,9 @@ async function resetConnection(): Promise<{ browser: Browser; page: Page; contex
|
|||||||
state.page = null
|
state.page = null
|
||||||
state.context = null
|
state.context = null
|
||||||
state.isConnected = false
|
state.isConnected = false
|
||||||
|
|
||||||
|
// Clear all browser logs on reset
|
||||||
|
browserLogs.clear()
|
||||||
|
|
||||||
await ensureRelayServer()
|
await ensureRelayServer()
|
||||||
|
|
||||||
@@ -242,7 +259,7 @@ async function resetConnection(): Promise<{ browser: Browser; page: Page; contex
|
|||||||
const contexts = browser.contexts()
|
const contexts = browser.contexts()
|
||||||
const context = contexts.length > 0 ? contexts[0] : await browser.newContext()
|
const context = contexts.length > 0 ? contexts[0] : await browser.newContext()
|
||||||
|
|
||||||
// Set up console listener for all pages
|
// Set up console listener for all future pages
|
||||||
context.on('page', (page) => {
|
context.on('page', (page) => {
|
||||||
setupPageConsoleListener(page)
|
setupPageConsoleListener(page)
|
||||||
})
|
})
|
||||||
@@ -250,8 +267,8 @@ async function resetConnection(): Promise<{ browser: Browser; page: Page; contex
|
|||||||
const pages = context.pages()
|
const pages = context.pages()
|
||||||
const page = pages.length > 0 ? pages[0] : await context.newPage()
|
const page = pages.length > 0 ? pages[0] : await context.newPage()
|
||||||
|
|
||||||
// Set up console listener for existing pages
|
// Set up console listener for all existing pages (including the one we might have just created)
|
||||||
pages.forEach(p => setupPageConsoleListener(p))
|
context.pages().forEach(p => setupPageConsoleListener(p))
|
||||||
|
|
||||||
state.browser = browser
|
state.browser = browser
|
||||||
state.page = page
|
state.page = page
|
||||||
@@ -421,6 +438,10 @@ server.tool(
|
|||||||
// Return all logs or limited count
|
// Return all logs or limited count
|
||||||
return count !== undefined ? allLogs.slice(-count) : allLogs
|
return count !== undefined ? allLogs.slice(-count) : allLogs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const clearAllLogs = () => {
|
||||||
|
browserLogs.clear()
|
||||||
|
}
|
||||||
|
|
||||||
let vmContextObj: VMContextWithGlobals = {
|
let vmContextObj: VMContextWithGlobals = {
|
||||||
page,
|
page,
|
||||||
@@ -430,6 +451,7 @@ server.tool(
|
|||||||
accessibilitySnapshot,
|
accessibilitySnapshot,
|
||||||
getLocatorStringForElement,
|
getLocatorStringForElement,
|
||||||
getLatestLogs,
|
getLatestLogs,
|
||||||
|
clearAllLogs,
|
||||||
resetPlaywright: async () => {
|
resetPlaywright: async () => {
|
||||||
const { page: newPage, context: newContext } = await resetConnection()
|
const { page: newPage, context: newContext } = await resetConnection()
|
||||||
|
|
||||||
@@ -443,6 +465,7 @@ server.tool(
|
|||||||
accessibilitySnapshot,
|
accessibilitySnapshot,
|
||||||
getLocatorStringForElement,
|
getLocatorStringForElement,
|
||||||
getLatestLogs,
|
getLatestLogs,
|
||||||
|
clearAllLogs,
|
||||||
resetPlaywright: vmContextObj.resetPlaywright,
|
resetPlaywright: vmContextObj.resetPlaywright,
|
||||||
require,
|
require,
|
||||||
import: vmContextObj.import,
|
import: vmContextObj.import,
|
||||||
|
|||||||
Reference in New Issue
Block a user