browser_resources_error_messages.js (24213B)
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 ResourceCommand API around ERROR_MESSAGE 7 // Reproduces assertions from devtools/shared/webconsole/test/chrome/test_page_errors.html 8 9 // Create a simple server so we have a nice sourceName in the resources packets. 10 const httpServer = createTestHTTPServer(); 11 httpServer.registerPathHandler(`/test_page_errors.html`, (req, res) => { 12 res.setStatusLine(req.httpVersion, 200, "OK"); 13 res.write(`<!DOCTYPE html><meta charset=utf8>Test Error Messages`); 14 }); 15 16 const TEST_URI = `http://localhost:${httpServer.identity.primaryPort}/test_page_errors.html`; 17 18 const { getMdnLinkParams } = ChromeUtils.importESModule( 19 "resource://devtools/shared/mdn.mjs" 20 ); 21 22 add_task(async function () { 23 // Disable the preloaded process as it creates processes intermittently 24 // which forces the emission of RDP requests we aren't correctly waiting for. 25 await pushPref("dom.ipc.processPrelaunch.enabled", false); 26 27 await testErrorMessagesResources(); 28 await testErrorMessagesResourcesWithIgnoreExistingResources(); 29 }); 30 31 async function testErrorMessagesResources() { 32 // Open a test tab 33 const tab = await addTab(TEST_URI); 34 35 const { client, resourceCommand, targetCommand } = 36 await initResourceCommand(tab); 37 38 const receivedMessages = []; 39 // The expected messages are the errors, twice (once for cached messages, once for live messages) 40 const expectedMessages = Array.from(expectedPageErrors.values()).concat( 41 Array.from(expectedPageErrors.values()) 42 ); 43 44 info( 45 "Log some errors *before* calling ResourceCommand.watchResources in order to assert" + 46 " the behavior of already existing messages." 47 ); 48 await triggerErrors(tab, resourceCommand); 49 50 let done; 51 const onAllErrorReceived = new Promise(resolve => (done = resolve)); 52 const onAvailable = resources => { 53 for (const resource of resources) { 54 const { pageError } = resource; 55 56 is( 57 resource.targetFront, 58 targetCommand.targetFront, 59 "The targetFront property is the expected one" 60 ); 61 62 if (!pageError.sourceName.includes("test_page_errors")) { 63 info(`Ignore error from unknown source: "${pageError.sourceName}"`); 64 continue; 65 } 66 67 const index = receivedMessages.length; 68 receivedMessages.push(resource); 69 70 const isAlreadyExistingResource = 71 receivedMessages.length <= expectedPageErrors.size; 72 is( 73 resource.isAlreadyExistingResource, 74 isAlreadyExistingResource, 75 "isAlreadyExistingResource has expected value" 76 ); 77 78 info(`checking received page error #${index}: ${pageError.errorMessage}`); 79 ok(pageError, "The resource has a pageError attribute"); 80 checkPageErrorResource(pageError, expectedMessages[index]); 81 82 if (receivedMessages.length == expectedMessages.length) { 83 done(); 84 } 85 } 86 }; 87 88 await resourceCommand.watchResources([resourceCommand.TYPES.ERROR_MESSAGE], { 89 onAvailable, 90 }); 91 92 await BrowserTestUtils.waitForCondition( 93 () => receivedMessages.length === expectedPageErrors.size 94 ); 95 96 info( 97 "Now log errors *after* the call to ResourceCommand.watchResources and after having" + 98 " received all existing messages" 99 ); 100 await triggerErrors(tab, resourceCommand); 101 102 info("Waiting for all expected errors to be received"); 103 await onAllErrorReceived; 104 ok(true, "All the expected errors were received"); 105 106 Services.console.reset(); 107 targetCommand.destroy(); 108 await client.close(); 109 } 110 111 async function testErrorMessagesResourcesWithIgnoreExistingResources() { 112 info("Test ignoreExistingResources option for ERROR_MESSAGE"); 113 const tab = await addTab(TEST_URI); 114 115 const { client, resourceCommand, targetCommand } = 116 await initResourceCommand(tab); 117 118 info( 119 "Check whether onAvailable will not be called with existing error messages" 120 ); 121 await triggerErrors(tab, resourceCommand); 122 123 const availableResources = []; 124 await resourceCommand.watchResources([resourceCommand.TYPES.ERROR_MESSAGE], { 125 onAvailable: resources => availableResources.push(...resources), 126 ignoreExistingResources: true, 127 }); 128 is( 129 availableResources.length, 130 0, 131 "onAvailable wasn't called for existing error messages" 132 ); 133 134 info( 135 "Check whether onAvailable will be called with the future error messages" 136 ); 137 await triggerErrors(tab, resourceCommand); 138 139 const expectedMessages = Array.from(expectedPageErrors.values()); 140 await waitUntil(() => availableResources.length === expectedMessages.length); 141 for (let i = 0; i < expectedMessages.length; i++) { 142 const resource = availableResources[i]; 143 const { pageError } = resource; 144 const expected = expectedMessages[i]; 145 checkPageErrorResource(pageError, expected); 146 is( 147 resource.isAlreadyExistingResource, 148 false, 149 "isAlreadyExistingResource is set to false for live messages" 150 ); 151 } 152 153 Services.console.reset(); 154 targetCommand.destroy(); 155 await client.close(); 156 } 157 158 /** 159 * Triggers all the errors in the content page. 160 */ 161 async function triggerErrors(tab, resourceCommand) { 162 for (const [expression, expected] of expectedPageErrors.entries()) { 163 if ( 164 !expected[noUncaughtException] && 165 !Services.appinfo.browserTabsRemoteAutostart 166 ) { 167 expectUncaughtException(); 168 } 169 170 const { promise: onErrorMessage, resolve } = Promise.withResolvers(); 171 const onAvailable = resources => { 172 if ( 173 resources.some(r => 174 expected.errorMessage.test(r.pageError.errorMessage) 175 ) 176 ) { 177 resolve(); 178 } 179 }; 180 await resourceCommand.watchResources( 181 [resourceCommand.TYPES.ERROR_MESSAGE], 182 { 183 onAvailable, 184 ignoreExistingResources: true, 185 } 186 ); 187 188 await ContentTask.spawn( 189 tab.linkedBrowser, 190 expression, 191 function frameScript(expr) { 192 const document = content.document; 193 const scriptEl = document.createElement("script"); 194 scriptEl.textContent = expr; 195 document.body.appendChild(scriptEl); 196 } 197 ); 198 199 await onErrorMessage; 200 await resourceCommand.unwatchResources( 201 [resourceCommand.TYPES.ERROR_MESSAGE], 202 { 203 onAvailable, 204 } 205 ); 206 } 207 } 208 209 function checkPageErrorResource(pageErrorResource, expected) { 210 // Let's remove test harness related frames in stacktrace 211 const clonedPageErrorResource = { ...pageErrorResource }; 212 if (clonedPageErrorResource.stacktrace) { 213 const index = clonedPageErrorResource.stacktrace.findIndex(frame => 214 frame.filename.startsWith("resource://testing-common/content-task.js") 215 ); 216 if (index > -1) { 217 clonedPageErrorResource.stacktrace = 218 clonedPageErrorResource.stacktrace.slice(0, index); 219 } 220 } 221 checkObject(clonedPageErrorResource, expected); 222 } 223 224 const noUncaughtException = Symbol(); 225 const NUMBER_REGEX = /^\d+$/; 226 // timeStamp are the result of a number in microsecond divided by 1000. 227 // so we can't expect a precise number of decimals, or even if there would 228 // be decimals at all. 229 const FRACTIONAL_NUMBER_REGEX = /^\d+(\.\d{1,3})?$/; 230 231 const mdnUrl = path => 232 `https://developer.mozilla.org/${path}?${getMdnLinkParams("firefox-console-errors")}`; 233 234 const expectedPageErrors = new Map([ 235 [ 236 "document.doTheImpossible();", 237 { 238 errorMessage: /doTheImpossible/, 239 errorMessageName: "JSMSG_NOT_FUNCTION", 240 sourceName: /test_page_errors/, 241 category: "content javascript", 242 timeStamp: FRACTIONAL_NUMBER_REGEX, 243 error: true, 244 warning: false, 245 info: false, 246 lineNumber: NUMBER_REGEX, 247 columnNumber: NUMBER_REGEX, 248 exceptionDocURL: mdnUrl( 249 "docs/Web/JavaScript/Reference/Errors/Not_a_function" 250 ), 251 innerWindowID: NUMBER_REGEX, 252 private: false, 253 stacktrace: [ 254 { 255 filename: /test_page_errors\.html/, 256 lineNumber: 1, 257 columnNumber: 10, 258 functionName: null, 259 }, 260 ], 261 notes: null, 262 chromeContext: false, 263 isPromiseRejection: false, 264 isForwardedFromContentProcess: false, 265 }, 266 ], 267 [ 268 "(42).toString(0);", 269 { 270 errorMessage: /radix/, 271 errorMessageName: "JSMSG_BAD_RADIX", 272 sourceName: /test_page_errors/, 273 category: "content javascript", 274 timeStamp: FRACTIONAL_NUMBER_REGEX, 275 error: true, 276 warning: false, 277 info: false, 278 lineNumber: NUMBER_REGEX, 279 columnNumber: NUMBER_REGEX, 280 exceptionDocURL: mdnUrl("docs/Web/JavaScript/Reference/Errors/Bad_radix"), 281 innerWindowID: NUMBER_REGEX, 282 private: false, 283 stacktrace: [ 284 { 285 filename: /test_page_errors\.html/, 286 lineNumber: 1, 287 columnNumber: 6, 288 functionName: null, 289 }, 290 ], 291 notes: null, 292 chromeContext: false, 293 isPromiseRejection: false, 294 isForwardedFromContentProcess: false, 295 }, 296 ], 297 [ 298 "'use strict'; (Object.freeze({name: 'Elsa', score: 157})).score = 0;", 299 { 300 errorMessage: /read.only/, 301 errorMessageName: "JSMSG_READ_ONLY", 302 sourceName: /test_page_errors/, 303 category: "content javascript", 304 timeStamp: FRACTIONAL_NUMBER_REGEX, 305 error: true, 306 warning: false, 307 info: false, 308 lineNumber: NUMBER_REGEX, 309 columnNumber: NUMBER_REGEX, 310 exceptionDocURL: mdnUrl("docs/Web/JavaScript/Reference/Errors/Read-only"), 311 innerWindowID: NUMBER_REGEX, 312 private: false, 313 stacktrace: [ 314 { 315 filename: /test_page_errors\.html/, 316 lineNumber: 1, 317 columnNumber: 23, 318 functionName: null, 319 }, 320 ], 321 notes: null, 322 chromeContext: false, 323 isPromiseRejection: false, 324 isForwardedFromContentProcess: false, 325 }, 326 ], 327 [ 328 "([]).length = -1", 329 { 330 errorMessage: /array length/, 331 errorMessageName: "JSMSG_BAD_ARRAY_LENGTH", 332 sourceName: /test_page_errors/, 333 category: "content javascript", 334 timeStamp: FRACTIONAL_NUMBER_REGEX, 335 error: true, 336 warning: false, 337 info: false, 338 lineNumber: NUMBER_REGEX, 339 columnNumber: NUMBER_REGEX, 340 exceptionDocURL: mdnUrl( 341 "docs/Web/JavaScript/Reference/Errors/Invalid_array_length" 342 ), 343 innerWindowID: NUMBER_REGEX, 344 private: false, 345 stacktrace: [ 346 { 347 filename: /test_page_errors\.html/, 348 lineNumber: 1, 349 columnNumber: 2, 350 functionName: null, 351 }, 352 ], 353 notes: null, 354 chromeContext: false, 355 isPromiseRejection: false, 356 isForwardedFromContentProcess: false, 357 }, 358 ], 359 [ 360 "'abc'.repeat(-1);", 361 { 362 errorMessage: /repeat count.*non-negative/, 363 errorMessageName: "JSMSG_NEGATIVE_REPETITION_COUNT", 364 sourceName: /test_page_errors/, 365 category: "content javascript", 366 timeStamp: FRACTIONAL_NUMBER_REGEX, 367 error: true, 368 warning: false, 369 info: false, 370 lineNumber: NUMBER_REGEX, 371 columnNumber: NUMBER_REGEX, 372 exceptionDocURL: mdnUrl( 373 "docs/Web/JavaScript/Reference/Errors/Negative_repetition_count" 374 ), 375 innerWindowID: NUMBER_REGEX, 376 private: false, 377 stacktrace: [ 378 { 379 filename: "self-hosted", 380 sourceId: null, 381 lineNumber: NUMBER_REGEX, 382 columnNumber: NUMBER_REGEX, 383 functionName: "repeat", 384 }, 385 { 386 filename: /test_page_errors\.html/, 387 lineNumber: 1, 388 columnNumber: 7, 389 functionName: null, 390 }, 391 ], 392 notes: null, 393 chromeContext: false, 394 isPromiseRejection: false, 395 isForwardedFromContentProcess: false, 396 }, 397 ], 398 [ 399 "'a'.repeat(2e28);", 400 { 401 errorMessage: /repeat count.*less than infinity/, 402 errorMessageName: "JSMSG_RESULTING_STRING_TOO_LARGE", 403 sourceName: /test_page_errors/, 404 category: "content javascript", 405 timeStamp: FRACTIONAL_NUMBER_REGEX, 406 error: true, 407 warning: false, 408 info: false, 409 lineNumber: NUMBER_REGEX, 410 columnNumber: NUMBER_REGEX, 411 exceptionDocURL: mdnUrl( 412 "docs/Web/JavaScript/Reference/Errors/Resulting_string_too_large" 413 ), 414 innerWindowID: NUMBER_REGEX, 415 private: false, 416 stacktrace: [ 417 { 418 filename: "self-hosted", 419 sourceId: null, 420 lineNumber: NUMBER_REGEX, 421 columnNumber: NUMBER_REGEX, 422 functionName: "repeat", 423 }, 424 { 425 filename: /test_page_errors\.html/, 426 lineNumber: 1, 427 columnNumber: 5, 428 functionName: null, 429 }, 430 ], 431 notes: null, 432 chromeContext: false, 433 isPromiseRejection: false, 434 isForwardedFromContentProcess: false, 435 }, 436 ], 437 [ 438 "77.1234.toExponential(-1);", 439 { 440 errorMessage: /out of range/, 441 errorMessageName: "JSMSG_PRECISION_RANGE", 442 sourceName: /test_page_errors/, 443 category: "content javascript", 444 timeStamp: FRACTIONAL_NUMBER_REGEX, 445 error: true, 446 warning: false, 447 info: false, 448 lineNumber: NUMBER_REGEX, 449 columnNumber: NUMBER_REGEX, 450 exceptionDocURL: mdnUrl( 451 "docs/Web/JavaScript/Reference/Errors/Precision_range" 452 ), 453 innerWindowID: NUMBER_REGEX, 454 private: false, 455 stacktrace: [ 456 { 457 filename: /test_page_errors\.html/, 458 lineNumber: 1, 459 columnNumber: 9, 460 functionName: null, 461 }, 462 ], 463 notes: null, 464 chromeContext: false, 465 isPromiseRejection: false, 466 isForwardedFromContentProcess: false, 467 }, 468 ], 469 [ 470 "function a() { return; 1 + 1; }", 471 { 472 errorMessage: /unreachable code/, 473 errorMessageName: "JSMSG_STMT_AFTER_RETURN", 474 sourceName: /test_page_errors/, 475 category: "content javascript", 476 timeStamp: FRACTIONAL_NUMBER_REGEX, 477 error: false, 478 warning: true, 479 info: false, 480 sourceId: null, 481 lineNumber: NUMBER_REGEX, 482 columnNumber: NUMBER_REGEX, 483 exceptionDocURL: mdnUrl( 484 "docs/Web/JavaScript/Reference/Errors/Stmt_after_return" 485 ), 486 innerWindowID: NUMBER_REGEX, 487 private: false, 488 stacktrace: null, 489 notes: null, 490 chromeContext: false, 491 isPromiseRejection: false, 492 isForwardedFromContentProcess: false, 493 }, 494 ], 495 [ 496 "{let a, a;}", 497 { 498 errorMessage: /redeclaration of/, 499 errorMessageName: "JSMSG_REDECLARED_VAR", 500 sourceName: /test_page_errors/, 501 category: "content javascript", 502 timeStamp: FRACTIONAL_NUMBER_REGEX, 503 error: true, 504 warning: false, 505 info: false, 506 sourceId: null, 507 lineNumber: NUMBER_REGEX, 508 columnNumber: NUMBER_REGEX, 509 exceptionDocURL: mdnUrl( 510 "docs/Web/JavaScript/Reference/Errors/Redeclared_parameter" 511 ), 512 innerWindowID: NUMBER_REGEX, 513 private: false, 514 stacktrace: [], 515 chromeContext: false, 516 isPromiseRejection: false, 517 isForwardedFromContentProcess: false, 518 notes: [ 519 { 520 messageBody: /Previously declared at line/, 521 frame: { 522 source: /test_page_errors/, 523 }, 524 }, 525 ], 526 }, 527 ], 528 [ 529 `var error = new TypeError("abc"); 530 error.name = "MyError"; 531 error.message = "here"; 532 throw error`, 533 { 534 errorMessage: /MyError: here/, 535 errorMessageName: "", 536 sourceName: /test_page_errors/, 537 category: "content javascript", 538 timeStamp: FRACTIONAL_NUMBER_REGEX, 539 error: true, 540 warning: false, 541 info: false, 542 lineNumber: NUMBER_REGEX, 543 columnNumber: NUMBER_REGEX, 544 exceptionDocURL: undefined, 545 innerWindowID: NUMBER_REGEX, 546 private: false, 547 stacktrace: [ 548 { 549 filename: /test_page_errors\.html/, 550 lineNumber: 1, 551 columnNumber: 13, 552 functionName: null, 553 }, 554 ], 555 notes: null, 556 chromeContext: false, 557 isPromiseRejection: false, 558 isForwardedFromContentProcess: false, 559 }, 560 ], 561 [ 562 "DOMTokenList.prototype.contains.call([])", 563 { 564 errorMessage: /does not implement interface/, 565 errorMessageName: "MSG_METHOD_THIS_DOES_NOT_IMPLEMENT_INTERFACE", 566 sourceName: /test_page_errors/, 567 category: "content javascript", 568 timeStamp: FRACTIONAL_NUMBER_REGEX, 569 error: true, 570 warning: false, 571 info: false, 572 lineNumber: NUMBER_REGEX, 573 columnNumber: NUMBER_REGEX, 574 exceptionDocURL: undefined, 575 innerWindowID: NUMBER_REGEX, 576 private: false, 577 stacktrace: [ 578 { 579 filename: /test_page_errors\.html/, 580 lineNumber: 1, 581 columnNumber: 33, 582 functionName: null, 583 }, 584 ], 585 notes: null, 586 chromeContext: false, 587 isPromiseRejection: false, 588 isForwardedFromContentProcess: false, 589 }, 590 ], 591 [ 592 ` 593 function promiseThrow() { 594 var error2 = new TypeError("abc"); 595 error2.name = "MyPromiseError"; 596 error2.message = "here2"; 597 return Promise.reject(error2); 598 } 599 promiseThrow()`, 600 { 601 errorMessage: /MyPromiseError: here2/, 602 errorMessageName: "", 603 sourceName: /test_page_errors/, 604 category: "content javascript", 605 timeStamp: FRACTIONAL_NUMBER_REGEX, 606 error: true, 607 warning: false, 608 info: false, 609 lineNumber: NUMBER_REGEX, 610 columnNumber: NUMBER_REGEX, 611 exceptionDocURL: undefined, 612 innerWindowID: NUMBER_REGEX, 613 private: false, 614 stacktrace: [ 615 { 616 filename: /test_page_errors\.html/, 617 sourceId: null, 618 lineNumber: 6, 619 columnNumber: 24, 620 functionName: "promiseThrow", 621 }, 622 { 623 filename: /test_page_errors\.html/, 624 sourceId: null, 625 lineNumber: 8, 626 columnNumber: 7, 627 functionName: null, 628 }, 629 ], 630 notes: null, 631 chromeContext: false, 632 isPromiseRejection: true, 633 isForwardedFromContentProcess: false, 634 [noUncaughtException]: true, 635 }, 636 ], 637 [ 638 // Error with a cause 639 `var originalError = new TypeError("abc"); 640 var error = new Error("something went wrong", { cause: originalError }) 641 throw error`, 642 { 643 errorMessage: /Error: something went wrong/, 644 errorMessageName: "", 645 sourceName: /test_page_errors/, 646 category: "content javascript", 647 timeStamp: FRACTIONAL_NUMBER_REGEX, 648 error: true, 649 warning: false, 650 info: false, 651 lineNumber: NUMBER_REGEX, 652 columnNumber: NUMBER_REGEX, 653 innerWindowID: NUMBER_REGEX, 654 private: false, 655 stacktrace: [ 656 { 657 filename: /test_page_errors\.html/, 658 lineNumber: 2, 659 columnNumber: 19, 660 functionName: null, 661 }, 662 ], 663 exception: { 664 preview: { 665 cause: { 666 class: "TypeError", 667 preview: { 668 message: "abc", 669 }, 670 }, 671 }, 672 }, 673 notes: null, 674 chromeContext: false, 675 isPromiseRejection: false, 676 isForwardedFromContentProcess: false, 677 }, 678 ], 679 [ 680 // Error with a cause chain 681 `var a = new Error("err-a"); 682 var b = new Error("err-b", { cause: a }); 683 var c = new Error("err-c", { cause: b }); 684 var d = new Error("err-d", { cause: c }); 685 throw d`, 686 { 687 errorMessage: /Error: err-d/, 688 errorMessageName: "", 689 sourceName: /test_page_errors/, 690 category: "content javascript", 691 timeStamp: FRACTIONAL_NUMBER_REGEX, 692 error: true, 693 warning: false, 694 info: false, 695 lineNumber: NUMBER_REGEX, 696 columnNumber: NUMBER_REGEX, 697 innerWindowID: NUMBER_REGEX, 698 private: false, 699 stacktrace: [ 700 { 701 filename: /test_page_errors\.html/, 702 lineNumber: 4, 703 columnNumber: 14, 704 functionName: null, 705 }, 706 ], 707 exception: { 708 preview: { 709 cause: { 710 class: "Error", 711 preview: { 712 message: "err-c", 713 cause: { 714 class: "Error", 715 preview: { 716 message: "err-b", 717 cause: { 718 class: "Error", 719 preview: { 720 message: "err-a", 721 }, 722 }, 723 }, 724 }, 725 }, 726 }, 727 }, 728 }, 729 notes: null, 730 chromeContext: false, 731 isPromiseRejection: false, 732 isForwardedFromContentProcess: false, 733 }, 734 ], 735 [ 736 // Error with a null cause 737 `throw new Error("something went wrong", { cause: null })`, 738 { 739 errorMessage: /Error: something went wrong/, 740 errorMessageName: "", 741 sourceName: /test_page_errors/, 742 category: "content javascript", 743 timeStamp: FRACTIONAL_NUMBER_REGEX, 744 error: true, 745 warning: false, 746 info: false, 747 lineNumber: NUMBER_REGEX, 748 columnNumber: NUMBER_REGEX, 749 innerWindowID: NUMBER_REGEX, 750 private: false, 751 stacktrace: [ 752 { 753 filename: /test_page_errors\.html/, 754 lineNumber: 1, 755 columnNumber: 7, 756 functionName: null, 757 }, 758 ], 759 exception: { 760 preview: { 761 cause: { 762 type: "null", 763 }, 764 }, 765 }, 766 notes: null, 767 chromeContext: false, 768 isPromiseRejection: false, 769 isForwardedFromContentProcess: false, 770 }, 771 ], 772 [ 773 // Error with an undefined cause 774 `throw new Error("something went wrong", { cause: undefined })`, 775 { 776 errorMessage: /Error: something went wrong/, 777 errorMessageName: "", 778 sourceName: /test_page_errors/, 779 category: "content javascript", 780 timeStamp: FRACTIONAL_NUMBER_REGEX, 781 error: true, 782 warning: false, 783 info: false, 784 lineNumber: NUMBER_REGEX, 785 columnNumber: NUMBER_REGEX, 786 innerWindowID: NUMBER_REGEX, 787 private: false, 788 stacktrace: [ 789 { 790 filename: /test_page_errors\.html/, 791 lineNumber: 1, 792 columnNumber: 7, 793 functionName: null, 794 }, 795 ], 796 exception: { 797 preview: { 798 cause: { 799 type: "undefined", 800 }, 801 }, 802 }, 803 notes: null, 804 chromeContext: false, 805 isPromiseRejection: false, 806 isForwardedFromContentProcess: false, 807 }, 808 ], 809 [ 810 // Error with a number cause 811 `throw new Error("something went wrong", { cause: 0 })`, 812 { 813 errorMessage: /Error: something went wrong/, 814 errorMessageName: "", 815 sourceName: /test_page_errors/, 816 category: "content javascript", 817 timeStamp: FRACTIONAL_NUMBER_REGEX, 818 error: true, 819 warning: false, 820 info: false, 821 lineNumber: NUMBER_REGEX, 822 columnNumber: NUMBER_REGEX, 823 innerWindowID: NUMBER_REGEX, 824 private: false, 825 stacktrace: [ 826 { 827 filename: /test_page_errors\.html/, 828 lineNumber: 1, 829 columnNumber: 7, 830 functionName: null, 831 }, 832 ], 833 exception: { 834 preview: { 835 cause: 0, 836 }, 837 }, 838 notes: null, 839 chromeContext: false, 840 isPromiseRejection: false, 841 isForwardedFromContentProcess: false, 842 }, 843 ], 844 [ 845 // Error with a string cause 846 `throw new Error("something went wrong", { cause: "ooops" })`, 847 { 848 errorMessage: /Error: something went wrong/, 849 errorMessageName: "", 850 sourceName: /test_page_errors/, 851 category: "content javascript", 852 timeStamp: FRACTIONAL_NUMBER_REGEX, 853 error: true, 854 warning: false, 855 info: false, 856 lineNumber: NUMBER_REGEX, 857 columnNumber: NUMBER_REGEX, 858 innerWindowID: NUMBER_REGEX, 859 private: false, 860 stacktrace: [ 861 { 862 filename: /test_page_errors\.html/, 863 lineNumber: 1, 864 columnNumber: 7, 865 functionName: null, 866 }, 867 ], 868 exception: { 869 preview: { 870 cause: "ooops", 871 }, 872 }, 873 notes: null, 874 chromeContext: false, 875 isPromiseRejection: false, 876 isForwardedFromContentProcess: false, 877 }, 878 ], 879 ]);