diff --git a/.circleci/config.yml b/.circleci/config.yml index 87740249862fb..5f80abb145ff7 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -872,6 +872,8 @@ jobs: - upload-test-results test-bun: executor: linux-python + environment: + OVERRIDE_NODE_JS_TEST_VERSION: "v24.0.0" steps: - checkout - pip-install @@ -880,10 +882,14 @@ jobs: name: install bun command: | curl -fsSL https://bun.com/install | bash - echo "BUN_ENGINE = os.path.expanduser('~/.bun/bin/bun')" >> ~/emsdk/.emscripten - echo "JS_ENGINES = [BUN_ENGINE]" >> ~/emsdk/.emscripten + echo "NODE_JS_TEST = os.path.expanduser('~/.bun/bin/bun')" >> ~/emsdk/.emscripten + echo "JS_ENGINES = [NODE_JS_TEST]" >> ~/emsdk/.emscripten - run-tests: - test_targets: "core0.test_hello_world" + test_targets: " + core0.test_hello_world + core0.test_hello_argc_pthreads + core2.test_pthread_create + " test-jsc: executor: linux-python steps: diff --git a/src/pthread_esm_startup.mjs b/src/pthread_esm_startup.mjs index fe53ed6a7e5a0..c28d9f1fdea8c 100644 --- a/src/pthread_esm_startup.mjs +++ b/src/pthread_esm_startup.mjs @@ -16,14 +16,17 @@ console.log("Running pthread_esm_startup"); #if ENVIRONMENT_MAY_BE_NODE if ({{{ nodeDetectionCode() }}}) { // Create as web-worker-like an environment as we can. + globalThis.self = globalThis; var worker_threads = await import('worker_threads'); - global.Worker = worker_threads.Worker; + globalThis.Worker = worker_threads.Worker; var parentPort = worker_threads['parentPort']; - parentPort.on('message', (msg) => global.onmessage?.({ data: msg })); - Object.assign(globalThis, { - self: global, - postMessage: (msg) => parentPort['postMessage'](msg), - }); + // Deno and Bun already have `postMessage` defined on the global scope and + // deliver messages to `globalThis.onmessage`, so we must not duplicate that + // behavior here if `postMessage` is already present. + if (!globalThis.postMessage) { + parentPort.on('message', (msg) => globalThis.onmessage?.({ data: msg })); + globalThis.postMessage = (msg) => parentPort['postMessage'](msg); + } } #endif diff --git a/src/runtime_common.js b/src/runtime_common.js index 93523d4e12ecd..62b84cbe10e31 100644 --- a/src/runtime_common.js +++ b/src/runtime_common.js @@ -38,12 +38,15 @@ var readyPromiseResolve, readyPromiseReject; #if (PTHREADS || WASM_WORKERS) && (ENVIRONMENT_MAY_BE_NODE && !WASM_ESM_INTEGRATION) if (ENVIRONMENT_IS_NODE && {{{ ENVIRONMENT_IS_WORKER_THREAD() }}}) { // Create as web-worker-like an environment as we can. + globalThis.self = globalThis; var parentPort = worker_threads['parentPort']; - parentPort.on('message', (msg) => global.onmessage?.({ data: msg })); - Object.assign(globalThis, { - self: global, - postMessage: (msg) => parentPort['postMessage'](msg), - }); + // Deno and Bun already have `postMessage` defined on the global scope and + // deliver messages to `globalThis.onmessage`, so we must not duplicate that + // behavior here if `postMessage` is already present. + if (!globalThis.postMessage) { + parentPort.on('message', (msg) => globalThis.onmessage?.({ data: msg })); + globalThis.postMessage = (msg) => parentPort['postMessage'](msg); + } // Node.js Workers do not pass postMessage()s and uncaught exception events to the parent // thread necessarily in the same order where they were generated in sequential program order. // See https://github.com/nodejs/node/issues/59617 diff --git a/test/common.py b/test/common.py index a7393901bb02f..2334f5b64d9b4 100644 --- a/test/common.py +++ b/test/common.py @@ -393,6 +393,15 @@ def require_node(self): self.require_engine(nodejs) return nodejs + def get_node_test_version(self, nodejs): + override = os.environ.get('OVERRIDE_NODE_JS_TEST_VERSION') + if override: + override = override.removeprefix('v') + override = override.split('-')[0].split('.') + override = tuple(int(v) for v in override) + return override + return shared.get_node_version(nodejs) + def node_is_canary(self, nodejs): return nodejs and nodejs[0] and ('canary' in nodejs[0] or 'nightly' in nodejs[0]) @@ -435,7 +444,7 @@ def try_require_node_version(self, major, minor = 0, revision = 0): nodejs = self.get_nodejs() if not nodejs: self.skipTest('Test requires nodejs to run') - version = shared.get_node_version(nodejs) + version = self.get_node_test_version(nodejs) if version < (major, minor, revision): return False @@ -622,7 +631,7 @@ def setUp(self): nodejs = self.get_nodejs() if nodejs: - node_version = shared.get_node_version(nodejs) + node_version = self.get_node_test_version(nodejs) if node_version < (13, 0, 0): self.node_args.append('--unhandled-rejections=strict') elif node_version < (15, 0, 0): diff --git a/test/test_other.py b/test/test_other.py index 2f80f1963a2c4..6880bcf0c8901 100644 --- a/test/test_other.py +++ b/test/test_other.py @@ -3682,7 +3682,7 @@ def test_embind_tsgen_jspi(self): 'legacy': [1], }) def test_embind_tsgen_exceptions(self, legacy): - if not legacy and shared.get_node_version(config.NODE_JS)[0] < 22: + if not legacy and self.get_node_test_version(config.NODE_JS)[0] < 22: self.skipTest('Node version needs to be 22 or greater to run tsgen with Wasm EH') self.set_setting('WASM_LEGACY_EXCEPTIONS', legacy) @@ -12368,7 +12368,7 @@ def test_gen_struct_info(self): self.assertFileContents(path_from_root('src/struct_info_generated.json'), read_file('out.json')) # Same again for wasm64 - node_version = shared.get_node_version(self.get_nodejs()) + node_version = self.get_node_test_version(self.get_nodejs()) if node_version and node_version >= (14, 0, 0): self.run_process([PYTHON, path_from_root('tools/gen_struct_info.py'), '--wasm64', '-o', 'out.json']) self.assertFileContents(path_from_root('src/struct_info_generated_wasm64.json'), read_file('out.json')) @@ -12881,7 +12881,7 @@ def test_node_unhandled_rejection(self): self.build('main.c', cflags=['--pre-js=pre.js', '-sNODEJS_CATCH_REJECTION=0']) self.assertNotContained('unhandledRejection', read_file('main.js')) - if shared.get_node_version(self.get_nodejs())[0] >= 15: + if self.get_node_test_version(self.get_nodejs())[0] >= 15: self.skipTest('old behaviour of node JS cannot be tested on node v15 or above') output = self.run_js('main.js') @@ -13960,7 +13960,7 @@ def test_parseTools_legacy(self): @requires_node def test_min_node_version(self): - node_version = shared.get_node_version(self.get_nodejs()) + node_version = self.get_node_test_version(self.get_nodejs()) node_version = '.'.join(str(x) for x in node_version) self.set_setting('MIN_NODE_VERSION', 300000) expected = 'This emscripten-generated code requires node v30.0.0 (detected v%s' % node_version