browser_webconsole_errors.js (10961B)
1 /* Any copyright is dedicated to the Public Domain. 2 * http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 // Check if errors are logged as expected 5 6 "use strict"; 7 8 const TEST_URI = `data:text/html;charset=utf8,<!DOCTYPE html>Errors`; 9 10 add_task(async function () { 11 const hud = await openNewTabAndConsole(TEST_URI); 12 13 const TEST_DATA = [ 14 { 15 desc: "ReferenceError: asdf is not defined", 16 expression: ` 17 function bar() { 18 asdf() 19 } 20 function foo() { 21 bar() 22 } 23 24 foo()`, 25 expected: `Uncaught ReferenceError: asdf is not defined`, 26 }, 27 28 { 29 desc: "SyntaxError: redeclaration of let a", 30 expression: `let a, a;`, 31 expected: `SyntaxError: redeclaration of let a`, 32 assert: messageEl => { 33 info("Check that error notes are displayed"); 34 const notes = messageEl.querySelectorAll(".error-note .message-body"); 35 is(notes.length, 1, "There's only one note"); 36 is(notes[0].innerText, "note: Previously declared at line 1, column 5"); 37 }, 38 }, 39 40 { 41 desc: "TypeError longString message", 42 expression: `throw new Error("Long error ".repeat(10000))`, 43 expected: `Uncaught Error: Long error Long error`, 44 }, 45 46 { 47 desc: `throw string with URL`, 48 expression: `throw "“https://evil.com/?${"a".repeat( 49 200 50 )}“ is evil and “https://not-so-evil.com/?${"b".repeat( 51 200 52 )}“ is not good either"`, 53 expected: `Uncaught “https://evil.com/?${"a".repeat( 54 200 55 )}“ is evil and “https://not-so-evil.com/?${"b".repeat( 56 200 57 )}“ is not good either`, 58 assert: messageEl => { 59 const links = messageEl.querySelectorAll(".message-body a.cropped-url"); 60 is(links.length, 2, "2 links are displayed"); 61 62 const evilURL = `https://evil.com/?${"a".repeat(200)}`; 63 const badURL = `https://not-so-evil.com/?${"b".repeat(200)}`; 64 65 is( 66 links[0].getAttribute("href"), 67 evilURL, 68 "first link has expected href" 69 ); 70 is( 71 links[0].getAttribute("title"), 72 evilURL, 73 "first link has expected title" 74 ); 75 76 is( 77 links[1].getAttribute("href"), 78 badURL, 79 "second link has expected href" 80 ); 81 is( 82 links[1].getAttribute("title"), 83 badURL, 84 "second link has expected title" 85 ); 86 }, 87 }, 88 89 { 90 desc: `throw ""`, 91 expression: `throw ""`, 92 expected: `Uncaught <empty string>`, 93 }, 94 { 95 desc: `throw "tomato"`, 96 expression: `throw "tomato"`, 97 expected: `Uncaught tomato`, 98 }, 99 { 100 desc: `throw false`, 101 expression: `throw false`, 102 expected: `Uncaught false`, 103 }, 104 { desc: `throw 0`, expression: `throw 0`, expected: `Uncaught 0` }, 105 { desc: `throw null`, expression: `throw null`, expected: `Uncaught null` }, 106 { 107 desc: `throw undefined`, 108 expression: `throw undefined`, 109 expected: `Uncaught undefined`, 110 }, 111 { 112 desc: `throw Symbol`, 113 expression: `throw Symbol("potato")`, 114 expected: `Uncaught Symbol("potato")`, 115 }, 116 { 117 desc: `throw Object`, 118 expression: `throw {vegetable: "cucumber"}`, 119 expected: `Uncaught Object { vegetable: "cucumber" }`, 120 }, 121 { 122 desc: `throw Error Object`, 123 expression: `throw new Error("pumpkin")`, 124 expected: `Uncaught Error: pumpkin`, 125 }, 126 { 127 desc: `throw Error Object with custom name`, 128 expression: ` 129 var err = new Error("pineapple"); 130 err.name = "JuicyError"; 131 err.flavor = "delicious"; 132 throw err;`, 133 expected: `Uncaught JuicyError: pineapple`, 134 }, 135 { 136 desc: `throw Error Object with error cause`, 137 expression: ` 138 var originalError = new SyntaxError("original error") 139 var err = new Error("something went wrong", { 140 cause: originalError 141 }); 142 throw err;`, 143 expected: `Uncaught Error: something went wrong`, 144 assert: messageEl => { 145 const causeEl = messageEl.querySelector(".error-rep-cause"); 146 is( 147 causeEl.innerText, 148 `Caused by: SyntaxError: original error`, 149 "Caused by show expected" 150 ); 151 }, 152 }, 153 { 154 desc: `throw Error Object with cause chain`, 155 expression: ` 156 var a = new Error("err-a") 157 var b = new Error("err-b", { cause: a }) 158 var c = new Error("err-c", { cause: b }) 159 var d = new Error("err-d", { cause: c }) 160 throw d;`, 161 expected: `Uncaught Error: err-d`, 162 assert: messageEl => { 163 const causeEl = messageEl.querySelector(".error-rep-cause"); 164 is( 165 causeEl.innerText, 166 [ 167 "Caused by: Error: err-c", 168 "Caused by: Error: err-b", 169 "Caused by: Error: err-a", 170 ].join("\n"), 171 "The cause chain is properly displayed" 172 ); 173 }, 174 }, 175 { 176 desc: `throw Error Object with cyclical cause chain`, 177 expression: ` 178 var a = new Error("err-a", { cause: b}) 179 var b = new Error("err-b", { cause: a }) 180 throw b;`, 181 expected: `Uncaught Error: err-b`, 182 assert: messageEl => { 183 const causeEl = messageEl.querySelector(".error-rep-cause"); 184 is( 185 causeEl.innerText, 186 // TODO: This is not how we should display cyclical cause chain, but we have it here 187 // to ensure it's displaying something that makes _some_ sense. 188 // This should be properly handled in Bug 1719605. 189 [ 190 "Caused by: Error: err-a", 191 "Caused by: Error: err-b", 192 "Caused by: Error: err-a", 193 ].join("\n"), 194 "The cyclical cause chain is properly displayed" 195 ); 196 }, 197 }, 198 { 199 desc: `throw Error Object with falsy cause`, 200 expression: `throw new Error("null cause", { cause: null });`, 201 expected: `Uncaught Error: null cause`, 202 assert: messageEl => { 203 const causeEl = messageEl.querySelector(".error-rep-cause"); 204 is( 205 causeEl.innerText, 206 "Caused by: null", 207 "The null cause is properly displayed" 208 ); 209 }, 210 }, 211 { 212 desc: `throw Error Object with number cause`, 213 expression: `throw new Error("number cause", { cause: 0 });`, 214 expected: `Uncaught Error: number cause`, 215 assert: messageEl => { 216 const causeEl = messageEl.querySelector(".error-rep-cause"); 217 is( 218 causeEl.innerText, 219 "Caused by: 0", 220 "The 0 cause is properly displayed" 221 ); 222 }, 223 }, 224 { 225 desc: `throw Error Object with string cause`, 226 expression: `throw new Error("string cause", { cause: "cause message" });`, 227 expected: `Uncaught Error: string cause`, 228 assert: messageEl => { 229 const causeEl = messageEl.querySelector(".error-rep-cause"); 230 is( 231 causeEl.innerText, 232 `Caused by: "cause message"`, 233 "The string cause is properly displayed" 234 ); 235 }, 236 }, 237 { 238 desc: `throw Error Object with object cause`, 239 expression: `throw new Error("object cause", { cause: { code: 234, message: "ERR_234"} });`, 240 expected: `Uncaught Error: object cause`, 241 assert: messageEl => { 242 const causeEl = messageEl.querySelector(".error-rep-cause"); 243 is( 244 causeEl.innerText, 245 `Caused by: Object { … }`, 246 "The object cause is properly displayed" 247 ); 248 }, 249 }, 250 { 251 desc: `Promise reject ""`, 252 expression: `Promise.reject("")`, 253 expected: `Uncaught (in promise) <empty string>`, 254 }, 255 { 256 desc: `Promise reject "tomato"`, 257 expression: `Promise.reject("tomato")`, 258 expected: `Uncaught (in promise) tomato`, 259 }, 260 { 261 desc: `Promise reject false`, 262 expression: `Promise.reject(false)`, 263 expected: `Uncaught (in promise) false`, 264 }, 265 { 266 desc: `Promise reject 0`, 267 expression: `Promise.reject(0)`, 268 expected: `Uncaught (in promise) 0`, 269 }, 270 { 271 desc: `Promise reject null`, 272 expression: `Promise.reject(null)`, 273 expected: `Uncaught (in promise) null`, 274 }, 275 { 276 desc: `Promise reject undefined`, 277 expression: `Promise.reject(undefined)`, 278 expected: `Uncaught (in promise) undefined`, 279 }, 280 { 281 desc: `Promise reject Symbol`, 282 expression: `Promise.reject(Symbol("potato"))`, 283 expected: `Uncaught (in promise) Symbol("potato")`, 284 }, 285 { 286 desc: `Promise reject Object`, 287 expression: `Promise.reject({vegetable: "cucumber"})`, 288 expected: `Uncaught (in promise) Object { vegetable: "cucumber" }`, 289 }, 290 { 291 desc: `Promise reject Error Object`, 292 expression: `Promise.reject(new Error("pumpkin"))`, 293 expected: `Uncaught (in promise) Error: pumpkin`, 294 }, 295 { 296 desc: `Promise reject Error Object with custom name`, 297 expression: ` 298 var err = new Error("pineapple"); 299 err.name = "JuicyError"; 300 err.flavor = "delicious"; 301 Promise.reject(err);`, 302 expected: `Uncaught (in promise) JuicyError: pineapple`, 303 }, 304 { 305 desc: `Promise reject Error Object with error cause`, 306 expression: `Promise.resolve().then(() => { 307 try { 308 unknownFunc(); 309 } catch(e) { 310 throw new Error("something went wrong", { cause: e }) 311 } 312 })`, 313 expected: `Uncaught (in promise) Error: something went wrong`, 314 assert: messageEl => { 315 const causeEl = messageEl.querySelector(".error-rep-cause"); 316 is( 317 causeEl.innerText, 318 `Caused by: ReferenceError: unknownFunc is not defined`, 319 "The cause is properly displayed" 320 ); 321 }, 322 }, 323 ]; 324 325 // javascript.options.experimental.explicit_resource_management is set to true, but it's 326 // only supported on Nightly at the moment 327 if (AppConstants.ENABLE_EXPLICIT_RESOURCE_MANAGEMENT) { 328 TEST_DATA.push({ 329 desc: `SuppressedError`, 330 expression: `throw new SuppressedError( 331 new Error("foo"), 332 new Error("bar"), 333 "the suppressed error message" 334 )`, 335 expected: `Uncaught SuppressedError: the suppressed error message`, 336 }); 337 } 338 339 for (const { desc, expression, expected, assert } of TEST_DATA) { 340 info(`Check error: ${desc}`); 341 342 const onErrorLogged = waitForMessageByType(hud, expected, ".error"); 343 344 await SpecialPowers.spawn( 345 gBrowser.selectedBrowser, 346 [expression], 347 function (expr) { 348 const script = content.document.createElement("script"); 349 script.append(content.document.createTextNode(expr)); 350 content.document.body.append(script); 351 script.remove(); 352 } 353 ); 354 355 const message = await onErrorLogged; 356 if (assert) { 357 assert(message.node); 358 } 359 } 360 });