1"use strict"; 2 3function receiveEventOnce(target, name) { 4 return new Promise(resolve => { 5 target.addEventListener( 6 name, 7 ev => { 8 resolve(ev); 9 }, 10 { once: true } 11 ); 12 }); 13} 14 15async function postAndTestMessageEvent(data, transfer, title) { 16 postMessage(data, "*", transfer); 17 const messagePortCount = transfer.filter(i => i instanceof MessagePort) 18 .length; 19 const ev = await receiveEventOnce(window, "message"); 20 assert_equals( 21 ev.ports.length, 22 messagePortCount, 23 `Correct number of ports ${title}` 24 ); 25 for (const [i, port] of ev.ports.entries()) { 26 assert_true( 27 port instanceof MessagePort, 28 `ports[${i}] include MessagePort ${title}` 29 ); 30 } 31 for (const [key, value] of Object.entries(data)) { 32 assert_true( 33 ev.data[key] instanceof value.constructor, 34 `data.${key} has correct interface ${value.constructor.name} ${title}` 35 ); 36 } 37} 38 39async function transferMessagePortWithOrder1(stream) { 40 const channel = new MessageChannel(); 41 await postAndTestMessageEvent( 42 { stream, port2: channel.port2 }, 43 [stream, channel.port2], 44 `when transferring [${stream.constructor.name}, MessagePort]` 45 ); 46} 47 48async function transferMessagePortWithOrder2(stream) { 49 const channel = new MessageChannel(); 50 await postAndTestMessageEvent( 51 { stream, port2: channel.port2 }, 52 [channel.port2, stream], 53 `when transferring [MessagePort, ${stream.constructor.name}]` 54 ); 55} 56 57async function transferMessagePortWithOrder3(stream) { 58 const channel = new MessageChannel(); 59 await postAndTestMessageEvent( 60 { port1: channel.port1, stream, port2: channel.port2 }, 61 [channel.port1, stream, channel.port2], 62 `when transferring [MessagePort, ${stream.constructor.name}, MessagePort]` 63 ); 64} 65 66async function transferMessagePortWithOrder4(stream) { 67 const channel = new MessageChannel(); 68 await postAndTestMessageEvent( 69 {}, 70 [channel.port1, stream, channel.port2], 71 `when transferring [MessagePort, ${stream.constructor.name}, MessagePort] but with empty data` 72 ); 73} 74 75async function transferMessagePortWithOrder5(stream) { 76 const channel = new MessageChannel(); 77 await postAndTestMessageEvent( 78 { port2: channel.port2, port1: channel.port1, stream }, 79 [channel.port1, stream, channel.port2], 80 `when transferring [MessagePort, ${stream.constructor.name}, MessagePort] but with data having different order` 81 ); 82} 83 84async function transferMessagePortWithOrder6(stream) { 85 const channel = new MessageChannel(); 86 await postAndTestMessageEvent( 87 { port2: channel.port2, port1: channel.port1 }, 88 [channel.port1, stream, channel.port2], 89 `when transferring [MessagePort, ${stream.constructor.name}, MessagePort] but with stream not being in the data` 90 ); 91} 92 93async function transferMessagePortWithOrder7(stream) { 94 const channel = new MessageChannel(); 95 await postAndTestMessageEvent( 96 { stream }, 97 [channel.port1, stream, channel.port2], 98 `when transferring [MessagePort, ${stream.constructor.name}, MessagePort] but with ports not being in the data` 99 ); 100} 101 102async function transferMessagePortWith(constructor) { 103 await transferMessagePortWithOrder1(new constructor()); 104 await transferMessagePortWithOrder2(new constructor()); 105 await transferMessagePortWithOrder3(new constructor()); 106} 107 108async function advancedTransferMesagePortWith(constructor) { 109 await transferMessagePortWithOrder4(new constructor()); 110 await transferMessagePortWithOrder5(new constructor()); 111 await transferMessagePortWithOrder6(new constructor()); 112 await transferMessagePortWithOrder7(new constructor()); 113} 114 115async function mixedTransferMessagePortWithOrder1() { 116 const channel = new MessageChannel(); 117 const readable = new ReadableStream(); 118 const writable = new WritableStream(); 119 const transform = new TransformStream(); 120 await postAndTestMessageEvent( 121 { 122 readable, 123 writable, 124 transform, 125 port1: channel.port1, 126 port2: channel.port2, 127 }, 128 [readable, writable, transform, channel.port1, channel.port2], 129 `when transferring [ReadableStream, WritableStream, TransformStream, MessagePort, MessagePort]` 130 ); 131} 132 133async function mixedTransferMessagePortWithOrder2() { 134 const channel = new MessageChannel(); 135 const readable = new ReadableStream(); 136 const writable = new WritableStream(); 137 const transform = new TransformStream(); 138 await postAndTestMessageEvent( 139 { readable, writable, transform }, 140 [transform, channel.port1, readable, channel.port2, writable], 141 `when transferring [TransformStream, MessagePort, ReadableStream, MessagePort, WritableStream]` 142 ); 143} 144 145async function mixedTransferMessagePortWithOrder3() { 146 const channel = new MessageChannel(); 147 const readable1 = new ReadableStream(); 148 const readable2 = new ReadableStream(); 149 const writable1 = new WritableStream(); 150 const writable2 = new WritableStream(); 151 const transform1 = new TransformStream(); 152 const transform2 = new TransformStream(); 153 await postAndTestMessageEvent( 154 { readable1, writable1, transform1, readable2, writable2, transform2 }, 155 [ 156 transform2, 157 channel.port1, 158 readable1, 159 channel.port2, 160 writable2, 161 readable2, 162 writable1, 163 transform1, 164 ], 165 `when transferring [TransformStream, MessagePort, ReadableStream, MessagePort, WritableStream, ReadableStream, WritableStream, TransformStream] but with the data having different order` 166 ); 167} 168 169async function mixedTransferMesagePortWith() { 170 await mixedTransferMessagePortWithOrder1(); 171 await mixedTransferMessagePortWithOrder2(); 172 await mixedTransferMessagePortWithOrder3(); 173} 174 175promise_test(async t => { 176 await transferMessagePortWith(ReadableStream); 177}, "Transferring a MessagePort with a ReadableStream should set `.ports`"); 178 179promise_test(async t => { 180 await transferMessagePortWith(WritableStream); 181}, "Transferring a MessagePort with a WritableStream should set `.ports`"); 182 183promise_test(async t => { 184 await transferMessagePortWith(TransformStream); 185}, "Transferring a MessagePort with a TransformStream should set `.ports`"); 186 187promise_test(async t => { 188 await transferMessagePortWith(ReadableStream); 189}, "Transferring a MessagePort with a ReadableStream should set `.ports`, advanced"); 190 191promise_test(async t => { 192 await transferMessagePortWith(WritableStream); 193}, "Transferring a MessagePort with a WritableStream should set `.ports`, advanced"); 194 195promise_test(async t => { 196 await transferMessagePortWith(TransformStream); 197}, "Transferring a MessagePort with a TransformStream should set `.ports`, advanced"); 198 199promise_test(async t => { 200 await mixedTransferMesagePortWith(); 201}, "Transferring a MessagePort with multiple streams should set `.ports`"); 202 203test(() => { 204 assert_throws_dom("DataCloneError", () => 205 postMessage({ stream: new ReadableStream() }, "*") 206 ); 207}, "ReadableStream must not be serializable"); 208 209test(() => { 210 assert_throws_dom("DataCloneError", () => 211 postMessage({ stream: new WritableStream() }, "*") 212 ); 213}, "WritableStream must not be serializable"); 214 215test(() => { 216 assert_throws_dom("DataCloneError", () => 217 postMessage({ stream: new TransformStream() }, "*") 218 ); 219}, "TransformStream must not be serializable"); 220