current commit
250716.3 · tools,test: enforce best practices to detect never settling promises
'use strict';
/**
 * This test verifies that dynamic import in an indirect eval without JS stacks.
 * In this case, the referrer for the dynamic import will be null and the main
 * context default loader in createContext() resolves to cwd.
 *
 * Caveat: this test can be unstable if the loader internals are changed and performs
 * microtasks with a JS stack (e.g. with CallbackScope). In this case, the
 * referrer will be resolved to the top JS stack frame `node:internal/process/task_queues.js`.
 * This is due to the implementation detail of how V8 finds the referrer for a dynamic import
 * call.
 */

const common = require('../common');

// Can't process.chdir() in worker.
const { isMainThread } = require('worker_threads');

if (!isMainThread) {
  common.skip('This test only works on a main thread');
}

const tmpdir = require('../common/tmpdir');
const fixtures = require('../common/fixtures');
const fs = require('node:fs');
const {
  Script,
  createContext,
  constants: { USE_MAIN_CONTEXT_DEFAULT_LOADER },
} = require('node:vm');
const assert = require('node:assert');

common.expectWarning('ExperimentalWarning',
                     'vm.USE_MAIN_CONTEXT_DEFAULT_LOADER is an experimental feature and might change at any time');
assert(
  !process.execArgv.includes('--experimental-vm-modules'),
  'This test must be run without --experimental-vm-modules');
assert.strictEqual(typeof USE_MAIN_CONTEXT_DEFAULT_LOADER, 'symbol');

async function main() {
  tmpdir.refresh();
  process.chdir(tmpdir.path);

  //
  {
    const options = {
      importModuleDynamically: USE_MAIN_CONTEXT_DEFAULT_LOADER,
    };
    const ctx = createContext({}, options);
    const s = new Script('Promise.resolve("import(\'./message.mjs\')").then(eval)', {
      importModuleDynamically: common.mustNotCall(),
    });
    await assert.rejects(s.runInContext(ctx), { code: 'ERR_MODULE_NOT_FOUND' });
  }

  const moduleUrl = fixtures.fileURL('es-modules', 'message.mjs');
  fs.copyFileSync(moduleUrl, tmpdir.resolve('message.mjs'));
  {
    const options = {
      importModuleDynamically: USE_MAIN_CONTEXT_DEFAULT_LOADER,
    };
    const ctx = createContext({}, options);
    const moduleUrl = fixtures.fileURL('es-modules', 'message.mjs');
    const namespace = await import(moduleUrl.href);
    const script = new Script('Promise.resolve("import(\'./message.mjs\')").then(eval)', {
      importModuleDynamically: common.mustNotCall(),
    });
    const result = await script.runInContext(ctx);
    assert.deepStrictEqual(result, namespace);
  }
}

main().then(common.mustCall());