| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 364cba6 commit 47e0142
4 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,191 @@ | |||
| 1 | + // Suite for the DOMException interface (Web IDL Standard §4.3). | ||
| 2 | + // | ||
| 3 | + // The suite gates itself on the API being present, so it can sit in | ||
| 4 | + // runAllTests() on every runtime and report a visible pending spec where | ||
| 5 | + // DOMException does not exist yet, rather than being wired in per-runtime. | ||
| 6 | + // | ||
| 7 | + // A runtime that DOES implement it must keep an unguarded canary in its own | ||
| 8 | + // suite asserting the global is there (on iOS: | ||
| 9 | + // TestRunner/app/tests/RuntimeImplementedAPIs.js). Without one, this gate | ||
| 10 | + // would quietly turn a regression that removed the API into a skipped suite. | ||
| 11 | + // | ||
| 12 | + // The integration specs at the bottom assert that OTHER web APIs throw real | ||
| 13 | + // DOMExceptions. Each is additionally gated on that API existing, so a | ||
| 14 | + // runtime that has DOMException but not (say) AbortSignal only skips the | ||
| 15 | + // pairing, not the interface tests. | ||
| 16 | + | ||
| 17 | + var globalObject = typeof globalThis !== "undefined" ? globalThis : global; | ||
| 18 | + | ||
| 19 | + if (typeof globalObject.DOMException === "undefined") { | ||
| 20 | + describe("DOMException", function () { | ||
| 21 | + it("is skipped: this runtime does not implement DOMException", function () { | ||
| 22 | + pending(); | ||
| 23 | + }); | ||
| 24 | + }); | ||
| 25 | + return; | ||
| 26 | + } | ||
| 27 | + | ||
| 28 | + var DOMException = globalObject.DOMException; | ||
| 29 | + | ||
| 30 | + function captureThrown(fn) { | ||
| 31 | + try { | ||
| 32 | + fn(); | ||
| 33 | + } catch (e) { | ||
| 34 | + return e; | ||
| 35 | + } | ||
| 36 | + return null; | ||
| 37 | + } | ||
| 38 | + | ||
| 39 | + // Web IDL §4.3.4: every name in the legacy code table, and the constant that | ||
| 40 | + // mirrors each code. Names outside the table must map to code 0. | ||
| 41 | + var legacyTable = [ | ||
| 42 | + ["IndexSizeError", "INDEX_SIZE_ERR", 1], | ||
| 43 | + ["DOMStringSizeError", "DOMSTRING_SIZE_ERR", 2], | ||
| 44 | + ["HierarchyRequestError", "HIERARCHY_REQUEST_ERR", 3], | ||
| 45 | + ["WrongDocumentError", "WRONG_DOCUMENT_ERR", 4], | ||
| 46 | + ["InvalidCharacterError", "INVALID_CHARACTER_ERR", 5], | ||
| 47 | + ["NoDataAllowedError", "NO_DATA_ALLOWED_ERR", 6], | ||
| 48 | + ["NoModificationAllowedError", "NO_MODIFICATION_ALLOWED_ERR", 7], | ||
| 49 | + ["NotFoundError", "NOT_FOUND_ERR", 8], | ||
| 50 | + ["NotSupportedError", "NOT_SUPPORTED_ERR", 9], | ||
| 51 | + ["InUseAttributeError", "INUSE_ATTRIBUTE_ERR", 10], | ||
| 52 | + ["InvalidStateError", "INVALID_STATE_ERR", 11], | ||
| 53 | + ["SyntaxError", "SYNTAX_ERR", 12], | ||
| 54 | + ["InvalidModificationError", "INVALID_MODIFICATION_ERR", 13], | ||
| 55 | + ["NamespaceError", "NAMESPACE_ERR", 14], | ||
| 56 | + ["InvalidAccessError", "INVALID_ACCESS_ERR", 15], | ||
| 57 | + ["ValidationError", "VALIDATION_ERR", 16], | ||
| 58 | + ["TypeMismatchError", "TYPE_MISMATCH_ERR", 17], | ||
| 59 | + ["SecurityError", "SECURITY_ERR", 18], | ||
| 60 | + ["NetworkError", "NETWORK_ERR", 19], | ||
| 61 | + ["AbortError", "ABORT_ERR", 20], | ||
| 62 | + ["URLMismatchError", "URL_MISMATCH_ERR", 21], | ||
| 63 | + ["QuotaExceededError", "QUOTA_EXCEEDED_ERR", 22], | ||
| 64 | + ["TimeoutError", "TIMEOUT_ERR", 23], | ||
| 65 | + ["InvalidNodeTypeError", "INVALID_NODE_TYPE_ERR", 24], | ||
| 66 | + ["DataCloneError", "DATA_CLONE_ERR", 25], | ||
| 67 | + ]; | ||
| 68 | + | ||
| 69 | + describe("DOMException", function () { | ||
| 70 | + it("constructs with spec defaults", function () { | ||
| 71 | + var e = new DOMException(); | ||
| 72 | + expect(e.message).toBe(""); | ||
| 73 | + expect(e.name).toBe("Error"); | ||
| 74 | + expect(e.code).toBe(0); | ||
| 75 | + }); | ||
| 76 | + | ||
| 77 | + it("takes message and name, converting both to string", function () { | ||
| 78 | + var e = new DOMException("boom", "NotFoundError"); | ||
| 79 | + expect(e.message).toBe("boom"); | ||
| 80 | + expect(e.name).toBe("NotFoundError"); | ||
| 81 | + | ||
| 82 | + var coerced = new DOMException(null, 42); | ||
| 83 | + expect(coerced.message).toBe("null"); | ||
| 84 | + expect(coerced.name).toBe("42"); | ||
| 85 | + }); | ||
| 86 | + | ||
| 87 | + it("treats an explicit undefined message as absent", function () { | ||
| 88 | + expect(new DOMException(undefined, "AbortError").message).toBe(""); | ||
| 89 | + }); | ||
| 90 | + | ||
| 91 | + it("maps every legacy name to its code, on the instance and in the constants", function () { | ||
| 92 | + legacyTable.forEach(function (row) { | ||
| 93 | + var name = row[0], constant = row[1], code = row[2]; | ||
| 94 | + expect(new DOMException("m", name).code).toBe(code); | ||
| 95 | + expect(DOMException[constant]).toBe(code); | ||
| 96 | + expect(DOMException.prototype[constant]).toBe(code); | ||
| 97 | + }); | ||
| 98 | + }); | ||
| 99 | + | ||
| 100 | + it("maps a name outside the legacy table to code 0", function () { | ||
| 101 | + expect(new DOMException("m", "NotAllowedError").code).toBe(0); | ||
| 102 | + expect(new DOMException("m", "NoSuchName").code).toBe(0); | ||
| 103 | + }); | ||
| 104 | + | ||
| 105 | + it("inherits from Error", function () { | ||
| 106 | + var e = new DOMException("m", "AbortError"); | ||
| 107 | + expect(e instanceof DOMException).toBe(true); | ||
| 108 | + expect(e instanceof Error).toBe(true); | ||
| 109 | + expect(Object.getPrototypeOf(DOMException.prototype)).toBe(Error.prototype); | ||
| 110 | + }); | ||
| 111 | + | ||
| 112 | + it("stringifies as name: message through Error.prototype.toString", function () { | ||
| 113 | + expect(String(new DOMException("boom", "NotFoundError"))).toBe("NotFoundError: boom"); | ||
| 114 | + expect(String(new DOMException("", "AbortError"))).toBe("AbortError"); | ||
| 115 | + }); | ||
| 116 | + | ||
| 117 | + it("brands via Object.prototype.toString", function () { | ||
| 118 | + expect(Object.prototype.toString.call(new DOMException())).toBe("[object DOMException]"); | ||
| 119 | + }); | ||
| 120 | + | ||
| 121 | + it("defines name, message and code as prototype accessors", function () { | ||
| 122 | + ["name", "message", "code"].forEach(function (key) { | ||
| 123 | + var desc = Object.getOwnPropertyDescriptor(DOMException.prototype, key); | ||
| 124 | + expect(desc).toBeDefined(); | ||
| 125 | + expect(typeof desc.get).toBe("function"); | ||
| 126 | + expect(desc.set).toBeUndefined(); | ||
| 127 | + }); | ||
| 128 | + }); | ||
| 129 | + | ||
| 130 | + it("rejects a foreign receiver on the accessors", function () { | ||
| 131 | + var get = Object.getOwnPropertyDescriptor(DOMException.prototype, "name").get; | ||
| 132 | + expect(captureThrown(function () { get.call({}); })).not.toBeNull(); | ||
| 133 | + }); | ||
| 134 | + | ||
| 135 | + it("is named DOMException with both constructor arguments optional", function () { | ||
| 136 | + expect(DOMException.name).toBe("DOMException"); | ||
| 137 | + expect(DOMException.length).toBe(0); | ||
| 138 | + }); | ||
| 139 | + | ||
| 140 | + it("carries a stack where this runtime's errors do", function () { | ||
| 141 | + if (typeof new Error().stack !== "string") { | ||
| 142 | + pending(); | ||
| 143 | + return; | ||
| 144 | + } | ||
| 145 | + expect(typeof new DOMException("m", "AbortError").stack).toBe("string"); | ||
| 146 | + }); | ||
| 147 | + }); | ||
| 148 | + | ||
| 149 | + describe("DOMException integration", function () { | ||
| 150 | + var hasAbortSignal = | ||
| 151 | + typeof globalObject.AbortSignal === "function" && | ||
| 152 | + typeof globalObject.AbortSignal.abort === "function"; | ||
| 153 | + | ||
| 154 | + (hasAbortSignal ? it : xit)("is the class of AbortSignal.abort()'s default reason", function () { | ||
| 155 | + var reason = globalObject.AbortSignal.abort().reason; | ||
| 156 | + expect(reason instanceof DOMException).toBe(true); | ||
| 157 | + expect(reason.name).toBe("AbortError"); | ||
| 158 | + expect(reason.code).toBe(DOMException.ABORT_ERR); | ||
| 159 | + }); | ||
| 160 | + | ||
| 161 | + var hasTimeout = | ||
| 162 | + typeof globalObject.AbortSignal === "function" && | ||
| 163 | + typeof globalObject.AbortSignal.timeout === "function"; | ||
| 164 | + | ||
| 165 | + (hasTimeout ? it : xit)("is the class of AbortSignal.timeout()'s reason", function (done) { | ||
| 166 | + var signal = globalObject.AbortSignal.timeout(1); | ||
| 167 | + signal.addEventListener("abort", function () { | ||
| 168 | + expect(signal.reason instanceof DOMException).toBe(true); | ||
| 169 | + expect(signal.reason.name).toBe("TimeoutError"); | ||
| 170 | + done(); | ||
| 171 | + }); | ||
| 172 | + }); | ||
| 173 | + | ||
| 174 | + var hasAtob = typeof globalObject.atob === "function"; | ||
| 175 | + | ||
| 176 | + (hasAtob ? it : xit)("is the class of atob's InvalidCharacterError", function () { | ||
| 177 | + var thrown = captureThrown(function () { globalObject.atob("a"); }); | ||
| 178 | + expect(thrown instanceof DOMException).toBe(true); | ||
| 179 | + expect(thrown.name).toBe("InvalidCharacterError"); | ||
| 180 | + expect(thrown.code).toBe(DOMException.INVALID_CHARACTER_ERR); | ||
| 181 | + }); | ||
| 182 | + | ||
| 183 | + var hasStructuredClone = typeof globalObject.structuredClone === "function"; | ||
| 184 | + | ||
| 185 | + (hasStructuredClone ? it : xit)("is the class of structuredClone's DataCloneError", function () { | ||
| 186 | + var thrown = captureThrown(function () { globalObject.structuredClone(function () {}); }); | ||
| 187 | + expect(thrown instanceof DOMException).toBe(true); | ||
| 188 | + expect(thrown.name).toBe("DataCloneError"); | ||
| 189 | + expect(thrown.code).toBe(DOMException.DATA_CLONE_ERR); | ||
| 190 | + }); | ||
| 191 | + }); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,88 @@ | |||
| 1 | + // Suite for the CustomEvent interface (DOM Standard §2.4). | ||
| 2 | + // | ||
| 3 | + // The suite gates itself on the API being present, so it can sit in | ||
| 4 | + // runAllTests() on every runtime and report a visible pending spec where | ||
| 5 | + // CustomEvent does not exist yet, rather than being wired in per-runtime. | ||
| 6 | + // | ||
| 7 | + // A runtime that DOES implement it must keep an unguarded canary in its own | ||
| 8 | + // suite asserting the global is there (on iOS: | ||
| 9 | + // TestRunner/app/tests/RuntimeImplementedAPIs.js). Without one, this gate | ||
| 10 | + // would quietly turn a regression that removed the API into a skipped suite. | ||
| 11 | + // | ||
| 12 | + // Nothing here asserts constructor arity or missing-argument TypeErrors: | ||
| 13 | + // runtimes differ on how strictly the base Event enforces them, and this | ||
| 14 | + // suite pins CustomEvent's own contract, not Event's. | ||
| 15 | + | ||
| 16 | + var globalObject = typeof globalThis !== "undefined" ? globalThis : global; | ||
| 17 | + | ||
| 18 | + if (typeof globalObject.CustomEvent === "undefined" || typeof globalObject.Event === "undefined") { | ||
| 19 | + describe("CustomEvent", function () { | ||
| 20 | + it("is skipped: this runtime does not implement CustomEvent", function () { | ||
| 21 | + pending(); | ||
| 22 | + }); | ||
| 23 | + }); | ||
| 24 | + return; | ||
| 25 | + } | ||
| 26 | + | ||
| 27 | + var CustomEvent = globalObject.CustomEvent; | ||
| 28 | + var Event = globalObject.Event; | ||
| 29 | + | ||
| 30 | + describe("CustomEvent", function () { | ||
| 31 | + it("constructs an Event of the given type", function () { | ||
| 32 | + var e = new CustomEvent("build"); | ||
| 33 | + expect(e.type).toBe("build"); | ||
| 34 | + expect(e instanceof CustomEvent).toBe(true); | ||
| 35 | + expect(e instanceof Event).toBe(true); | ||
| 36 | + }); | ||
| 37 | + | ||
| 38 | + it("chains its prototype onto Event.prototype", function () { | ||
| 39 | + expect(Object.getPrototypeOf(CustomEvent.prototype)).toBe(Event.prototype); | ||
| 40 | + expect(CustomEvent.prototype.constructor).toBe(CustomEvent); | ||
| 41 | + }); | ||
| 42 | + | ||
| 43 | + it("defaults detail to null", function () { | ||
| 44 | + expect(new CustomEvent("a").detail).toBe(null); | ||
| 45 | + expect(new CustomEvent("a", {}).detail).toBe(null); | ||
| 46 | + expect(new CustomEvent("a", { bubbles: true }).detail).toBe(null); | ||
| 47 | + }); | ||
| 48 | + | ||
| 49 | + it("carries detail through by identity", function () { | ||
| 50 | + var payload = { answer: 42 }; | ||
| 51 | + expect(new CustomEvent("a", { detail: payload }).detail).toBe(payload); | ||
| 52 | + }); | ||
| 53 | + | ||
| 54 | + it("preserves falsy detail values", function () { | ||
| 55 | + expect(new CustomEvent("a", { detail: 0 }).detail).toBe(0); | ||
| 56 | + expect(new CustomEvent("a", { detail: "" }).detail).toBe(""); | ||
| 57 | + expect(new CustomEvent("a", { detail: false }).detail).toBe(false); | ||
| 58 | + expect(new CustomEvent("a", { detail: null }).detail).toBe(null); | ||
| 59 | + }); | ||
| 60 | + | ||
| 61 | + it("honors the Event init flags", function () { | ||
| 62 | + var e = new CustomEvent("a", { bubbles: true, cancelable: true, detail: 1 }); | ||
| 63 | + expect(e.bubbles).toBe(true); | ||
| 64 | + expect(e.cancelable).toBe(true); | ||
| 65 | + }); | ||
| 66 | + | ||
| 67 | + it("supports preventDefault when cancelable", function () { | ||
| 68 | + var e = new CustomEvent("a", { cancelable: true }); | ||
| 69 | + expect(e.defaultPrevented).toBe(false); | ||
| 70 | + e.preventDefault(); | ||
| 71 | + expect(e.defaultPrevented).toBe(true); | ||
| 72 | + }); | ||
| 73 | + | ||
| 74 | + if (typeof globalObject.EventTarget === "function") { | ||
| 75 | + it("dispatches through an EventTarget with detail intact", function () { | ||
| 76 | + var target = new globalObject.EventTarget(); | ||
| 77 | + var payload = { hello: "world" }; | ||
| 78 | + var seen = null; | ||
| 79 | + target.addEventListener("custom", function (event) { | ||
| 80 | + seen = event; | ||
| 81 | + }); | ||
| 82 | + target.dispatchEvent(new CustomEvent("custom", { detail: payload })); | ||
| 83 | + expect(seen).not.toBeNull(); | ||
| 84 | + expect(seen instanceof CustomEvent).toBe(true); | ||
| 85 | + expect(seen.detail).toBe(payload); | ||
| 86 | + }); | ||
| 87 | + } | ||
| 88 | + }); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1 @@ | |||
| 1 | + require("./CustomEvent"); | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -30,6 +30,14 @@ exports.runTextEncodingTests = function() { | |||
| 30 | 30 | require("./TextEncoding"); | |
| 31 | 31 | } | |
| 32 | 32 | ||
| 33 | + exports.runDOMExceptionTests = function() { | ||
| 34 | + require("./DOMException"); | ||
| 35 | + } | ||
| 36 | + | ||
| 37 | + exports.runEventsTests = function() { | ||
| 38 | + require("./Events"); | ||
| 39 | + } | ||
| 40 | + | ||
| 33 | 41 | exports.runAllTests = function() { | |
| 34 | 42 | exports.runImportTests(); | |
| 35 | 43 | exports.runRequireTests(); | |
@@ -39,4 +47,6 @@ exports.runAllTests = function() { | |||
| 39 | 47 | exports.runPerformanceTests(); | |
| 40 | 48 | exports.runStructuredCloneTests(); | |
| 41 | 49 | exports.runTextEncodingTests(); | |
| 50 | + exports.runDOMExceptionTests(); | ||
| 51 | + exports.runEventsTests(); | ||
| 42 | 52 | } | |
| Back | FazBrowse Home | New Git URL |
0 commit comments