browser_webconsole_uncaught_exception.js (3647B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 // Test that stack traces are shown when primitive values are thrown instead of 5 // error objects. 6 7 "use strict"; 8 9 const TEST_URI = `data:text/html,<!DOCTYPE html><meta charset=utf8>Test uncaught exception`; 10 11 add_task(async function () { 12 const hud = await openNewTabAndConsole(TEST_URI); 13 14 await checkThrowingWithStack(hud, `"tomato"`, "Uncaught tomato"); 15 await checkThrowingWithStack(hud, `""`, "Uncaught <empty string>"); 16 await checkThrowingWithStack(hud, `42`, "Uncaught 42"); 17 await checkThrowingWithStack(hud, `0`, "Uncaught 0"); 18 await checkThrowingWithStack(hud, `null`, "Uncaught null"); 19 await checkThrowingWithStack(hud, `undefined`, "Uncaught undefined"); 20 await checkThrowingWithStack(hud, `false`, "Uncaught false"); 21 22 await checkThrowingWithStack( 23 hud, 24 `new Error("watermelon")`, 25 "Uncaught Error: watermelon" 26 ); 27 28 await checkThrowingWithStack( 29 hud, 30 `(err = new Error("lettuce"), err.name = "VegetableError", err)`, 31 "Uncaught VegetableError: lettuce" 32 ); 33 34 await checkThrowingWithStack( 35 hud, 36 `{ fav: "eggplant" }`, 37 `Uncaught Object { fav: "eggplant" }` 38 ); 39 40 info("Check custom error with name and message getters"); 41 // register the class 42 await SpecialPowers.spawn(gBrowser.selectedBrowser, [], function () { 43 const script = content.document.createElement("script"); 44 script.append( 45 content.document.createTextNode( 46 ` 47 class CustomError extends Error { 48 get name() { 49 return "CustomErrorName"; 50 } 51 52 get message() { 53 return "custom-error-message"; 54 } 55 }`.trim() 56 ) 57 ); 58 content.document.body.append(script); 59 }); 60 61 await checkThrowingWithStack( 62 hud, 63 `new CustomError()`, 64 "Uncaught CustomErrorName: custom-error-message", 65 // Additional frames: the stacktrace contains the CustomError call 66 [1] 67 ); 68 info("Check that object in errors can be expanded"); 69 const rejectedObjectMessage = findErrorMessage(hud, "eggplant"); 70 const oi = rejectedObjectMessage.querySelector(".tree"); 71 ok(true, "The object was rendered in an ObjectInspector"); 72 73 info("Expanding the object"); 74 const onOiExpanded = waitFor(() => { 75 return oi.querySelectorAll(".node").length === 3; 76 }); 77 oi.querySelector(".theme-twisty").click(); 78 await onOiExpanded; 79 80 ok( 81 oi.querySelector(".theme-twisty").classList.contains("open"), 82 "Object expanded" 83 ); 84 85 // The object inspector now looks like: 86 // Object { fav: "eggplant" } 87 // | fav: "eggplant" 88 // | <prototype>: Object { ... } 89 90 const oiNodes = oi.querySelectorAll(".node"); 91 is(oiNodes.length, 3, "There is the expected number of nodes in the tree"); 92 93 ok(oiNodes[0].textContent.includes(`Object { fav: "eggplant" }`)); 94 ok(oiNodes[1].textContent.includes(`fav: "eggplant"`)); 95 ok(oiNodes[2].textContent.includes(`<prototype>: Object { \u2026 }`)); 96 }); 97 98 async function checkThrowingWithStack( 99 hud, 100 expression, 101 expectedMessage, 102 additionalFrameLines = [] 103 ) { 104 await SpecialPowers.spawn( 105 gBrowser.selectedBrowser, 106 [expression], 107 function (expr) { 108 const script = content.document.createElement("script"); 109 script.append( 110 content.document.createTextNode(` 111 a = () => {throw ${expr}}; 112 b = () => a(); 113 c = () => b(); 114 d = () => c(); 115 d(); 116 `) 117 ); 118 content.document.body.append(script); 119 script.remove(); 120 } 121 ); 122 return checkMessageStack(hud, expectedMessage, [ 123 ...additionalFrameLines, 124 2, 125 3, 126 4, 127 5, 128 6, 129 ]); 130 }