diff --git a/lib/internal/modules/esm/initialize_import_meta.js b/lib/internal/modules/esm/initialize_import_meta.js index d6be06f23e1493..28d10f50fd7b6f 100644 --- a/lib/internal/modules/esm/initialize_import_meta.js +++ b/lib/internal/modules/esm/initialize_import_meta.js @@ -3,12 +3,31 @@ const { getOptionValue } = require('internal/options'); const experimentalImportMetaResolve = getOptionValue('--experimental-import-meta-resolve'); +const isTestRunner = getOptionValue('--test-in-source'); const { PromisePrototypeThen, PromiseReject, + ObjectAssign, } = primordials; const asyncESM = require('internal/process/esm_loader'); +let testModule; +let runnerModule; + +function lazyLoadTestModule() { + if (testModule === undefined) { + testModule = require('internal/test_runner/harness'); + } + return testModule; +} + +function lazyLoadRunnerModule() { + if (runnerModule === undefined) { + runnerModule = require('internal/test_runner/runner'); + } + return runnerModule; +} + function createImportMetaResolve(defaultParentUrl) { return async function resolve(specifier, parentUrl = defaultParentUrl) { return PromisePrototypeThen( @@ -34,6 +53,21 @@ function initializeImportMeta(meta, context) { } meta.url = url; + if (isTestRunner) { + const { test, describe, it, before, after, beforeEach, afterEach } = lazyLoadTestModule(); + const { run } = lazyLoadRunnerModule(); + meta.test = test; + ObjectAssign(meta.test, { + after, + afterEach, + before, + beforeEach, + describe, + it, + run, + test, + }); + } } module.exports = { diff --git a/lib/internal/test_runner/harness.js b/lib/internal/test_runner/harness.js index ffb414e30e8972..dd2e3c72fb736e 100644 --- a/lib/internal/test_runner/harness.js +++ b/lib/internal/test_runner/harness.js @@ -21,7 +21,7 @@ const { kCancelledByParent, Test, ItTest, Suite } = require('internal/test_runne const { setupTestReporters } = require('internal/test_runner/utils'); const { bigint: hrtime } = process.hrtime; -const isTestRunnerCli = getOptionValue('--test'); +const isTestRunnerCli = getOptionValue('--test') || getOptionValue('--test-in-source'); const testResources = new SafeMap(); const wasRootSetup = new SafeWeakSet(); diff --git a/lib/internal/test_runner/test.js b/lib/internal/test_runner/test.js index 48271e2e71a80e..cc941ce177e71c 100644 --- a/lib/internal/test_runner/test.js +++ b/lib/internal/test_runner/test.js @@ -64,7 +64,7 @@ const kTestTimeoutFailure = 'testTimeoutFailure'; const kHookFailure = 'hookFailed'; const kDefaultTimeout = null; const noop = FunctionPrototype; -const isTestRunner = getOptionValue('--test'); +const isTestRunner = getOptionValue('--test') || getOptionValue('--test-in-source'); const testOnlyFlag = !isTestRunner && getOptionValue('--test-only'); const testNamePatternFlag = isTestRunner ? null : getOptionValue('--test-name-pattern'); diff --git a/src/node_options.cc b/src/node_options.cc index c1f97a5d9207eb..e3c49cd6ca29e3 100644 --- a/src/node_options.cc +++ b/src/node_options.cc @@ -556,6 +556,9 @@ EnvironmentOptionsParser::EnvironmentOptionsParser() { AddOption("--test", "launch test runner on startup", &EnvironmentOptions::test_runner); + AddOption("--test-in-source", + "run tests within source file", + &EnvironmentOptions::test_runner_in_source); AddOption("--experimental-test-coverage", "enable code coverage in the test runner", &EnvironmentOptions::test_runner_coverage); diff --git a/src/node_options.h b/src/node_options.h index 07ec47d861c77f..9a3774955f6b48 100644 --- a/src/node_options.h +++ b/src/node_options.h @@ -155,6 +155,7 @@ class EnvironmentOptions : public Options { std::string diagnostic_dir; bool test_runner = false; bool test_runner_coverage = false; + bool test_runner_in_source = false; std::vector test_name_pattern; std::vector test_reporter; std::vector test_reporter_destination;