1'use strict'; 2const common = require('../common'); 3common.skipIfInspectorDisabled(); 4const assert = require('assert'); 5const inspector = require('inspector'); 6const path = require('path'); 7const { pathToFileURL } = require('url'); 8 9// This test case will set a breakpoint 4 lines below 10function debuggedFunction() { 11 let i; 12 let accum = 0; 13 for (i = 0; i < 5; i++) { 14 accum += i; 15 } 16 return accum; 17} 18 19let scopeCallback = null; 20 21function checkScope(session, scopeId) { 22 session.post('Runtime.getProperties', { 23 'objectId': scopeId, 24 'ownProperties': false, 25 'accessorPropertiesOnly': false, 26 'generatePreview': true 27 }, scopeCallback); 28} 29 30function debuggerPausedCallback(session, notification) { 31 const params = notification.params; 32 const callFrame = params.callFrames[0]; 33 const scopeId = callFrame.scopeChain[0].object.objectId; 34 checkScope(session, scopeId); 35} 36 37function waitForWarningSkipAsyncStackTraces(resolve) { 38 process.once('warning', function(warning) { 39 if (warning.code === 'INSPECTOR_ASYNC_STACK_TRACES_NOT_AVAILABLE') { 40 waitForWarningSkipAsyncStackTraces(resolve); 41 } else { 42 resolve(warning); 43 } 44 }); 45} 46 47async function testNoCrashWithExceptionInCallback() { 48 // There is a deliberate exception in the callback 49 const session = new inspector.Session(); 50 session.connect(); 51 const error = new Error('We expect this'); 52 console.log('Expecting warning to be emitted'); 53 const promise = new Promise(waitForWarningSkipAsyncStackTraces); 54 session.post('Console.enable', () => { throw error; }); 55 assert.strictEqual(await promise, error); 56 session.disconnect(); 57} 58 59function testSampleDebugSession() { 60 let cur = 0; 61 const failures = []; 62 const expects = { 63 i: [0, 1, 2, 3, 4], 64 accum: [0, 0, 1, 3, 6] 65 }; 66 scopeCallback = function(error, result) { 67 const i = cur++; 68 let v, actual, expected; 69 for (v of result.result) { 70 actual = v.value.value; 71 expected = expects[v.name][i]; 72 if (actual !== expected) { 73 failures.push(`Iteration ${i} variable: ${v.name} ` + 74 `expected: ${expected} actual: ${actual}`); 75 } 76 } 77 }; 78 const session = new inspector.Session(); 79 session.connect(); 80 session.on('Debugger.paused', 81 (notification) => debuggerPausedCallback(session, notification)); 82 let cbAsSecondArgCalled = false; 83 assert.throws(() => { 84 session.post('Debugger.enable', function() {}, function() {}); 85 }, TypeError); 86 session.post('Debugger.enable', () => cbAsSecondArgCalled = true); 87 session.post('Debugger.setBreakpointByUrl', { 88 'lineNumber': 13, 89 'url': pathToFileURL(path.resolve(__dirname, __filename)).toString(), 90 'columnNumber': 0, 91 'condition': '' 92 }); 93 94 debuggedFunction(); 95 assert.deepStrictEqual(cbAsSecondArgCalled, true); 96 assert.deepStrictEqual(failures, []); 97 assert.strictEqual(cur, 5); 98 scopeCallback = null; 99 session.disconnect(); 100 assert.throws(() => session.post('Debugger.enable'), (e) => !!e); 101} 102 103async function testNoCrashConsoleLogBeforeThrow() { 104 const session = new inspector.Session(); 105 session.connect(); 106 let attempt = 1; 107 process.on('warning', common.mustCall(3)); 108 session.on('inspectorNotification', () => { 109 if (attempt++ > 3) 110 return; 111 console.log('console.log in handler'); 112 throw new Error('Exception in handler'); 113 }); 114 session.post('Runtime.enable'); 115 console.log('Did not crash'); 116 session.disconnect(); 117} 118 119async function doTests() { 120 await testNoCrashWithExceptionInCallback(); 121 testSampleDebugSession(); 122 let breakpointHit = false; 123 scopeCallback = () => (breakpointHit = true); 124 debuggedFunction(); 125 assert.strictEqual(breakpointHit, false); 126 testSampleDebugSession(); 127 await testNoCrashConsoleLogBeforeThrow(); 128} 129 130doTests().then(common.mustCall()); 131