Source code
Revision control
Copy as Markdown
Other Tools
/* Any copyright is dedicated to the Public Domain.
/* eslint-disable object-shorthand */
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`<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title></title>
</head>
<body>
<span id="span">Hello there.</span>
<script>
globalThis.myPolicy = trustedTypes.createPolicy("myPolicy", {
createHTML: s => "<my-policy>" + s + "</my-policy>",
createScript: s => "/* myPolicy */ " + s,
createScriptURL: s => s + "?myPolicy",
});
</script>
</body>
</html>`;
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,
},
{
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
{
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: `
200
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],
],
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,
];