/* Any copyright is dedicated to the Public Domain. * http://creativecommons.org/publicdomain/zero/1.0/ */ /* eslint-disable object-shorthand */ // eslint-disable-next-line mozilla/reject-import-system-module-from-non-system import { AppConstants } from "resource://gre/modules/AppConstants.sys.mjs"; // Try replicating real world environment, by using // * a true HTML document // * served from http (https isn't yet supported by nsHttpServer) // * with a regular domain name (example.com) export const TEST_PAGE_HTML = String.raw` Hello there. `; export const CONTEXTS = { JS: "js", PAGE: "page", CHROME: "chrome" }; /** * Manifest covering all the possible JavaScript value types that gecko may create. * This consist in JavaScript code instantiating one of more example values for all of these types. * * See README.md */ const BasicPrimitives = [ { context: CONTEXTS.JS, expression: "undefined", }, { context: CONTEXTS.JS, expression: "null", }, { context: CONTEXTS.JS, expression: "true", }, { context: CONTEXTS.JS, expression: "false", }, { context: CONTEXTS.JS, expression: "NaN", }, ]; const Strings = [ { context: CONTEXTS.JS, expression: `"abc"`, }, { context: CONTEXTS.JS, expression: `"\u9f2c\xFA"`, }, ]; const Numbers = [ { context: CONTEXTS.JS, expression: "42", }, { context: CONTEXTS.JS, expression: "-42", }, { context: CONTEXTS.JS, expression: "-0", }, { context: CONTEXTS.JS, expression: "Infinity", }, { context: CONTEXTS.JS, expression: "BigInt(1000000000000000000)", }, { context: CONTEXTS.JS, expression: "1n", }, { context: CONTEXTS.JS, expression: "-2n", }, { context: CONTEXTS.JS, expression: "0n", }, ]; const Primitives = [...BasicPrimitives, ...Strings, ...Numbers]; const PlainObjects = [ { context: CONTEXTS.JS, expression: "({})" }, { context: CONTEXTS.JS, expression: `({ foo: "bar"})` } ]; const Arrays = [ { context: CONTEXTS.JS, expression: "[]" }, { context: CONTEXTS.JS, expression: "[1]" }, { context: CONTEXTS.JS, expression: '["foo"]' } ]; const TypedArrays = [ { context: CONTEXTS.JS, expression: "new BigInt64Array()" }, { context: CONTEXTS.JS, expression: ` const a = new BigInt64Array(1); a[0] = BigInt(42); a; `, }, ]; const Maps = [ { context: CONTEXTS.JS, expression: `new Map( Array.from({ length: 2 }).map((el, i) => [ { key: i }, { object: 42 }, ]) )`, }, { context: CONTEXTS.JS, expression: `new Map(Array.from({ length: 20 }).map((el, i) => [Symbol(i), i]))`, }, { context: CONTEXTS.JS, expression: `new Map(Array.from({ length: 331 }).map((el, i) => [Symbol(i), i]))`, }, ]; const Sets = [ { context: CONTEXTS.JS, expression: `new Set(Array.from({ length: 2 }).map((el, i) => ({ value: i })))`, }, { context: CONTEXTS.JS, expression: `new Set(Array.from({ length: 20 }).map((el, i) => i))` }, { context: CONTEXTS.JS, expression: `new Set(Array.from({ length: 222 }).map((el, i) => i))` }, ]; const Temporals = [ { context: CONTEXTS.JS, expression: `new Temporal.Instant(355924804000000000n)` }, { context: CONTEXTS.JS, expression: `new Temporal.PlainDate(2021, 7, 1, "coptic")` }, { context: CONTEXTS.JS, expression: `new Temporal.PlainDateTime(2021, 7, 1, 0, 0, 0, 0, 0, 0, "gregory")`, }, { context: CONTEXTS.JS, expression: `new Temporal.PlainMonthDay(7, 1, "chinese")` }, { context: CONTEXTS.JS, expression: `new Temporal.PlainTime(4, 20)` }, { context: CONTEXTS.JS, expression: `new Temporal.PlainYearMonth(2021, 7, "indian")` }, { context: CONTEXTS.JS, expression: `new Temporal.ZonedDateTime(0n, "America/New_York")` }, { context: CONTEXTS.JS, expression: `Temporal.Duration.from({ years: 1 })` }, ]; const DOMAPIs = [ { context: CONTEXTS.PAGE, expression: `myPolicy.createHTML("hello")`, prefs: [["dom.security.trusted_types.enabled", true]], }, { context: CONTEXTS.PAGE, expression: `myPolicy.createScript("const hello = 'world'")` }, { context: CONTEXTS.PAGE, expression: `myPolicy.createScriptURL("https://example.com/trusted")` }, { context: CONTEXTS.PAGE, expression: ` const formData = new FormData(); formData.append("a", 1); formData.append("a", 2); formData.append("b", 3); formData; `, }, /* midi API requires https (See Bug 1967917) { context: CONTEXTS.PAGE, expression: ` const midiAccess = await navigator.requestMIDIAccess(); midiAccess.inputs; `, prefs: [ // This will make it so we'll have stable MIDI devices reported ["midi.testing", true], ["dom.webmidi.enabled", true], ["midi.prompt.testing", true], ["media.navigator.permission.disabled", true], ], }, */ { context: CONTEXTS.PAGE, expression: ` customElements.define("fx-test", class extends HTMLElement {}); const { states } = document.createElement("fx-test").attachInternals(); states.add("custom-state"); states.add("another-custom-state"); states; `, }, { context: CONTEXTS.PAGE, expression: ` CSS.highlights.set("search", new Highlight()); CSS.highlights.set("glow", new Highlight()); CSS.highlights.set("anchor", new Highlight()); CSS.highlights; `, prefs: [["dom.customHighlightAPI.enabled", true]], }, { context: CONTEXTS.PAGE, expression: `new URLSearchParams([ ["a", 1], ["a", 2], ["b", 3], ["b", 3], ["b", 5], ["c", "this is 6"], ["d", 7], ["e", 8], ["f", 9], ["g", 10], ["h", 11], ])`, }, ]; const Errors = [ { context: CONTEXTS.JS, expression: `new Error("foo")` }, { context: CONTEXTS.JS, expression: `throw new Error("Long error ".repeat(10000));`, }, { context: CONTEXTS.JS, expression: ` throw \`“https://evil.com/?${"a".repeat( 200 )}“ is evil and “https://not-so-evil.com/?${"b".repeat( 200 )}“ is not good either\`; `, }, { context: CONTEXTS.JS, expression: `Error("bar")` }, { context: CONTEXTS.JS, expression: ` function bar() { asdf(); } function foo() { bar(); } foo(); `, }, { context: CONTEXTS.JS, // Use nested `eval()` as syntax error would make the test framework throw on its own eval call expression: `eval("let a, a")`, }, { context: CONTEXTS.JS, expression: `throw "";` }, { context: CONTEXTS.JS, expression: `throw false;` }, { context: CONTEXTS.JS, expression: `throw undefined;` }, { context: CONTEXTS.JS, expression: `throw 0;` }, { context: CONTEXTS.JS, expression: `throw { vegetable: "cucumber" };` }, { context: CONTEXTS.JS, expression: `throw Symbol("potato");` }, { context: CONTEXTS.JS, expression: ` var err = new Error("pineapple"); err.name = "JuicyError"; err.flavor = "delicious"; throw err; `, }, { context: CONTEXTS.JS, expression: ` var originalError = new SyntaxError("original error"); var err = new Error("something went wrong", { cause: originalError, }); throw err; `, }, { context: CONTEXTS.JS, expression: ` var a = new Error("err-a"); var b = new Error("err-b", { cause: a }); var c = new Error("err-c", { cause: b }); var d = new Error("err-d", { cause: c }); throw d; `, }, { context: CONTEXTS.JS, expression: ` var a = new Error("err-a", { cause: b }); var b = new Error("err-b", { cause: a }); throw b; `, }, { context: CONTEXTS.JS, expression: `throw new Error("null cause", { cause: null });` }, { context: CONTEXTS.JS, expression: `throw new Error("number cause", { cause: 0 });` }, { context: CONTEXTS.JS, expression: `throw new Error("string cause", { cause: "cause message" });` }, { context: CONTEXTS.JS, expression: ` throw new Error("object cause", { cause: { code: 234, message: "ERR_234" }, }); `, }, { context: CONTEXTS.JS, expression: `Promise.reject("")` }, { context: CONTEXTS.JS, expression: `Promise.reject("tomato")` }, { context: CONTEXTS.JS, expression: `Promise.reject(false)` }, { context: CONTEXTS.JS, expression: `Promise.reject(0)` }, { context: CONTEXTS.JS, expression: `Promise.reject(null)` }, { context: CONTEXTS.JS, expression: `Promise.reject(undefined)` }, { context: CONTEXTS.JS, expression: `Promise.reject(Symbol("potato"))` }, { context: CONTEXTS.JS, expression: `Promise.reject({vegetable: "cucumber"})` }, { context: CONTEXTS.JS, expression: `Promise.reject(new Error("pumpkin"))` }, { context: CONTEXTS.JS, expression: ` var err = new Error("pineapple"); err.name = "JuicyError"; err.flavor = "delicious"; Promise.reject(err); `, }, { context: CONTEXTS.JS, expression: `Promise.resolve().then(() => { try { unknownFunc(); } catch(e) { throw new Error("something went wrong", { cause: e }) } })`, }, { context: CONTEXTS.JS, expression: ` throw new SuppressedError( new Error("foo"), new Error("bar"), "the suppressed error message" ); `, prefs: [ ["javascript.options.experimental.explicit_resource_management", true], ], // eslint-disable-next-line no-constant-binary-expression disabled: true || !AppConstants.ENABLE_EXPLICIT_RESOURCE_MANAGEMENT, }, ]; const Privileged = [ { context: CONTEXTS.CHROME, expression: `Components.Exception("foo")` } ]; export const AllObjects = [ ...Primitives, ...PlainObjects, ...Arrays, ...TypedArrays, ...Maps, ...Sets, ...Temporals, ...DOMAPIs, ...Errors, ...Privileged, ];