"use strict"; function receiveEventOnce(target, name) { return new Promise(resolve => { target.addEventListener( name, ev => { resolve(ev); }, { once: true } ); }); } async function postAndTestMessageEvent(data, transfer, title) { postMessage(data, "*", transfer); const messagePortCount = transfer.filter(i => i instanceof MessagePort) .length; const ev = await receiveEventOnce(window, "message"); assert_equals( ev.ports.length, messagePortCount, `Correct number of ports ${title}` ); for (const [i, port] of ev.ports.entries()) { assert_true( port instanceof MessagePort, `ports[${i}] include MessagePort ${title}` ); } for (const [key, value] of Object.entries(data)) { assert_true( ev.data[key] instanceof value.constructor, `data.${key} has correct interface ${value.constructor.name} ${title}` ); } } async function transferMessagePortWithOrder1(stream) { const channel = new MessageChannel(); await postAndTestMessageEvent( { stream, port2: channel.port2 }, [stream, channel.port2], `when transferring [${stream.constructor.name}, MessagePort]` ); } async function transferMessagePortWithOrder2(stream) { const channel = new MessageChannel(); await postAndTestMessageEvent( { stream, port2: channel.port2 }, [channel.port2, stream], `when transferring [MessagePort, ${stream.constructor.name}]` ); } async function transferMessagePortWithOrder3(stream) { const channel = new MessageChannel(); await postAndTestMessageEvent( { port1: channel.port1, stream, port2: channel.port2 }, [channel.port1, stream, channel.port2], `when transferring [MessagePort, ${stream.constructor.name}, MessagePort]` ); } async function transferMessagePortWithOrder4(stream) { const channel = new MessageChannel(); await postAndTestMessageEvent( {}, [channel.port1, stream, channel.port2], `when transferring [MessagePort, ${stream.constructor.name}, MessagePort] but with empty data` ); } async function transferMessagePortWithOrder5(stream) { const channel = new MessageChannel(); await postAndTestMessageEvent( { port2: channel.port2, port1: channel.port1, stream }, [channel.port1, stream, channel.port2], `when transferring [MessagePort, ${stream.constructor.name}, MessagePort] but with data having different order` ); } async function transferMessagePortWithOrder6(stream) { const channel = new MessageChannel(); await postAndTestMessageEvent( { port2: channel.port2, port1: channel.port1 }, [channel.port1, stream, channel.port2], `when transferring [MessagePort, ${stream.constructor.name}, MessagePort] but with stream not being in the data` ); } async function transferMessagePortWithOrder7(stream) { const channel = new MessageChannel(); await postAndTestMessageEvent( { stream }, [channel.port1, stream, channel.port2], `when transferring [MessagePort, ${stream.constructor.name}, MessagePort] but with ports not being in the data` ); } async function transferMessagePortWith(constructor) { await transferMessagePortWithOrder1(new constructor()); await transferMessagePortWithOrder2(new constructor()); await transferMessagePortWithOrder3(new constructor()); } async function advancedTransferMesagePortWith(constructor) { await transferMessagePortWithOrder4(new constructor()); await transferMessagePortWithOrder5(new constructor()); await transferMessagePortWithOrder6(new constructor()); await transferMessagePortWithOrder7(new constructor()); } async function mixedTransferMessagePortWithOrder1() { const channel = new MessageChannel(); const readable = new ReadableStream(); const writable = new WritableStream(); const transform = new TransformStream(); await postAndTestMessageEvent( { readable, writable, transform, port1: channel.port1, port2: channel.port2, }, [readable, writable, transform, channel.port1, channel.port2], `when transferring [ReadableStream, WritableStream, TransformStream, MessagePort, MessagePort]` ); } async function mixedTransferMessagePortWithOrder2() { const channel = new MessageChannel(); const readable = new ReadableStream(); const writable = new WritableStream(); const transform = new TransformStream(); await postAndTestMessageEvent( { readable, writable, transform }, [transform, channel.port1, readable, channel.port2, writable], `when transferring [TransformStream, MessagePort, ReadableStream, MessagePort, WritableStream]` ); } async function mixedTransferMessagePortWithOrder3() { const channel = new MessageChannel(); const readable1 = new ReadableStream(); const readable2 = new ReadableStream(); const writable1 = new WritableStream(); const writable2 = new WritableStream(); const transform1 = new TransformStream(); const transform2 = new TransformStream(); await postAndTestMessageEvent( { readable1, writable1, transform1, readable2, writable2, transform2 }, [ transform2, channel.port1, readable1, channel.port2, writable2, readable2, writable1, transform1, ], `when transferring [TransformStream, MessagePort, ReadableStream, MessagePort, WritableStream, ReadableStream, WritableStream, TransformStream] but with the data having different order` ); } async function mixedTransferMesagePortWith() { await mixedTransferMessagePortWithOrder1(); await mixedTransferMessagePortWithOrder2(); await mixedTransferMessagePortWithOrder3(); } promise_test(async t => { await transferMessagePortWith(ReadableStream); }, "Transferring a MessagePort with a ReadableStream should set `.ports`"); promise_test(async t => { await transferMessagePortWith(WritableStream); }, "Transferring a MessagePort with a WritableStream should set `.ports`"); promise_test(async t => { await transferMessagePortWith(TransformStream); }, "Transferring a MessagePort with a TransformStream should set `.ports`"); promise_test(async t => { await transferMessagePortWith(ReadableStream); }, "Transferring a MessagePort with a ReadableStream should set `.ports`, advanced"); promise_test(async t => { await transferMessagePortWith(WritableStream); }, "Transferring a MessagePort with a WritableStream should set `.ports`, advanced"); promise_test(async t => { await transferMessagePortWith(TransformStream); }, "Transferring a MessagePort with a TransformStream should set `.ports`, advanced"); promise_test(async t => { await mixedTransferMesagePortWith(); }, "Transferring a MessagePort with multiple streams should set `.ports`"); test(() => { assert_throws_dom("DataCloneError", () => postMessage({ stream: new ReadableStream() }, "*") ); }, "ReadableStream must not be serializable"); test(() => { assert_throws_dom("DataCloneError", () => postMessage({ stream: new WritableStream() }, "*") ); }, "WritableStream must not be serializable"); test(() => { assert_throws_dom("DataCloneError", () => postMessage({ stream: new TransformStream() }, "*") ); }, "TransformStream must not be serializable");