blob: 4c3b9275f312c910f988dffb17d821a30ebf83e0 [file] [edit]
<!DOCTYPE html>
<title>DOMException has a stack property, like other errors</title>
<body>
<p>DOMException has the [[ErrorData]] internal slot, and its JS wrapper is a JSC ErrorInstance, so
it exposes the same non-standard stack/line/column/sourceURL properties that a plain Error does.
This matches Firefox (which also reports a stack for DOMException) and is what the WebIDL
web-platform-test "If the implementation has a stack property on normal errors, it also does on
DOMExceptions" requires. This test can be run directly in any browser to compare behavior.</p>
<pre id="log"></pre>
<script>
if (window.testRunner)
testRunner.dumpAsText();
var log = [];
function check(description, actual, expected) {
var pass = actual === expected;
log.push((pass ? "PASS" : "FAIL") + ": " + description + " is " + JSON.stringify(actual)
+ (pass ? "" : ", expected " + JSON.stringify(expected)));
}
// WebTransportError is a DOMException subclass, but is only present when WebTransport is enabled.
// The checks involving it are guarded with "!window.WebTransportError || ..." so that this test
// produces identical output whether or not WebTransport is enabled.
check("typeof new DOMException().stack", typeof new DOMException().stack, "string");
check("typeof new WebTransportError().stack", !window.WebTransportError || typeof new WebTransportError().stack === "string", true);
// The stack is an own property with the same attributes a plain Error's stack has.
var domExceptionDesc = Object.getOwnPropertyDescriptor(new DOMException(), "stack");
var errorDesc = Object.getOwnPropertyDescriptor(new Error(), "stack");
check("DOMException stack is an own property", !!domExceptionDesc, true);
check("DOMException stack writable matches Error", domExceptionDesc.writable, errorDesc.writable);
check("DOMException stack enumerable matches Error", domExceptionDesc.enumerable, errorDesc.enumerable);
check("DOMException stack configurable matches Error", domExceptionDesc.configurable, errorDesc.configurable);
// The stack materializes the other WebKit-specific error properties too.
var e = new DOMException("message", "name");
check("typeof e.line", typeof e.line, "number");
check("typeof e.column", typeof e.column, "number");
check("typeof e.sourceURL", typeof e.sourceURL, "string");
// Materializing the stack must not give the exception own name/message properties; those still
// come from the WebIDL getters on DOMException.prototype.
check("e.stack forced", typeof e.stack, "string");
check("e.hasOwnProperty('message')", e.hasOwnProperty("message"), false);
check("e.hasOwnProperty('name')", e.hasOwnProperty("name"), false);
check("e.message", e.message, "message");
check("e.name", e.name, "name");
// Exceptions thrown by DOM APIs get a stack pointing at the code that called them.
function throwFromDOM() {
document.createElement("<invalid>");
}
var thrown;
try {
throwFromDOM();
} catch (exception) {
thrown = exception;
}
check("DOM API threw a DOMException", thrown instanceof DOMException, true);
check("thrown.name", thrown.name, "InvalidCharacterError");
check("thrown.stack names the calling function", thrown.stack.indexOf("throwFromDOM") !== -1, true);
// Error.stackTraceLimit is honored, just as it is for a plain Error.
Error.stackTraceLimit = 0;
check("typeof new DOMException().stack with stackTraceLimit 0", typeof new DOMException().stack, typeof new Error().stack);
Error.stackTraceLimit = 100;
// Structured clone preserves the stack, so a clone reports the same one as the original. Without
// this, structuredClone() would report the stack of the frame that did the deserializing.
var clone = structuredClone(thrown);
check("structuredClone(thrown).stack matches the original", clone.stack === thrown.stack, true);
check("structuredClone(thrown).name", clone.name, thrown.name);
check("structuredClone(thrown).message", clone.message, thrown.message);
check("structuredClone(thrown) is a DOMException", clone instanceof DOMException, true);
document.getElementById("log").textContent = log.join("\n");
</script>
</body>