forked from mirrors/gecko-dev
Refactor the error message with the adding the information from the imported
module, for example:
// a.mjs
import { a } from "./b.mjs";
// b.mjs
const b = 1;
Originally the error message is "import not found: default", now it
becomes "The requested module: b.mjs doesn't provide an export named: a"
// c.mjs
import { c } from "./d.mjs";
// d.mjs
export * from "./d1.mjs";
export * from "./d2.mjs";
// d1.mjs
export const c = 1;
// d2.mjs
export const c = 2;
Originally the error message is "ambiguous import: c", now it becomes
"The requested module d.mjs contains ambiguous star export: c from
d1.mjs and d2.mjs"
Add another error message for circular import:
// e.mjs
export { e } from "f.mjs";
// f.mjs
export { e } from "e.mjs";
Originally it was "indirect export not found: e", now it is
"The request module: f.mjs contains circular import: e".
Differential Revision: https://phabricator.services.mozilla.com/D200345
796 lines
22 KiB
JavaScript
796 lines
22 KiB
JavaScript
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
add_task(async function testSandbox() {
|
|
const uri = "http://example.com/";
|
|
const window = createContentWindow(uri);
|
|
const sandboxOpts = {
|
|
sandboxPrototype: window,
|
|
wantGlobalProperties: ["ChromeUtils"],
|
|
};
|
|
const sb = new Cu.Sandbox(uri, sandboxOpts);
|
|
|
|
Cu.evalInSandbox(`
|
|
globalThis["loaded"] = [];
|
|
var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
`, sb);
|
|
|
|
Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb), 0);
|
|
Cu.evalInSandbox(`ns.incCounter();`, sb);
|
|
Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb), 1);
|
|
|
|
Assert.equal(Cu.evalInSandbox(`globalThis["loaded"].join(",")`, sb), "2,1");
|
|
});
|
|
|
|
add_task(async function testNoWindowSandbox() {
|
|
// Sandbox without window doesn't have ScriptLoader, and Sandbox's
|
|
// ModuleLoader cannot be created.
|
|
const systemPrincipal = Components.Constructor(
|
|
"@mozilla.org/systemprincipal;1",
|
|
"nsIPrincipal"
|
|
)();
|
|
const sandboxOpts = {
|
|
wantGlobalProperties: ["ChromeUtils"],
|
|
};
|
|
|
|
const sb = new Cu.Sandbox(systemPrincipal, sandboxOpts);
|
|
|
|
let caught = false;
|
|
try {
|
|
Cu.evalInSandbox(`
|
|
ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
`, sb);
|
|
} catch (e) {
|
|
caught = true;
|
|
Assert.stringMatches(e.message, /No ModuleLoader found/);
|
|
}
|
|
Assert.ok(caught);
|
|
});
|
|
|
|
add_task(async function testWindow() {
|
|
const win1 = createChromeWindow();
|
|
|
|
win1.eval(`
|
|
globalThis["loaded"] = [];
|
|
var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
`);
|
|
|
|
Assert.equal(win1.eval(`ns.getCounter();`), 0);
|
|
win1.eval(`ns.incCounter();`);
|
|
Assert.equal(win1.eval(`ns.getCounter();`), 1);
|
|
|
|
Assert.equal(win1.eval(`globalThis["loaded"].join(",")`), "2,1");
|
|
});
|
|
|
|
add_task(async function testReImport() {
|
|
// Re-importing the same module should return the same thing.
|
|
|
|
const uri = "http://example.com/";
|
|
const window = createContentWindow(uri);
|
|
const sandboxOpts = {
|
|
sandboxPrototype: window,
|
|
wantGlobalProperties: ["ChromeUtils"],
|
|
};
|
|
const sb = new Cu.Sandbox(uri, sandboxOpts);
|
|
|
|
Cu.evalInSandbox(`
|
|
globalThis["loaded"] = [];
|
|
var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
`, sb);
|
|
|
|
Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb), 0);
|
|
Cu.evalInSandbox(`ns.incCounter();`, sb);
|
|
Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb), 1);
|
|
|
|
Assert.equal(Cu.evalInSandbox(`globalThis["loaded"].join(",")`, sb), "2,1");
|
|
|
|
Cu.evalInSandbox(`
|
|
var ns2 = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
`, sb);
|
|
|
|
// The counter should be shared, and also not reset.
|
|
Assert.equal(Cu.evalInSandbox(`ns2.getCounter();`, sb), 1);
|
|
Cu.evalInSandbox(`ns2.incCounter();`, sb);
|
|
Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb), 2);
|
|
Assert.equal(Cu.evalInSandbox(`ns2.getCounter();`, sb), 2);
|
|
|
|
// The top-level script shouldn't be executed twice.
|
|
Assert.equal(Cu.evalInSandbox(`globalThis["loaded"].join(",")`, sb), "2,1");
|
|
});
|
|
|
|
add_task(async function testNotFound() {
|
|
// Importing non-existent file should throw error.
|
|
|
|
const uri = "http://example.com/";
|
|
const window = createContentWindow(uri);
|
|
const sandboxOpts = {
|
|
sandboxPrototype: window,
|
|
wantGlobalProperties: ["ChromeUtils"],
|
|
};
|
|
const sb = new Cu.Sandbox(uri, sandboxOpts);
|
|
|
|
let caught = false;
|
|
try {
|
|
Cu.evalInSandbox(`
|
|
ChromeUtils.importESModule("resource://test/not_found.mjs", {
|
|
global: "current",
|
|
});
|
|
`, sb);
|
|
} catch (e) {
|
|
caught = true;
|
|
Assert.stringMatches(e.message, /Failed to load/);
|
|
}
|
|
Assert.ok(caught);
|
|
});
|
|
|
|
add_task(async function testParseError() {
|
|
// Parse error should be thrown.
|
|
|
|
const uri = "http://example.com/";
|
|
const window = createContentWindow(uri);
|
|
const sandboxOpts = {
|
|
sandboxPrototype: window,
|
|
wantGlobalProperties: ["ChromeUtils"],
|
|
};
|
|
const sb = new Cu.Sandbox(uri, sandboxOpts);
|
|
|
|
let caught = false;
|
|
try {
|
|
Cu.evalInSandbox(`
|
|
ChromeUtils.importESModule("resource://test/es6module_parse_error.js", {
|
|
global: "current",
|
|
});
|
|
`, sb);
|
|
} catch (e) {
|
|
caught = true;
|
|
Assert.stringMatches(e.message, /unexpected token/);
|
|
}
|
|
Assert.ok(caught);
|
|
});
|
|
|
|
add_task(async function testParseErrorInImport() {
|
|
// Parse error in imported module should be thrown.
|
|
|
|
const uri = "http://example.com/";
|
|
const window = createContentWindow(uri);
|
|
const sandboxOpts = {
|
|
sandboxPrototype: window,
|
|
wantGlobalProperties: ["ChromeUtils"],
|
|
};
|
|
const sb = new Cu.Sandbox(uri, sandboxOpts);
|
|
|
|
let caught = false;
|
|
try {
|
|
Cu.evalInSandbox(`
|
|
ChromeUtils.importESModule("resource://test/es6module_parse_error_in_import.js", {
|
|
global: "current",
|
|
});
|
|
`, sb);
|
|
} catch (e) {
|
|
caught = true;
|
|
Assert.stringMatches(e.message, /unexpected token/);
|
|
}
|
|
Assert.ok(caught);
|
|
});
|
|
|
|
add_task(async function testImportError() {
|
|
// Error for nested import should be thrown.
|
|
|
|
const uri = "http://example.com/";
|
|
const window = createContentWindow(uri);
|
|
const sandboxOpts = {
|
|
sandboxPrototype: window,
|
|
wantGlobalProperties: ["ChromeUtils"],
|
|
};
|
|
const sb = new Cu.Sandbox(uri, sandboxOpts);
|
|
|
|
let caught = false;
|
|
try {
|
|
Cu.evalInSandbox(`
|
|
ChromeUtils.importESModule("resource://test/es6module_import_error.js", {
|
|
global: "current",
|
|
});
|
|
`, sb);
|
|
} catch (e) {
|
|
caught = true;
|
|
Assert.stringMatches(e.message, /doesn't provide an export named/);
|
|
}
|
|
Assert.ok(caught);
|
|
});
|
|
|
|
add_task(async function testExecutionError() {
|
|
// Error while execution the top-level script should be thrown.
|
|
|
|
const uri = "http://example.com/";
|
|
const window = createContentWindow(uri);
|
|
const sandboxOpts = {
|
|
sandboxPrototype: window,
|
|
wantGlobalProperties: ["ChromeUtils"],
|
|
};
|
|
const sb = new Cu.Sandbox(uri, sandboxOpts);
|
|
|
|
let caught = false;
|
|
try {
|
|
Cu.evalInSandbox(`
|
|
ChromeUtils.importESModule("resource://test/es6module_throws.js", {
|
|
global: "current",
|
|
});
|
|
`, sb);
|
|
} catch (e) {
|
|
caught = true;
|
|
Assert.stringMatches(e.message, /foobar/);
|
|
}
|
|
Assert.ok(caught);
|
|
|
|
// Re-import should throw the same error.
|
|
|
|
caught = false;
|
|
try {
|
|
Cu.evalInSandbox(`
|
|
ChromeUtils.importESModule("resource://test/es6module_throws.js", {
|
|
global: "current",
|
|
});
|
|
`, sb);
|
|
} catch (e) {
|
|
caught = true;
|
|
Assert.stringMatches(e.message, /foobar/);
|
|
}
|
|
Assert.ok(caught);
|
|
});
|
|
|
|
add_task(async function testImportNestShared() {
|
|
// Importing system ESM should work.
|
|
|
|
const win1 = createChromeWindow();
|
|
|
|
const result = win1.eval(`
|
|
const { func1 } = ChromeUtils.importESModule("resource://test/non_shared_nest_import_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
func1();
|
|
`);
|
|
|
|
Assert.equal(result, 27);
|
|
});
|
|
|
|
add_task(async function testImportNestNonSharedSame() {
|
|
// For the same global, nested import for non-shared global is allowed while
|
|
// executing top-level script.
|
|
|
|
const win1 = createChromeWindow();
|
|
|
|
const result = win1.eval(`
|
|
const { func } = ChromeUtils.importESModule("resource://test/non_shared_nest_import_non_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
func();
|
|
`);
|
|
Assert.equal(result, 10);
|
|
});
|
|
|
|
add_task(async function testImportNestNonSharedDifferent() {
|
|
// For the different globals, nested import for non-shared global isn't
|
|
// allowed while executing top-level script.
|
|
|
|
const win1 = createChromeWindow();
|
|
|
|
const uri = "http://example.com/";
|
|
const window = createContentWindow(uri);
|
|
const sandboxOpts = {
|
|
sandboxPrototype: window,
|
|
wantGlobalProperties: ["ChromeUtils"],
|
|
};
|
|
win1.sb = new Cu.Sandbox(uri, sandboxOpts);
|
|
|
|
let caught = false;
|
|
try {
|
|
win1.eval(`
|
|
ChromeUtils.importESModule("resource://test/non_shared_nest_import_non_shared_2.mjs", {
|
|
global: "current",
|
|
});
|
|
`);
|
|
} catch (e) {
|
|
caught = true;
|
|
Assert.stringMatches(e.message, /cannot be used for different global/);
|
|
}
|
|
Assert.ok(caught);
|
|
});
|
|
|
|
add_task(async function testImportNestNonSharedAfterImport() {
|
|
// Nested import for non-shared global is allowed after the import, both for
|
|
// the same and different globals.
|
|
|
|
const win1 = createChromeWindow();
|
|
|
|
const uri = "http://example.com/";
|
|
const window = createContentWindow(uri);
|
|
const sandboxOpts = {
|
|
sandboxPrototype: window,
|
|
wantGlobalProperties: ["ChromeUtils"],
|
|
};
|
|
win1.sb = new Cu.Sandbox(uri, sandboxOpts);
|
|
|
|
const result = win1.eval(`
|
|
const { func3 } = ChromeUtils.importESModule("resource://test/non_shared_nest_import_non_shared_3.mjs", {
|
|
global: "current",
|
|
});
|
|
|
|
// Nested import happens here.
|
|
func3();
|
|
`);
|
|
Assert.equal(result, 22);
|
|
});
|
|
|
|
add_task(async function testIsolationWithSandbox() {
|
|
// Modules should be isolated for each sandbox.
|
|
|
|
const uri = "http://example.com/";
|
|
const window = createContentWindow(uri);
|
|
const sandboxOpts = {
|
|
sandboxPrototype: window,
|
|
wantGlobalProperties: ["ChromeUtils"],
|
|
};
|
|
const sb1 = new Cu.Sandbox(uri, sandboxOpts);
|
|
const sb2 = new Cu.Sandbox(uri, sandboxOpts);
|
|
const sb3 = new Cu.Sandbox(uri, sandboxOpts);
|
|
|
|
// Verify modules in 2 sandboxes are isolated.
|
|
|
|
Cu.evalInSandbox(`
|
|
globalThis["loaded"] = [];
|
|
var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
`, sb1);
|
|
Cu.evalInSandbox(`
|
|
globalThis["loaded"] = [];
|
|
var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
`, sb2);
|
|
|
|
Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb1), 0);
|
|
Cu.evalInSandbox(`ns.incCounter();`, sb1);
|
|
Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb1), 1);
|
|
|
|
Assert.equal(Cu.evalInSandbox(`globalThis["loaded"].join(",")`, sb1), "2,1");
|
|
|
|
Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb2), 0);
|
|
Cu.evalInSandbox(`ns.incCounter();`, sb2);
|
|
Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb2), 1);
|
|
|
|
Assert.equal(Cu.evalInSandbox(`globalThis["loaded"].join(",")`, sb2), "2,1");
|
|
|
|
// Verify importing after any modification to different global doesn't affect.
|
|
|
|
const ns3 = Cu.evalInSandbox(`
|
|
globalThis["loaded"] = [];
|
|
var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
`, sb3);
|
|
|
|
Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb3), 0);
|
|
Cu.evalInSandbox(`ns.incCounter();`, sb3);
|
|
Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb3), 1);
|
|
|
|
Assert.equal(Cu.evalInSandbox(`globalThis["loaded"].join(",")`, sb3), "2,1");
|
|
|
|
// Verify yet another modification are still isolated.
|
|
|
|
Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb1), 1);
|
|
Cu.evalInSandbox(`ns.incCounter();`, sb1);
|
|
Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb1), 2);
|
|
|
|
Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb2), 1);
|
|
Cu.evalInSandbox(`ns.incCounter();`, sb2);
|
|
Cu.evalInSandbox(`ns.incCounter();`, sb2);
|
|
Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb2), 3);
|
|
|
|
Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb3), 1);
|
|
Cu.evalInSandbox(`ns.incCounter();`, sb3);
|
|
Cu.evalInSandbox(`ns.incCounter();`, sb3);
|
|
Cu.evalInSandbox(`ns.incCounter();`, sb3);
|
|
Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb3), 4);
|
|
|
|
// Verify the module's `globalThis` points the target global.
|
|
|
|
Cu.evalInSandbox(`ns.putCounter();`, sb1);
|
|
Cu.evalInSandbox(`ns.putCounter();`, sb2);
|
|
Cu.evalInSandbox(`ns.putCounter();`, sb3);
|
|
|
|
const counter1 = Cu.evalInSandbox(`globalThis["counter"]`, sb1);
|
|
Assert.equal(counter1, 2);
|
|
const counter2 = Cu.evalInSandbox(`globalThis["counter"]`, sb2);
|
|
Assert.equal(counter2, 3);
|
|
const counter3 = Cu.evalInSandbox(`globalThis["counter"]`, sb3);
|
|
Assert.equal(counter3, 4);
|
|
});
|
|
|
|
add_task(async function testIsolationWithWindow() {
|
|
// Modules should be isolated for each window.
|
|
|
|
const win1 = createChromeWindow();
|
|
const win2 = createChromeWindow();
|
|
const win3 = createChromeWindow();
|
|
|
|
// Verify modules in 2 sandboxes are isolated.
|
|
|
|
win1.eval(`
|
|
globalThis["loaded"] = [];
|
|
var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
`);
|
|
win2.eval(`
|
|
globalThis["loaded"] = [];
|
|
var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
`);
|
|
|
|
Assert.equal(win1.eval(`ns.getCounter();`), 0);
|
|
win1.eval(`ns.incCounter();`);
|
|
Assert.equal(win1.eval(`ns.getCounter();`), 1);
|
|
|
|
Assert.equal(win1.eval(`globalThis["loaded"].join(",")`), "2,1");
|
|
|
|
Assert.equal(win2.eval(`ns.getCounter();`), 0);
|
|
win2.eval(`ns.incCounter();`);
|
|
Assert.equal(win2.eval(`ns.getCounter();`), 1);
|
|
|
|
Assert.equal(win2.eval(`globalThis["loaded"].join(",")`), "2,1");
|
|
|
|
// Verify importing after any modification to different global doesn't affect.
|
|
|
|
const ns3 = win3.eval(`
|
|
globalThis["loaded"] = [];
|
|
var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
`);
|
|
|
|
Assert.equal(win3.eval(`ns.getCounter();`), 0);
|
|
win3.eval(`ns.incCounter();`);
|
|
Assert.equal(win3.eval(`ns.getCounter();`), 1);
|
|
|
|
Assert.equal(win3.eval(`globalThis["loaded"].join(",")`), "2,1");
|
|
|
|
// Verify yet another modification are still isolated.
|
|
|
|
Assert.equal(win1.eval(`ns.getCounter();`), 1);
|
|
win1.eval(`ns.incCounter();`);
|
|
Assert.equal(win1.eval(`ns.getCounter();`), 2);
|
|
|
|
Assert.equal(win2.eval(`ns.getCounter();`), 1);
|
|
win2.eval(`ns.incCounter();`);
|
|
win2.eval(`ns.incCounter();`);
|
|
Assert.equal(win2.eval(`ns.getCounter();`), 3);
|
|
|
|
Assert.equal(win3.eval(`ns.getCounter();`), 1);
|
|
win3.eval(`ns.incCounter();`);
|
|
win3.eval(`ns.incCounter();`);
|
|
win3.eval(`ns.incCounter();`);
|
|
Assert.equal(win3.eval(`ns.getCounter();`), 4);
|
|
|
|
// Verify the module's `globalThis` points the target global.
|
|
|
|
win1.eval(`ns.putCounter();`);
|
|
win2.eval(`ns.putCounter();`);
|
|
win3.eval(`ns.putCounter();`);
|
|
|
|
const counter1 = win1.eval(`globalThis["counter"]`);
|
|
Assert.equal(counter1, 2);
|
|
const counter2 = win2.eval(`globalThis["counter"]`);
|
|
Assert.equal(counter2, 3);
|
|
const counter3 = win3.eval(`globalThis["counter"]`);
|
|
Assert.equal(counter3, 4);
|
|
});
|
|
|
|
add_task(async function testSyncImportBeforeAsyncImportTopLevel() {
|
|
const window = createChromeWindow();
|
|
|
|
window.eval(`
|
|
globalThis["loaded"] = [];
|
|
var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
`);
|
|
|
|
Assert.equal(window.eval(`ns.getCounter();`), 0);
|
|
window.eval(`ns.incCounter();`);
|
|
Assert.equal(window.eval(`ns.getCounter();`), 1);
|
|
|
|
Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
|
|
|
|
window.eval(`
|
|
var ns2 = null;
|
|
const nsPromise = import("resource://test/non_shared_1.mjs");
|
|
nsPromise.then(v => { ns2 = v; });
|
|
`);
|
|
|
|
Services.tm.spinEventLoopUntil(
|
|
"Wait until dynamic import finishes",
|
|
() => window.eval(`ns2 !== null`)
|
|
);
|
|
|
|
Assert.equal(window.eval(`ns2.getCounter();`), 1);
|
|
window.eval(`ns2.incCounter();`);
|
|
Assert.equal(window.eval(`ns2.getCounter();`), 2);
|
|
Assert.equal(window.eval(`ns.getCounter();`), 2);
|
|
|
|
Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
|
|
});
|
|
|
|
add_task(async function testSyncImportBeforeAsyncImportDependency() {
|
|
const window = createChromeWindow();
|
|
|
|
window.eval(`
|
|
globalThis["loaded"] = [];
|
|
var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
`);
|
|
|
|
Assert.equal(window.eval(`ns.getCounter();`), 0);
|
|
window.eval(`ns.incCounter();`);
|
|
Assert.equal(window.eval(`ns.getCounter();`), 1);
|
|
|
|
Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
|
|
|
|
window.eval(`
|
|
var ns2 = null;
|
|
const nsPromise = import("resource://test/import_non_shared_1.mjs");
|
|
nsPromise.then(v => { ns2 = v; });
|
|
`);
|
|
|
|
Services.tm.spinEventLoopUntil(
|
|
"Wait until dynamic import finishes",
|
|
() => window.eval(`ns2 !== null`)
|
|
);
|
|
|
|
Assert.equal(window.eval(`ns2.getCounter();`), 1);
|
|
window.eval(`ns2.incCounter();`);
|
|
Assert.equal(window.eval(`ns2.getCounter();`), 2);
|
|
Assert.equal(window.eval(`ns.getCounter();`), 2);
|
|
|
|
Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
|
|
});
|
|
|
|
add_task(async function testSyncImportAfterAsyncImportTopLevel() {
|
|
const window = createChromeWindow();
|
|
|
|
window.eval(`
|
|
var ns = null;
|
|
globalThis["loaded"] = [];
|
|
const nsPromise = import("resource://test/non_shared_1.mjs");
|
|
nsPromise.then(v => { ns = v; });
|
|
`);
|
|
|
|
Services.tm.spinEventLoopUntil(
|
|
"Wait until dynamic import finishes",
|
|
() => window.eval(`ns !== null`)
|
|
);
|
|
|
|
Assert.equal(window.eval(`ns.getCounter();`), 0);
|
|
window.eval(`ns.incCounter();`);
|
|
Assert.equal(window.eval(`ns.getCounter();`), 1);
|
|
|
|
Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
|
|
|
|
window.eval(`
|
|
var ns2 = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
`);
|
|
|
|
Assert.equal(window.eval(`ns2.getCounter();`), 1);
|
|
window.eval(`ns2.incCounter();`);
|
|
Assert.equal(window.eval(`ns2.getCounter();`), 2);
|
|
Assert.equal(window.eval(`ns.getCounter();`), 2);
|
|
|
|
Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
|
|
});
|
|
|
|
add_task(async function testSyncImportAfterAsyncImportDependency() {
|
|
const window = createChromeWindow();
|
|
|
|
window.eval(`
|
|
var ns = null;
|
|
globalThis["loaded"] = [];
|
|
const nsPromise = import("resource://test/non_shared_1.mjs");
|
|
nsPromise.then(v => { ns = v; });
|
|
`);
|
|
|
|
Services.tm.spinEventLoopUntil(
|
|
"Wait until dynamic import finishes",
|
|
() => window.eval(`ns !== null`)
|
|
);
|
|
|
|
Assert.equal(window.eval(`ns.getCounter();`), 0);
|
|
window.eval(`ns.incCounter();`);
|
|
Assert.equal(window.eval(`ns.getCounter();`), 1);
|
|
|
|
Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
|
|
|
|
window.eval(`
|
|
var ns2 = ChromeUtils.importESModule("resource://test/import_non_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
`);
|
|
|
|
Assert.equal(window.eval(`ns2.getCounter();`), 1);
|
|
window.eval(`ns2.incCounter();`);
|
|
Assert.equal(window.eval(`ns2.getCounter();`), 2);
|
|
Assert.equal(window.eval(`ns.getCounter();`), 2);
|
|
|
|
Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
|
|
});
|
|
|
|
add_task(async function testSyncImportWhileAsyncImportTopLevel() {
|
|
const window = createChromeWindow();
|
|
|
|
window.eval(`
|
|
var ns = null;
|
|
globalThis["loaded"] = [];
|
|
const nsPromise = import("resource://test/non_shared_1.mjs");
|
|
nsPromise.then(v => { ns = v; });
|
|
`);
|
|
|
|
window.eval(`
|
|
var ns2 = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
`);
|
|
|
|
Assert.equal(window.eval(`ns2.getCounter();`), 0);
|
|
window.eval(`ns2.incCounter();`);
|
|
Assert.equal(window.eval(`ns2.getCounter();`), 1);
|
|
|
|
Services.tm.spinEventLoopUntil(
|
|
"Wait until dynamic import finishes",
|
|
() => window.eval(`ns !== null`)
|
|
);
|
|
|
|
Assert.equal(window.eval(`ns.getCounter();`), 1);
|
|
window.eval(`ns.incCounter();`);
|
|
Assert.equal(window.eval(`ns.getCounter();`), 2);
|
|
Assert.equal(window.eval(`ns2.getCounter();`), 2);
|
|
|
|
Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
|
|
});
|
|
|
|
add_task(async function testSyncImportWhileAsyncImportDependency() {
|
|
const window = createChromeWindow();
|
|
|
|
window.eval(`
|
|
var ns = null;
|
|
globalThis["loaded"] = [];
|
|
const nsPromise = import("resource://test/non_shared_1.mjs");
|
|
nsPromise.then(v => { ns = v; });
|
|
`);
|
|
|
|
window.eval(`
|
|
var ns2 = ChromeUtils.importESModule("resource://test/import_non_shared_1.mjs", {
|
|
global: "current",
|
|
});
|
|
`);
|
|
|
|
Assert.equal(window.eval(`ns2.getCounter();`), 0);
|
|
window.eval(`ns2.incCounter();`);
|
|
Assert.equal(window.eval(`ns2.getCounter();`), 1);
|
|
|
|
Services.tm.spinEventLoopUntil(
|
|
"Wait until dynamic import finishes",
|
|
() => window.eval(`ns !== null`)
|
|
);
|
|
|
|
Assert.equal(window.eval(`ns.getCounter();`), 1);
|
|
window.eval(`ns.incCounter();`);
|
|
Assert.equal(window.eval(`ns.getCounter();`), 2);
|
|
Assert.equal(window.eval(`ns2.getCounter();`), 2);
|
|
|
|
Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
|
|
});
|
|
|
|
add_task(async function testSyncImportBeforeAsyncImportTLA() {
|
|
// Top-level-await is not supported by sync import.
|
|
|
|
const window = createChromeWindow();
|
|
|
|
let caught = false;
|
|
|
|
try {
|
|
window.eval(`
|
|
ChromeUtils.importESModule("resource://test/es6module_top_level_await.js", {
|
|
global: "current",
|
|
});
|
|
`);
|
|
} catch (e) {
|
|
caught = true;
|
|
Assert.stringMatches(e.message, /top level await is not supported/);
|
|
}
|
|
Assert.ok(caught);
|
|
|
|
window.eval(`
|
|
var ns2 = null;
|
|
const nsPromise = import("resource://test/es6module_top_level_await.js");
|
|
nsPromise.then(v => { ns2 = v; });
|
|
`);
|
|
|
|
Services.tm.spinEventLoopUntil(
|
|
"Wait until dynamic import finishes",
|
|
() => window.eval(`ns2 !== null`)
|
|
);
|
|
|
|
Assert.equal(window.eval(`ns2.foo();`), 10);
|
|
});
|
|
|
|
add_task(async function testSyncImportAfterAsyncImportTLA() {
|
|
// Top-level-await is not supported by sync import, but if the module is
|
|
// already imported, the existing module namespace is returned.
|
|
|
|
const window = createChromeWindow();
|
|
|
|
window.eval(`
|
|
var ns2 = null;
|
|
const nsPromise = import("resource://test/es6module_top_level_await.js");
|
|
nsPromise.then(v => { ns2 = v; });
|
|
`);
|
|
|
|
Services.tm.spinEventLoopUntil(
|
|
"Wait until dynamic import finishes",
|
|
() => window.eval(`ns2 !== null`)
|
|
);
|
|
|
|
Assert.equal(window.eval(`ns2.foo();`), 10);
|
|
|
|
window.eval(`
|
|
var ns = ChromeUtils.importESModule("resource://test/es6module_top_level_await.js", {
|
|
global: "current",
|
|
});
|
|
`);
|
|
|
|
Assert.equal(window.eval(`ns.foo();`), 10);
|
|
Assert.equal(window.eval(`ns2.foo == ns.foo;`), true);
|
|
});
|
|
|
|
add_task(async function testSyncImportWhileAsyncImportTLA() {
|
|
// Top-level-await is not supported by sync import, but if the module is
|
|
// already fetching, ChromeUtils.importESModule waits for it and, the
|
|
// async-imported module namespace is returned.
|
|
|
|
const window = createChromeWindow();
|
|
|
|
window.eval(`
|
|
var ns2 = null;
|
|
const nsPromise = import("resource://test/es6module_top_level_await.js");
|
|
nsPromise.then(v => { ns2 = v; });
|
|
`);
|
|
|
|
window.eval(`
|
|
var ns = ChromeUtils.importESModule("resource://test/es6module_top_level_await.js", {
|
|
global: "current",
|
|
});
|
|
`);
|
|
|
|
Services.tm.spinEventLoopUntil(
|
|
"Wait until dynamic import finishes",
|
|
() => window.eval(`ns2 !== null`)
|
|
);
|
|
|
|
Assert.equal(window.eval(`ns2.foo();`), 10);
|
|
Assert.equal(window.eval(`ns.foo();`), 10);
|
|
Assert.equal(window.eval(`ns2.foo == ns.foo;`), true);
|
|
});
|