tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

test_import_global_current.js (22481B)


      1 /* This Source Code Form is subject to the terms of the Mozilla Public
      2 * License, v. 2.0. If a copy of the MPL was not distributed with this
      3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
      4 
      5 add_task(async function testSandbox() {
      6  const uri = "http://example.com/";
      7  const window = createContentWindow(uri);
      8  const sandboxOpts = {
      9    sandboxPrototype: window,
     10    wantGlobalProperties: ["ChromeUtils"],
     11  };
     12  const sb = new Cu.Sandbox(uri, sandboxOpts);
     13 
     14  Cu.evalInSandbox(`
     15 globalThis["loaded"] = [];
     16 var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
     17  global: "current",
     18 });
     19 `, sb);
     20 
     21  Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb), 0);
     22  Cu.evalInSandbox(`ns.incCounter();`, sb);
     23  Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb), 1);
     24 
     25  Assert.equal(Cu.evalInSandbox(`globalThis["loaded"].join(",")`, sb), "2,1");
     26 });
     27 
     28 add_task(async function testNoWindowSandbox() {
     29  // Sandbox without window doesn't have ScriptLoader, and Sandbox's
     30  // ModuleLoader cannot be created.
     31  const systemPrincipal = Components.Constructor(
     32    "@mozilla.org/systemprincipal;1",
     33    "nsIPrincipal"
     34  )();
     35  const sandboxOpts = {
     36    wantGlobalProperties: ["ChromeUtils"],
     37  };
     38 
     39  const sb = new Cu.Sandbox(systemPrincipal, sandboxOpts);
     40 
     41  let caught = false;
     42  try {
     43  Cu.evalInSandbox(`
     44 ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
     45  global: "current",
     46 });
     47 `, sb);
     48  } catch (e) {
     49    caught = true;
     50    Assert.stringMatches(e.message, /No ModuleLoader found/);
     51  }
     52  Assert.ok(caught);
     53 });
     54 
     55 add_task(async function testWindow() {
     56  const win1 = createChromeWindow();
     57 
     58  win1.eval(`
     59 globalThis["loaded"] = [];
     60 var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
     61  global: "current",
     62 });
     63 `);
     64 
     65  Assert.equal(win1.eval(`ns.getCounter();`), 0);
     66  win1.eval(`ns.incCounter();`);
     67  Assert.equal(win1.eval(`ns.getCounter();`), 1);
     68 
     69  Assert.equal(win1.eval(`globalThis["loaded"].join(",")`), "2,1");
     70 });
     71 
     72 add_task(async function testReImport() {
     73  // Re-importing the same module should return the same thing.
     74 
     75  const uri = "http://example.com/";
     76  const window = createContentWindow(uri);
     77  const sandboxOpts = {
     78    sandboxPrototype: window,
     79    wantGlobalProperties: ["ChromeUtils"],
     80  };
     81  const sb = new Cu.Sandbox(uri, sandboxOpts);
     82 
     83  Cu.evalInSandbox(`
     84 globalThis["loaded"] = [];
     85 var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
     86  global: "current",
     87 });
     88 `, sb);
     89 
     90  Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb), 0);
     91  Cu.evalInSandbox(`ns.incCounter();`, sb);
     92  Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb), 1);
     93 
     94  Assert.equal(Cu.evalInSandbox(`globalThis["loaded"].join(",")`, sb), "2,1");
     95 
     96  Cu.evalInSandbox(`
     97 var ns2 = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
     98  global: "current",
     99 });
    100 `, sb);
    101 
    102  // The counter should be shared, and also not reset.
    103  Assert.equal(Cu.evalInSandbox(`ns2.getCounter();`, sb), 1);
    104  Cu.evalInSandbox(`ns2.incCounter();`, sb);
    105  Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb), 2);
    106  Assert.equal(Cu.evalInSandbox(`ns2.getCounter();`, sb), 2);
    107 
    108  // The top-level script shouldn't be executed twice.
    109  Assert.equal(Cu.evalInSandbox(`globalThis["loaded"].join(",")`, sb), "2,1");
    110 });
    111 
    112 add_task(async function testNotFound() {
    113  // Importing non-existent file should throw error.
    114 
    115  const uri = "http://example.com/";
    116  const window = createContentWindow(uri);
    117  const sandboxOpts = {
    118    sandboxPrototype: window,
    119    wantGlobalProperties: ["ChromeUtils"],
    120  };
    121  const sb = new Cu.Sandbox(uri, sandboxOpts);
    122 
    123  let caught = false;
    124  try {
    125  Cu.evalInSandbox(`
    126 ChromeUtils.importESModule("resource://test/not_found.mjs", {
    127  global: "current",
    128 });
    129 `, sb);
    130  } catch (e) {
    131    caught = true;
    132    Assert.stringMatches(e.message, /Failed to load/);
    133  }
    134  Assert.ok(caught);
    135 });
    136 
    137 add_task(async function testParseError() {
    138  // Parse error should be thrown.
    139 
    140  const uri = "http://example.com/";
    141  const window = createContentWindow(uri);
    142  const sandboxOpts = {
    143    sandboxPrototype: window,
    144    wantGlobalProperties: ["ChromeUtils"],
    145  };
    146  const sb = new Cu.Sandbox(uri, sandboxOpts);
    147 
    148  let caught = false;
    149  try {
    150  Cu.evalInSandbox(`
    151 ChromeUtils.importESModule("resource://test/es6module_parse_error.js", {
    152  global: "current",
    153 });
    154 `, sb);
    155  } catch (e) {
    156    caught = true;
    157    Assert.stringMatches(e.message, /unexpected token/);
    158  }
    159  Assert.ok(caught);
    160 });
    161 
    162 add_task(async function testParseErrorInImport() {
    163  // Parse error in imported module should be thrown.
    164 
    165  const uri = "http://example.com/";
    166  const window = createContentWindow(uri);
    167  const sandboxOpts = {
    168    sandboxPrototype: window,
    169    wantGlobalProperties: ["ChromeUtils"],
    170  };
    171  const sb = new Cu.Sandbox(uri, sandboxOpts);
    172 
    173  let caught = false;
    174  try {
    175  Cu.evalInSandbox(`
    176 ChromeUtils.importESModule("resource://test/es6module_parse_error_in_import.js", {
    177  global: "current",
    178 });
    179 `, sb);
    180  } catch (e) {
    181    caught = true;
    182    Assert.stringMatches(e.message, /unexpected token/);
    183  }
    184  Assert.ok(caught);
    185 });
    186 
    187 add_task(async function testImportError() {
    188  // Error for nested import should be thrown.
    189 
    190  const uri = "http://example.com/";
    191  const window = createContentWindow(uri);
    192  const sandboxOpts = {
    193    sandboxPrototype: window,
    194    wantGlobalProperties: ["ChromeUtils"],
    195  };
    196  const sb = new Cu.Sandbox(uri, sandboxOpts);
    197 
    198  let caught = false;
    199  try {
    200  Cu.evalInSandbox(`
    201 ChromeUtils.importESModule("resource://test/es6module_import_error.js", {
    202  global: "current",
    203 });
    204 `, sb);
    205  } catch (e) {
    206    caught = true;
    207    Assert.stringMatches(e.message, /doesn't provide an export named/);
    208  }
    209  Assert.ok(caught);
    210 });
    211 
    212 add_task(async function testExecutionError() {
    213  // Error while execution the top-level script should be thrown.
    214 
    215  const uri = "http://example.com/";
    216  const window = createContentWindow(uri);
    217  const sandboxOpts = {
    218    sandboxPrototype: window,
    219    wantGlobalProperties: ["ChromeUtils"],
    220  };
    221  const sb = new Cu.Sandbox(uri, sandboxOpts);
    222 
    223  let caught = false;
    224  try {
    225  Cu.evalInSandbox(`
    226 ChromeUtils.importESModule("resource://test/es6module_throws.js", {
    227  global: "current",
    228 });
    229 `, sb);
    230  } catch (e) {
    231    caught = true;
    232    Assert.stringMatches(e.message, /foobar/);
    233  }
    234  Assert.ok(caught);
    235 
    236  // Re-import should throw the same error.
    237 
    238  caught = false;
    239  try {
    240  Cu.evalInSandbox(`
    241 ChromeUtils.importESModule("resource://test/es6module_throws.js", {
    242  global: "current",
    243 });
    244 `, sb);
    245  } catch (e) {
    246    caught = true;
    247    Assert.stringMatches(e.message, /foobar/);
    248  }
    249  Assert.ok(caught);
    250 });
    251 
    252 add_task(async function testImportNestShared() {
    253  // Importing system ESM should work.
    254 
    255  const win1 = createChromeWindow();
    256 
    257  const result = win1.eval(`
    258 const { func1 } = ChromeUtils.importESModule("resource://test/non_shared_nest_import_shared_1.mjs", {
    259  global: "current",
    260 });
    261 func1();
    262 `);
    263 
    264  Assert.equal(result, 27);
    265 });
    266 
    267 add_task(async function testImportNestNonSharedSame() {
    268  // For the same global, nested import for non-shared global is allowed while
    269  // executing top-level script.
    270 
    271  const win1 = createChromeWindow();
    272 
    273  const result = win1.eval(`
    274 const { func } = ChromeUtils.importESModule("resource://test/non_shared_nest_import_non_shared_1.mjs", {
    275  global: "current",
    276 });
    277 func();
    278 `);
    279  Assert.equal(result, 10);
    280 });
    281 
    282 add_task(async function testImportNestNonSharedDifferent() {
    283  // For the different globals, nested import for non-shared global isn't
    284  // allowed while executing top-level script.
    285 
    286  const win1 = createChromeWindow();
    287 
    288  const uri = "http://example.com/";
    289  const window = createContentWindow(uri);
    290  const sandboxOpts = {
    291    sandboxPrototype: window,
    292    wantGlobalProperties: ["ChromeUtils"],
    293  };
    294  win1.sb = new Cu.Sandbox(uri, sandboxOpts);
    295 
    296  let caught = false;
    297  try {
    298  win1.eval(`
    299 ChromeUtils.importESModule("resource://test/non_shared_nest_import_non_shared_2.mjs", {
    300  global: "current",
    301 });
    302 `);
    303  } catch (e) {
    304    caught = true;
    305    Assert.stringMatches(e.message, /cannot be used for different global/);
    306  }
    307  Assert.ok(caught);
    308 });
    309 
    310 add_task(async function testImportNestNonSharedAfterImport() {
    311  // Nested import for non-shared global is allowed after the import, both for
    312  // the same and different globals.
    313 
    314  const win1 = createChromeWindow();
    315 
    316  const uri = "http://example.com/";
    317  const window = createContentWindow(uri);
    318  const sandboxOpts = {
    319    sandboxPrototype: window,
    320    wantGlobalProperties: ["ChromeUtils"],
    321  };
    322  win1.sb = new Cu.Sandbox(uri, sandboxOpts);
    323 
    324  const result = win1.eval(`
    325 const { func3 } = ChromeUtils.importESModule("resource://test/non_shared_nest_import_non_shared_3.mjs", {
    326  global: "current",
    327 });
    328 
    329 // Nested import happens here.
    330 func3();
    331 `);
    332  Assert.equal(result, 22);
    333 });
    334 
    335 add_task(async function testIsolationWithSandbox() {
    336  // Modules should be isolated for each sandbox.
    337 
    338  const uri = "http://example.com/";
    339  const window = createContentWindow(uri);
    340  const sandboxOpts = {
    341    sandboxPrototype: window,
    342    wantGlobalProperties: ["ChromeUtils"],
    343  };
    344  const sb1 = new Cu.Sandbox(uri, sandboxOpts);
    345  const sb2 = new Cu.Sandbox(uri, sandboxOpts);
    346  const sb3 = new Cu.Sandbox(uri, sandboxOpts);
    347 
    348  // Verify modules in 2 sandboxes are isolated.
    349 
    350  Cu.evalInSandbox(`
    351 globalThis["loaded"] = [];
    352 var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
    353  global: "current",
    354 });
    355 `, sb1);
    356  Cu.evalInSandbox(`
    357 globalThis["loaded"] = [];
    358 var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
    359  global: "current",
    360 });
    361 `, sb2);
    362 
    363  Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb1), 0);
    364  Cu.evalInSandbox(`ns.incCounter();`, sb1);
    365  Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb1), 1);
    366 
    367  Assert.equal(Cu.evalInSandbox(`globalThis["loaded"].join(",")`, sb1), "2,1");
    368 
    369  Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb2), 0);
    370  Cu.evalInSandbox(`ns.incCounter();`, sb2);
    371  Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb2), 1);
    372 
    373  Assert.equal(Cu.evalInSandbox(`globalThis["loaded"].join(",")`, sb2), "2,1");
    374 
    375  // Verify importing after any modification to different global doesn't affect.
    376 
    377  const ns3 = Cu.evalInSandbox(`
    378 globalThis["loaded"] = [];
    379 var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
    380  global: "current",
    381 });
    382 `, sb3);
    383 
    384  Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb3), 0);
    385  Cu.evalInSandbox(`ns.incCounter();`, sb3);
    386  Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb3), 1);
    387 
    388  Assert.equal(Cu.evalInSandbox(`globalThis["loaded"].join(",")`, sb3), "2,1");
    389 
    390  // Verify yet another modification are still isolated.
    391 
    392  Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb1), 1);
    393  Cu.evalInSandbox(`ns.incCounter();`, sb1);
    394  Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb1), 2);
    395 
    396  Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb2), 1);
    397  Cu.evalInSandbox(`ns.incCounter();`, sb2);
    398  Cu.evalInSandbox(`ns.incCounter();`, sb2);
    399  Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb2), 3);
    400 
    401  Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb3), 1);
    402  Cu.evalInSandbox(`ns.incCounter();`, sb3);
    403  Cu.evalInSandbox(`ns.incCounter();`, sb3);
    404  Cu.evalInSandbox(`ns.incCounter();`, sb3);
    405  Assert.equal(Cu.evalInSandbox(`ns.getCounter();`, sb3), 4);
    406 
    407  // Verify the module's `globalThis` points the target global.
    408 
    409  Cu.evalInSandbox(`ns.putCounter();`, sb1);
    410  Cu.evalInSandbox(`ns.putCounter();`, sb2);
    411  Cu.evalInSandbox(`ns.putCounter();`, sb3);
    412 
    413  const counter1 = Cu.evalInSandbox(`globalThis["counter"]`, sb1);
    414  Assert.equal(counter1, 2);
    415  const counter2 = Cu.evalInSandbox(`globalThis["counter"]`, sb2);
    416  Assert.equal(counter2, 3);
    417  const counter3 = Cu.evalInSandbox(`globalThis["counter"]`, sb3);
    418  Assert.equal(counter3, 4);
    419 });
    420 
    421 add_task(async function testIsolationWithWindow() {
    422  // Modules should be isolated for each window.
    423 
    424  const win1 = createChromeWindow();
    425  const win2 = createChromeWindow();
    426  const win3 = createChromeWindow();
    427 
    428  // Verify modules in 2 sandboxes are isolated.
    429 
    430  win1.eval(`
    431 globalThis["loaded"] = [];
    432 var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
    433  global: "current",
    434 });
    435 `);
    436  win2.eval(`
    437 globalThis["loaded"] = [];
    438 var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
    439  global: "current",
    440 });
    441 `);
    442 
    443  Assert.equal(win1.eval(`ns.getCounter();`), 0);
    444  win1.eval(`ns.incCounter();`);
    445  Assert.equal(win1.eval(`ns.getCounter();`), 1);
    446 
    447  Assert.equal(win1.eval(`globalThis["loaded"].join(",")`), "2,1");
    448 
    449  Assert.equal(win2.eval(`ns.getCounter();`), 0);
    450  win2.eval(`ns.incCounter();`);
    451  Assert.equal(win2.eval(`ns.getCounter();`), 1);
    452 
    453  Assert.equal(win2.eval(`globalThis["loaded"].join(",")`), "2,1");
    454 
    455  // Verify importing after any modification to different global doesn't affect.
    456 
    457  const ns3 = win3.eval(`
    458 globalThis["loaded"] = [];
    459 var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
    460  global: "current",
    461 });
    462 `);
    463 
    464  Assert.equal(win3.eval(`ns.getCounter();`), 0);
    465  win3.eval(`ns.incCounter();`);
    466  Assert.equal(win3.eval(`ns.getCounter();`), 1);
    467 
    468  Assert.equal(win3.eval(`globalThis["loaded"].join(",")`), "2,1");
    469 
    470  // Verify yet another modification are still isolated.
    471 
    472  Assert.equal(win1.eval(`ns.getCounter();`), 1);
    473  win1.eval(`ns.incCounter();`);
    474  Assert.equal(win1.eval(`ns.getCounter();`), 2);
    475 
    476  Assert.equal(win2.eval(`ns.getCounter();`), 1);
    477  win2.eval(`ns.incCounter();`);
    478  win2.eval(`ns.incCounter();`);
    479  Assert.equal(win2.eval(`ns.getCounter();`), 3);
    480 
    481  Assert.equal(win3.eval(`ns.getCounter();`), 1);
    482  win3.eval(`ns.incCounter();`);
    483  win3.eval(`ns.incCounter();`);
    484  win3.eval(`ns.incCounter();`);
    485  Assert.equal(win3.eval(`ns.getCounter();`), 4);
    486 
    487  // Verify the module's `globalThis` points the target global.
    488 
    489  win1.eval(`ns.putCounter();`);
    490  win2.eval(`ns.putCounter();`);
    491  win3.eval(`ns.putCounter();`);
    492 
    493  const counter1 = win1.eval(`globalThis["counter"]`);
    494  Assert.equal(counter1, 2);
    495  const counter2 = win2.eval(`globalThis["counter"]`);
    496  Assert.equal(counter2, 3);
    497  const counter3 = win3.eval(`globalThis["counter"]`);
    498  Assert.equal(counter3, 4);
    499 });
    500 
    501 add_task(async function testSyncImportBeforeAsyncImportTopLevel() {
    502  const window = createChromeWindow();
    503 
    504  window.eval(`
    505 globalThis["loaded"] = [];
    506 var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
    507  global: "current",
    508 });
    509 `);
    510 
    511  Assert.equal(window.eval(`ns.getCounter();`), 0);
    512  window.eval(`ns.incCounter();`);
    513  Assert.equal(window.eval(`ns.getCounter();`), 1);
    514 
    515  Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
    516 
    517  window.eval(`
    518 var ns2 = null;
    519 const nsPromise = import("resource://test/non_shared_1.mjs");
    520 nsPromise.then(v => { ns2 = v; });
    521 `);
    522 
    523  Services.tm.spinEventLoopUntil(
    524    "Wait until dynamic import finishes",
    525    () => window.eval(`ns2 !== null`)
    526  );
    527 
    528  Assert.equal(window.eval(`ns2.getCounter();`), 1);
    529  window.eval(`ns2.incCounter();`);
    530  Assert.equal(window.eval(`ns2.getCounter();`), 2);
    531  Assert.equal(window.eval(`ns.getCounter();`), 2);
    532 
    533  Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
    534 });
    535 
    536 add_task(async function testSyncImportBeforeAsyncImportDependency() {
    537  const window = createChromeWindow();
    538 
    539  window.eval(`
    540 globalThis["loaded"] = [];
    541 var ns = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
    542  global: "current",
    543 });
    544 `);
    545 
    546  Assert.equal(window.eval(`ns.getCounter();`), 0);
    547  window.eval(`ns.incCounter();`);
    548  Assert.equal(window.eval(`ns.getCounter();`), 1);
    549 
    550  Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
    551 
    552  window.eval(`
    553 var ns2 = null;
    554 const nsPromise = import("resource://test/import_non_shared_1.mjs");
    555 nsPromise.then(v => { ns2 = v; });
    556 `);
    557 
    558  Services.tm.spinEventLoopUntil(
    559    "Wait until dynamic import finishes",
    560    () => window.eval(`ns2 !== null`)
    561  );
    562 
    563  Assert.equal(window.eval(`ns2.getCounter();`), 1);
    564  window.eval(`ns2.incCounter();`);
    565  Assert.equal(window.eval(`ns2.getCounter();`), 2);
    566  Assert.equal(window.eval(`ns.getCounter();`), 2);
    567 
    568  Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
    569 });
    570 
    571 add_task(async function testSyncImportAfterAsyncImportTopLevel() {
    572  const window = createChromeWindow();
    573 
    574  window.eval(`
    575 var ns = null;
    576 globalThis["loaded"] = [];
    577 const nsPromise = import("resource://test/non_shared_1.mjs");
    578 nsPromise.then(v => { ns = v; });
    579 `);
    580 
    581  Services.tm.spinEventLoopUntil(
    582    "Wait until dynamic import finishes",
    583    () => window.eval(`ns !== null`)
    584  );
    585 
    586  Assert.equal(window.eval(`ns.getCounter();`), 0);
    587  window.eval(`ns.incCounter();`);
    588  Assert.equal(window.eval(`ns.getCounter();`), 1);
    589 
    590  Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
    591 
    592  window.eval(`
    593 var ns2 = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
    594  global: "current",
    595 });
    596 `);
    597 
    598  Assert.equal(window.eval(`ns2.getCounter();`), 1);
    599  window.eval(`ns2.incCounter();`);
    600  Assert.equal(window.eval(`ns2.getCounter();`), 2);
    601  Assert.equal(window.eval(`ns.getCounter();`), 2);
    602 
    603  Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
    604 });
    605 
    606 add_task(async function testSyncImportAfterAsyncImportDependency() {
    607  const window = createChromeWindow();
    608 
    609  window.eval(`
    610 var ns = null;
    611 globalThis["loaded"] = [];
    612 const nsPromise = import("resource://test/non_shared_1.mjs");
    613 nsPromise.then(v => { ns = v; });
    614 `);
    615 
    616  Services.tm.spinEventLoopUntil(
    617    "Wait until dynamic import finishes",
    618    () => window.eval(`ns !== null`)
    619  );
    620 
    621  Assert.equal(window.eval(`ns.getCounter();`), 0);
    622  window.eval(`ns.incCounter();`);
    623  Assert.equal(window.eval(`ns.getCounter();`), 1);
    624 
    625  Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
    626 
    627  window.eval(`
    628 var ns2 = ChromeUtils.importESModule("resource://test/import_non_shared_1.mjs", {
    629  global: "current",
    630 });
    631 `);
    632 
    633  Assert.equal(window.eval(`ns2.getCounter();`), 1);
    634  window.eval(`ns2.incCounter();`);
    635  Assert.equal(window.eval(`ns2.getCounter();`), 2);
    636  Assert.equal(window.eval(`ns.getCounter();`), 2);
    637 
    638  Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
    639 });
    640 
    641 add_task(async function testSyncImportWhileAsyncImportTopLevel() {
    642  const window = createChromeWindow();
    643 
    644  window.eval(`
    645 var ns = null;
    646 globalThis["loaded"] = [];
    647 const nsPromise = import("resource://test/non_shared_1.mjs");
    648 nsPromise.then(v => { ns = v; });
    649 `);
    650 
    651  window.eval(`
    652 var ns2 = ChromeUtils.importESModule("resource://test/non_shared_1.mjs", {
    653  global: "current",
    654 });
    655 `);
    656 
    657  Assert.equal(window.eval(`ns2.getCounter();`), 0);
    658  window.eval(`ns2.incCounter();`);
    659  Assert.equal(window.eval(`ns2.getCounter();`), 1);
    660 
    661  Services.tm.spinEventLoopUntil(
    662    "Wait until dynamic import finishes",
    663    () => window.eval(`ns !== null`)
    664  );
    665 
    666  Assert.equal(window.eval(`ns.getCounter();`), 1);
    667  window.eval(`ns.incCounter();`);
    668  Assert.equal(window.eval(`ns.getCounter();`), 2);
    669  Assert.equal(window.eval(`ns2.getCounter();`), 2);
    670 
    671  Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
    672 });
    673 
    674 add_task(async function testSyncImportWhileAsyncImportDependency() {
    675  const window = createChromeWindow();
    676 
    677  window.eval(`
    678 var ns = null;
    679 globalThis["loaded"] = [];
    680 const nsPromise = import("resource://test/non_shared_1.mjs");
    681 nsPromise.then(v => { ns = v; });
    682 `);
    683 
    684  window.eval(`
    685 var ns2 = ChromeUtils.importESModule("resource://test/import_non_shared_1.mjs", {
    686  global: "current",
    687 });
    688 `);
    689 
    690  Assert.equal(window.eval(`ns2.getCounter();`), 0);
    691  window.eval(`ns2.incCounter();`);
    692  Assert.equal(window.eval(`ns2.getCounter();`), 1);
    693 
    694  Services.tm.spinEventLoopUntil(
    695    "Wait until dynamic import finishes",
    696    () => window.eval(`ns !== null`)
    697  );
    698 
    699  Assert.equal(window.eval(`ns.getCounter();`), 1);
    700  window.eval(`ns.incCounter();`);
    701  Assert.equal(window.eval(`ns.getCounter();`), 2);
    702  Assert.equal(window.eval(`ns2.getCounter();`), 2);
    703 
    704  Assert.equal(window.eval(`globalThis["loaded"].join(",")`), "2,1");
    705 });
    706 
    707 add_task(async function testSyncImportBeforeAsyncImportTLA() {
    708  // Top-level-await is not supported by sync import.
    709 
    710  const window = createChromeWindow();
    711 
    712  let caught = false;
    713 
    714  try {
    715    window.eval(`
    716 ChromeUtils.importESModule("resource://test/es6module_top_level_await.js", {
    717  global: "current",
    718 });
    719 `);
    720  } catch (e) {
    721    caught = true;
    722    Assert.stringMatches(e.message, /top level await is not supported/);
    723  }
    724  Assert.ok(caught);
    725 
    726  window.eval(`
    727 var ns2 = null;
    728 const nsPromise = import("resource://test/es6module_top_level_await.js");
    729 nsPromise.then(v => { ns2 = v; });
    730 `);
    731 
    732  Services.tm.spinEventLoopUntil(
    733    "Wait until dynamic import finishes",
    734    () => window.eval(`ns2 !== null`)
    735  );
    736 
    737  Assert.equal(window.eval(`ns2.foo();`), 10);
    738 });
    739 
    740 add_task(async function testSyncImportAfterAsyncImportTLA() {
    741  // Top-level-await is not supported by sync import, but if the module is
    742  // already imported, the existing module namespace is returned.
    743 
    744  const window = createChromeWindow();
    745 
    746  window.eval(`
    747 var ns2 = null;
    748 const nsPromise = import("resource://test/es6module_top_level_await.js");
    749 nsPromise.then(v => { ns2 = v; });
    750 `);
    751 
    752  Services.tm.spinEventLoopUntil(
    753    "Wait until dynamic import finishes",
    754    () => window.eval(`ns2 !== null`)
    755  );
    756 
    757  Assert.equal(window.eval(`ns2.foo();`), 10);
    758 
    759  window.eval(`
    760 var ns = ChromeUtils.importESModule("resource://test/es6module_top_level_await.js", {
    761  global: "current",
    762 });
    763 `);
    764 
    765  Assert.equal(window.eval(`ns.foo();`), 10);
    766  Assert.equal(window.eval(`ns2.foo == ns.foo;`), true);
    767 });
    768 
    769 // TODO: Bug 1973663: Enable xpcshell test testSyncImportWhileAsyncImportTLA
    770 /*
    771 add_task(async function testSyncImportWhileAsyncImportTLA() {
    772  // Top-level-await is not supported by sync import, but if the module is
    773  // already fetching, ChromeUtils.importESModule waits for it and, the
    774  // async-imported module namespace is returned.
    775 
    776  const window = createChromeWindow();
    777 
    778  window.eval(`
    779 var ns2 = null;
    780 const nsPromise = import("resource://test/es6module_top_level_await.js");
    781 nsPromise.then(v => { ns2 = v; });
    782 `);
    783 
    784  window.eval(`
    785 var ns = ChromeUtils.importESModule("resource://test/es6module_top_level_await.js", {
    786  global: "current",
    787 });
    788 `);
    789 
    790  Services.tm.spinEventLoopUntil(
    791    "Wait until dynamic import finishes",
    792    () => window.eval(`ns2 !== null`)
    793  );
    794 
    795  Assert.equal(window.eval(`ns2.foo();`), 10);
    796  Assert.equal(window.eval(`ns.foo();`), 10);
    797  Assert.equal(window.eval(`ns2.foo == ns.foo;`), true);
    798 });
    799 */