test_xpcshell_debugging.js (3248B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 "use strict"; 5 6 // Test the xpcshell-test debug support. Ideally we should have this test 7 // next to the xpcshell support code, but that's tricky... 8 9 // HACK: ServiceWorkerManager requires the "profile-change-teardown" to cleanly 10 // shutdown, and setting _profileInitialized to `true` will trigger those 11 // notifications (see /testing/xpcshell/head.js). 12 // eslint-disable-next-line no-undef 13 _profileInitialized = true; 14 15 add_task(async function () { 16 const testFile = do_get_file("xpcshell_debugging_script.js"); 17 18 // _setupDevToolsServer is from xpcshell-test's head.js 19 /* global _setupDevToolsServer */ 20 let testInitialized = false; 21 const { DevToolsServer } = _setupDevToolsServer([testFile.path], () => { 22 testInitialized = true; 23 }); 24 const transport = DevToolsServer.connectPipe(); 25 const client = new DevToolsClient(transport); 26 await client.connect(); 27 28 // Ensure that global actors are available. Just test the device actor. 29 const deviceFront = await client.mainRoot.getFront("device"); 30 const desc = await deviceFront.getDescription(); 31 equal( 32 desc.geckobuildid, 33 Services.appinfo.platformBuildID, 34 "device actor works" 35 ); 36 37 // Even though we have no tabs, getMainProcess gives us the chrome debugger. 38 const commands = await CommandsFactory.forMainProcess({ client }); 39 await commands.targetCommand.startListening(); 40 41 // We have to pass at least one valid thread configuration in order to initialize 42 // the thread actor and make it pause on breakpoint/debugger statements. 43 await commands.threadConfigurationCommand.updateConfiguration({ 44 skipBreakpoints: false, 45 }); 46 const threadFront = 47 await commands.targetCommand.targetFront.getFront("thread"); 48 49 // Checks that the thread actor initializes immediately and that _setupDevToolsServer 50 // callback gets called. 51 ok(testInitialized); 52 53 const onPause = waitForPause(threadFront); 54 55 // Now load our test script, 56 // in another event loop so that the test can keep running! 57 Services.tm.dispatchToMainThread(() => { 58 load(testFile.path); 59 }); 60 61 // and our "paused" listener should get hit. 62 info("Wait for first paused event"); 63 const packet1 = await onPause; 64 equal( 65 packet1.why.type, 66 "breakpoint", 67 "yay - hit the breakpoint at the first line in our script" 68 ); 69 70 // Resume again - next stop should be our "debugger" statement. 71 info("Wait for second pause event"); 72 const packet2 = await resumeAndWaitForPause(threadFront); 73 equal( 74 packet2.why.type, 75 "debuggerStatement", 76 "yay - hit the 'debugger' statement in our script" 77 ); 78 79 info("Dynamically add a breakpoint after the debugger statement"); 80 const breakpointsFront = await commands.watcherFront.getBreakpointListActor(); 81 await breakpointsFront.setBreakpoint( 82 { sourceUrl: testFile.path, line: 11, column: 0 }, 83 {} 84 ); 85 86 // Resume again - next stop should be the new breakpoint. 87 info("Wait for third pause event"); 88 const packet3 = await resumeAndWaitForPause(threadFront); 89 equal( 90 packet3.why.type, 91 "breakpoint", 92 "yay - hit the breakpoint added after starting the test" 93 ); 94 finishClient(client); 95 });