[READ-ONLY] Mirror of https://github.com/vitest-dev/vitest. Next generation testing framework powered by Vite. vitest.dev
test testing-tools vite
12

Configure Feed

Select the types of activity you want to include in your feed.

fix(web-worker): MessagePort objects passed to Worker.postMessage work when clone === "native" (#9118)

authored by

Yuichiro Tachibana (Tsuchiya) and committed by
GitHub
(Nov 28, 2025, 10:10 AM +0100) deee83e5 fd8bd6de

+32 -12
+4 -1
packages/web-worker/src/utils.ts
··· 31 31 debug('clone worker message %o', data) 32 32 const origin = typeof location === 'undefined' ? undefined : location.origin 33 33 const ports = transfer?.filter((t): t is MessagePort => t instanceof MessagePort) 34 + const transferWithoutPorts = transfer?.filter( // `ports` must be excluded from the `transfer` option passed to `structuredClone` to keep the MessagePort objects working correctly in the same thread. 35 + t => !(t instanceof MessagePort), 36 + ) 34 37 35 38 if (typeof structuredClone === 'function' && clone === 'native') { 36 39 debug('create message event, using native structured clone') 37 40 return new MessageEvent('message', { 38 - data: structuredClone(data, { transfer }), 41 + data: structuredClone(data, { transfer: transferWithoutPorts }), 39 42 origin, 40 43 ports, 41 44 })
+28 -11
test/core/test/web-worker-node.test.ts
··· 1 1 // @vitest-environment node 2 2 3 + import type { defineWebWorkers } from '@vitest/web-worker/pure' 4 + 3 5 import { version } from 'node:process' 4 6 5 - import { beforeEach, describe, expect, it, vi } from 'vitest' 7 + import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' 6 8 import MyEventListenerWorker from '../src/web-worker/eventListenerWorker?worker' 7 - 8 9 import MyObjectWorker from '../src/web-worker/objectWorker?worker' 9 10 import MySelfWorker from '../src/web-worker/selfWorker?worker' 10 11 import MySharedWorker from '../src/web-worker/sharedWorker?sharedworker' ··· 211 212 expect(await testSelfWorker(new Worker(new URL('../src/web-worker/selfWorker.ts', import.meta.url)))).toBeTruthy() 212 213 }) 213 214 214 - it('transfer MessagePort objects to worker as event.ports', async () => { 215 - expect.assertions(1) 215 + const cloneTypes = [ 216 + 'native', 217 + 'ponyfill', 218 + 'none', 219 + ] satisfies Array<NonNullable<Parameters<typeof defineWebWorkers>[0]>['clone']> 220 + cloneTypes.forEach((clone) => { 221 + describe(`defineWebWorkers with clone=${clone}`, () => { 222 + beforeEach(() => { 223 + process.env.VITEST_WEB_WORKER_CLONE = clone 224 + }) 225 + afterEach(() => { 226 + process.env.VITEST_WEB_WORKER_CLONE = undefined 227 + }) 216 228 217 - const worker = new MyWorker() 218 - const channel = new MessageChannel() 219 - const promise = new Promise<string>((resolve, reject) => { 220 - channel.port1.onmessage = e => resolve(e.data as string) 221 - channel.port1.onmessageerror = reject 229 + it('transfers MessagePort objects to worker as event.ports', async () => { 230 + expect.assertions(1) 231 + 232 + const worker = new MyWorker() 233 + const channel = new MessageChannel() 234 + const promise = new Promise<string>((resolve, reject) => { 235 + channel.port1.onmessage = e => resolve(e.data as string) 236 + channel.port1.onmessageerror = reject 237 + }) 238 + worker.postMessage('hello', [channel.port2]) 239 + await expect(promise).resolves.toBe('hello world via port') 240 + }) 222 241 }) 223 - worker.postMessage('hello', [channel.port2]) 224 - await expect(promise).resolves.toBe('hello world via port') 225 242 }) 226 243 227 244 it('throws syntax error if no arguments are provided', () => {