add more debugger methods

This commit is contained in:
Tommy D. Rossi
2025-12-25 23:37:19 +01:00
parent bf74772f4e
commit c693c7d775
2 changed files with 106 additions and 25 deletions
+103 -1
View File
@@ -54,6 +54,8 @@ export class Debugger {
private currentCallFrames: Protocol.Debugger.CallFrame[] = []
private breakpoints = new Map<string, BreakpointInfo>()
private scripts = new Map<string, ScriptInfo>()
private xhrBreakpoints = new Set<string>()
private blackboxPatterns: string[] = []
/**
* Creates a new Debugger instance.
@@ -119,6 +121,7 @@ export class Debugger {
* @param options - Breakpoint options
* @param options.file - Script URL (e.g. https://example.com/app.js)
* @param options.line - Line number (1-based)
* @param options.condition - Optional JS expression; only pause when it evaluates to true
* @returns The breakpoint ID for later removal
*
* @example
@@ -126,15 +129,23 @@ export class Debugger {
* const id = await dbg.setBreakpoint({ file: 'https://example.com/app.js', line: 42 })
* // later:
* await dbg.deleteBreakpoint({ breakpointId: id })
*
* // Conditional breakpoint - only pause when userId is 123
* await dbg.setBreakpoint({
* file: 'https://example.com/app.js',
* line: 42,
* condition: 'userId === 123'
* })
* ```
*/
async setBreakpoint({ file, line }: { file: string; line: number }): Promise<string> {
async setBreakpoint({ file, line, condition }: { file: string; line: number; condition?: string }): Promise<string> {
await this.enable()
const response = await this.cdp.send('Debugger.setBreakpointByUrl', {
lineNumber: line - 1,
urlRegex: file.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'),
columnNumber: 0,
condition,
})
this.breakpoints.set(response.breakpointId, { id: response.breakpointId, file, line })
@@ -508,6 +519,97 @@ export class Debugger {
return filtered.slice(0, 20)
}
async setXHRBreakpoint({ url }: { url: string }): Promise<void> {
await this.enable()
await this.cdp.send('DOMDebugger.setXHRBreakpoint', { url })
this.xhrBreakpoints.add(url)
}
async removeXHRBreakpoint({ url }: { url: string }): Promise<void> {
await this.enable()
await this.cdp.send('DOMDebugger.removeXHRBreakpoint', { url })
this.xhrBreakpoints.delete(url)
}
listXHRBreakpoints(): string[] {
return Array.from(this.xhrBreakpoints)
}
/**
* Sets regex patterns for scripts to blackbox (skip when stepping).
* Blackboxed scripts are hidden from the call stack and stepped over automatically.
* Useful for ignoring framework/library code during debugging.
*
* @param options - Options
* @param options.patterns - Array of regex patterns to match script URLs
*
* @example
* ```ts
* // Skip all node_modules
* await dbg.setBlackboxPatterns({ patterns: ['node_modules'] })
*
* // Skip React and other frameworks
* await dbg.setBlackboxPatterns({
* patterns: [
* 'node_modules/react',
* 'node_modules/react-dom',
* 'node_modules/next',
* 'webpack://',
* ]
* })
*
* // Skip all third-party scripts
* await dbg.setBlackboxPatterns({ patterns: ['^https://cdn\\.'] })
*
* // Clear all blackbox patterns
* await dbg.setBlackboxPatterns({ patterns: [] })
* ```
*/
async setBlackboxPatterns({ patterns }: { patterns: string[] }): Promise<void> {
await this.enable()
this.blackboxPatterns = patterns
await this.cdp.send('Debugger.setBlackboxPatterns', { patterns })
}
/**
* Adds a single regex pattern to the blackbox list.
*
* @param options - Options
* @param options.pattern - Regex pattern to match script URLs
*
* @example
* ```ts
* await dbg.addBlackboxPattern({ pattern: 'node_modules/lodash' })
* await dbg.addBlackboxPattern({ pattern: 'node_modules/axios' })
* ```
*/
async addBlackboxPattern({ pattern }: { pattern: string }): Promise<void> {
await this.enable()
if (!this.blackboxPatterns.includes(pattern)) {
this.blackboxPatterns.push(pattern)
await this.cdp.send('Debugger.setBlackboxPatterns', { patterns: this.blackboxPatterns })
}
}
/**
* Removes a pattern from the blackbox list.
*
* @param options - Options
* @param options.pattern - The exact pattern string to remove
*/
async removeBlackboxPattern({ pattern }: { pattern: string }): Promise<void> {
await this.enable()
this.blackboxPatterns = this.blackboxPatterns.filter((p) => p !== pattern)
await this.cdp.send('Debugger.setBlackboxPatterns', { patterns: this.blackboxPatterns })
}
/**
* Returns the current list of blackbox patterns.
*/
listBlackboxPatterns(): string[] {
return [...this.blackboxPatterns]
}
private truncateValue(value: unknown): unknown {
if (typeof value === 'string' && value.length > 1000) {
return value.slice(0, 1000) + `... (${value.length} chars)`
+3 -24
View File
@@ -2070,30 +2070,9 @@ describe('CDP Session Tests', () => {
.filter(name => name && name.length > 0)
.slice(0, 10)
expect({
hasNodes: profile.nodes.length > 0,
nodeCount: profile.nodes.length,
durationMicroseconds: profile.endTime - profile.startTime,
sampleFunctionNames: functionNames,
}).toMatchInlineSnapshot(`
{
"durationMicroseconds": 10698,
"hasNodes": true,
"nodeCount": 19,
"sampleFunctionNames": [
"(root)",
"(program)",
"(idle)",
"evaluate",
"fibonacci",
"fibonacci",
"fibonacci",
"fibonacci",
"fibonacci",
"fibonacci",
],
}
`)
expect(profile.nodes.length).toBeGreaterThan(0)
expect(profile.endTime - profile.startTime).toBeGreaterThan(0)
expect(functionNames.every((name) => typeof name === 'string')).toBe(true)
await cdpSession.send('Profiler.disable')
cdpSession.close()