document debugger
This commit is contained in:
@@ -7,7 +7,7 @@
|
||||
"types": "dist/index.d.ts",
|
||||
"repository": "https://github.com/remorses/playwriter",
|
||||
"scripts": {
|
||||
"build": "rm -rf dist *.tsbuildinfo && mkdir dist && cp src/resource.md src/prompt.md dist/ && vite-node scripts/download-selector-generator.ts && tsc",
|
||||
"build": "rm -rf dist *.tsbuildinfo && mkdir dist && cp src/resource.md src/prompt.md src/debugger-examples.ts dist/ && vite-node scripts/download-selector-generator.ts && tsc",
|
||||
"prepublishOnly": "pnpm build",
|
||||
"watch": "tsc -w",
|
||||
"typecheck": "tsc --noEmit",
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
import type { Page } from 'playwright-core'
|
||||
import type { CDPSession } from './cdp-session.js'
|
||||
import type { Debugger } from './debugger.js'
|
||||
|
||||
export declare const page: Page
|
||||
export declare const getCDPSession: (options: { page: Page }) => Promise<CDPSession>
|
||||
export declare const createDebugger: (options: { cdp: CDPSession }) => Debugger
|
||||
export declare const console: { log: (...args: unknown[]) => void }
|
||||
@@ -0,0 +1,66 @@
|
||||
import { page, getCDPSession, createDebugger, console } from './debugger-examples-types.js'
|
||||
|
||||
// Example: List available scripts and set a breakpoint
|
||||
async function listScriptsAndSetBreakpoint() {
|
||||
const cdp = await getCDPSession({ page })
|
||||
const dbg = createDebugger({ cdp })
|
||||
await dbg.enable()
|
||||
|
||||
const scripts = dbg.listScripts({ search: 'app' })
|
||||
console.log(scripts)
|
||||
|
||||
if (scripts.length > 0) {
|
||||
const bpId = await dbg.setBreakpoint({ file: scripts[0].url, line: 100 })
|
||||
console.log('Breakpoint set:', bpId)
|
||||
}
|
||||
}
|
||||
|
||||
// Example: Inspect state when paused at a breakpoint
|
||||
async function inspectWhenPaused() {
|
||||
const cdp = await getCDPSession({ page })
|
||||
const dbg = createDebugger({ cdp })
|
||||
await dbg.enable()
|
||||
|
||||
if (dbg.isPaused()) {
|
||||
const loc = await dbg.getLocation()
|
||||
console.log('Paused at:', loc.url, 'line', loc.lineNumber)
|
||||
console.log('Source:', loc.sourceContext)
|
||||
|
||||
const vars = await dbg.inspectVariables({ scope: 'local' })
|
||||
console.log('Variables:', vars)
|
||||
|
||||
const result = await dbg.evaluate({ expression: 'myVar.length' })
|
||||
console.log('myVar.length =', result.value)
|
||||
|
||||
await dbg.stepOver()
|
||||
}
|
||||
}
|
||||
|
||||
// Example: Step through code
|
||||
async function stepThroughCode() {
|
||||
const cdp = await getCDPSession({ page })
|
||||
const dbg = createDebugger({ cdp })
|
||||
await dbg.enable()
|
||||
|
||||
await dbg.setBreakpoint({ file: 'https://example.com/app.js', line: 42 })
|
||||
|
||||
if (dbg.isPaused()) {
|
||||
await dbg.stepOver()
|
||||
await dbg.stepInto()
|
||||
await dbg.stepOut()
|
||||
await dbg.resume()
|
||||
}
|
||||
}
|
||||
|
||||
// Example: Cleanup all breakpoints
|
||||
async function cleanupBreakpoints() {
|
||||
const cdp = await getCDPSession({ page })
|
||||
const dbg = createDebugger({ cdp })
|
||||
|
||||
const breakpoints = dbg.listBreakpoints()
|
||||
for (const bp of breakpoints) {
|
||||
await dbg.deleteBreakpoint({ breakpointId: bp.id })
|
||||
}
|
||||
}
|
||||
|
||||
export { listScriptsAndSetBreakpoint, inspectWhenPaused, stepThroughCode, cleanupBreakpoints }
|
||||
@@ -15,6 +15,7 @@ import { getCdpUrl, LOG_FILE_PATH, VERSION, sleep } from './utils.js'
|
||||
import { killPortProcess } from 'kill-port-process'
|
||||
import { waitForPageLoad, WaitForPageLoadOptions, WaitForPageLoadResult } from './wait-for-page-load.js'
|
||||
import { getCDPSessionForPage, CDPSession } from './cdp-session.js'
|
||||
import { Debugger } from './debugger.js'
|
||||
|
||||
class CodeExecutionTimeoutError extends Error {
|
||||
constructor(timeout: number) {
|
||||
@@ -72,6 +73,7 @@ interface VMContext {
|
||||
clearAllLogs: () => void
|
||||
waitForPageLoad: (options: WaitForPageLoadOptions) => Promise<WaitForPageLoadResult>
|
||||
getCDPSession: (options: { page: Page }) => Promise<CDPSession>
|
||||
createDebugger: (options: { cdp: CDPSession }) => Debugger
|
||||
require: NodeRequire
|
||||
import: (specifier: string) => Promise<any>
|
||||
}
|
||||
@@ -389,6 +391,38 @@ const promptContent =
|
||||
fs.readFileSync(path.join(path.dirname(fileURLToPath(import.meta.url)), 'prompt.md'), 'utf-8') +
|
||||
`\n\nfor debugging internal playwriter errors, check playwriter relay server logs at: ${LOG_FILE_PATH}`
|
||||
|
||||
server.resource('debugger-api', 'playwriter://debugger-api', { mimeType: 'text/plain' }, async () => {
|
||||
const packageJsonPath = require.resolve('playwriter/package.json')
|
||||
const distDir = path.join(path.dirname(packageJsonPath), 'dist')
|
||||
|
||||
const debuggerTypes = fs.readFileSync(path.join(distDir, 'debugger.d.ts'), 'utf-8')
|
||||
const debuggerExamples = fs.readFileSync(path.join(distDir, 'debugger-examples.ts'), 'utf-8')
|
||||
|
||||
return {
|
||||
contents: [
|
||||
{
|
||||
uri: 'playwriter://debugger-api',
|
||||
text: dedent`
|
||||
# Debugger API Reference
|
||||
|
||||
## Types
|
||||
|
||||
\`\`\`ts
|
||||
${debuggerTypes}
|
||||
\`\`\`
|
||||
|
||||
## Examples
|
||||
|
||||
\`\`\`ts
|
||||
${debuggerExamples}
|
||||
\`\`\`
|
||||
`,
|
||||
mimeType: 'text/plain',
|
||||
},
|
||||
],
|
||||
}
|
||||
})
|
||||
|
||||
server.tool(
|
||||
'execute',
|
||||
promptContent,
|
||||
@@ -584,6 +618,10 @@ server.tool(
|
||||
return session
|
||||
}
|
||||
|
||||
const createDebugger = (options: { cdp: CDPSession }) => {
|
||||
return new Debugger(options)
|
||||
}
|
||||
|
||||
let vmContextObj: VMContextWithGlobals = {
|
||||
page,
|
||||
context,
|
||||
@@ -595,6 +633,7 @@ server.tool(
|
||||
clearAllLogs,
|
||||
waitForPageLoad,
|
||||
getCDPSession,
|
||||
createDebugger,
|
||||
resetPlaywright: async () => {
|
||||
const { page: newPage, context: newContext } = await resetConnection()
|
||||
|
||||
@@ -609,6 +648,7 @@ server.tool(
|
||||
clearAllLogs,
|
||||
waitForPageLoad,
|
||||
getCDPSession,
|
||||
createDebugger,
|
||||
resetPlaywright: vmContextObj.resetPlaywright,
|
||||
require,
|
||||
// TODO --experimental-vm-modules is needed to make import work in vm
|
||||
|
||||
@@ -95,13 +95,16 @@ you have access to some functions in addition to playwright methods:
|
||||
- `page`: the page object to create the session for
|
||||
- Returns: `{ send(method, params?), on(event, callback), off(event, callback) }`
|
||||
- Example: `const cdp = await getCDPSession({ page }); const metrics = await cdp.send('Page.getLayoutMetrics');`
|
||||
- Example listening for events:
|
||||
- `createDebugger({ cdp })`: creates a Debugger instance for setting breakpoints, stepping, and inspecting variables. Works with browser JS or Node.js (--inspect).
|
||||
- `cdp`: a CDPSession from `getCDPSession`
|
||||
- Methods: `enable()`, `setBreakpoint({ file, line })`, `deleteBreakpoint({ breakpointId })`, `listBreakpoints()`, `listScripts({ search? })`, `evaluate({ expression })`, `executeCode({ code })`, `inspectVariables({ scope? })`, `getLocation()`, `stepOver()`, `stepInto()`, `stepOut()`, `resume()`, `getConsoleOutput({ limit? })`, `isPaused()`
|
||||
- Example:
|
||||
```js
|
||||
const cdp = await getCDPSession({ page });
|
||||
await cdp.send('Debugger.enable');
|
||||
const pausedEvent = await new Promise((resolve) => { cdp.on('Debugger.paused', resolve); });
|
||||
console.log('Paused at:', pausedEvent.callFrames[0].location);
|
||||
await cdp.send('Debugger.resume');
|
||||
const cdp = await getCDPSession({ page }); const dbg = createDebugger({ cdp }); await dbg.enable();
|
||||
console.log(dbg.listScripts({ search: 'app' }));
|
||||
await dbg.setBreakpoint({ file: 'https://example.com/app.js', line: 42 });
|
||||
// user triggers the code, then:
|
||||
if (dbg.isPaused()) { console.log(await dbg.getLocation()); console.log(await dbg.inspectVariables()); await dbg.resume(); }
|
||||
```
|
||||
|
||||
example:
|
||||
|
||||
Reference in New Issue
Block a user