1'use strict'; 2const common = require('../common'); 3const assert = require('assert'); 4 5const { MessageChannel, MessagePort } = require('worker_threads'); 6 7{ 8 const { port1, port2 } = new MessageChannel(); 9 assert(port1 instanceof MessagePort); 10 assert(port2 instanceof MessagePort); 11 12 const input = { a: 1 }; 13 port1.postMessage(input); 14 port2.on('message', common.mustCall((received) => { 15 assert.deepStrictEqual(received, input); 16 port2.close(common.mustCall()); 17 })); 18} 19{ 20 // Test emitting non-message events on a port 21 const { port2 } = new MessageChannel(); 22 port2.addEventListener('foo', common.mustCall((received) => { 23 assert.strictEqual(received.type, 'foo'); 24 assert.strictEqual(received.detail, 'bar'); 25 })); 26 port2.on('foo', common.mustCall((received) => { 27 assert.strictEqual(received, 'bar'); 28 })); 29 port2.emit('foo', 'bar'); 30} 31{ 32 const { port1, port2 } = new MessageChannel(); 33 34 port1.onmessage = common.mustCall((message) => { 35 assert.strictEqual(message.data, 4); 36 assert.strictEqual(message.target, port1); 37 assert.deepStrictEqual(message.ports, []); 38 port2.close(common.mustCall()); 39 }); 40 41 port1.postMessage(2); 42 43 port2.onmessage = common.mustCall((message) => { 44 port2.postMessage(message.data * 2); 45 }); 46} 47 48{ 49 const { port1, port2 } = new MessageChannel(); 50 51 const input = { a: 1 }; 52 port1.postMessage(input); 53 // Check that the message still gets delivered if `port2` has its 54 // `on('message')` handler attached at a later point in time. 55 setImmediate(() => { 56 port2.on('message', common.mustCall((received) => { 57 assert.deepStrictEqual(received, input); 58 port2.close(common.mustCall()); 59 })); 60 }); 61} 62 63{ 64 const { port1, port2 } = new MessageChannel(); 65 66 const input = { a: 1 }; 67 68 const dummy = common.mustNotCall(); 69 // Check that the message still gets delivered if `port2` has its 70 // `on('message')` handler attached at a later point in time, even if a 71 // listener was removed previously. 72 port2.addListener('message', dummy); 73 setImmediate(() => { 74 port2.removeListener('message', dummy); 75 port1.postMessage(input); 76 setImmediate(() => { 77 port2.on('message', common.mustCall((received) => { 78 assert.deepStrictEqual(received, input); 79 port2.close(common.mustCall()); 80 })); 81 }); 82 }); 83} 84 85{ 86 const { port1, port2 } = new MessageChannel(); 87 port2.on('message', common.mustCall(6)); 88 port1.postMessage(1, null); 89 port1.postMessage(2, undefined); 90 port1.postMessage(3, []); 91 port1.postMessage(4, {}); 92 port1.postMessage(5, { transfer: undefined }); 93 port1.postMessage(6, { transfer: [] }); 94 95 const err = { 96 constructor: TypeError, 97 code: 'ERR_INVALID_ARG_TYPE', 98 message: 'Optional transferList argument must be an iterable' 99 }; 100 101 assert.throws(() => port1.postMessage(5, 0), err); 102 assert.throws(() => port1.postMessage(5, false), err); 103 assert.throws(() => port1.postMessage(5, 'X'), err); 104 assert.throws(() => port1.postMessage(5, Symbol('X')), err); 105 106 const err2 = { 107 constructor: TypeError, 108 code: 'ERR_INVALID_ARG_TYPE', 109 message: 'Optional options.transfer argument must be an iterable' 110 }; 111 112 assert.throws(() => port1.postMessage(5, { transfer: null }), err2); 113 assert.throws(() => port1.postMessage(5, { transfer: 0 }), err2); 114 assert.throws(() => port1.postMessage(5, { transfer: false }), err2); 115 assert.throws(() => port1.postMessage(5, { transfer: {} }), err2); 116 assert.throws(() => port1.postMessage(5, { 117 transfer: { [Symbol.iterator]() { return {}; } } 118 }), err2); 119 assert.throws(() => port1.postMessage(5, { 120 transfer: { [Symbol.iterator]() { return { next: 42 }; } } 121 }), err2); 122 assert.throws(() => port1.postMessage(5, { 123 transfer: { [Symbol.iterator]() { return { next: null }; } } 124 }), err2); 125 port1.close(); 126} 127 128{ 129 // Make sure these ArrayBuffers end up detached, i.e. are actually being 130 // transferred because the transfer list provides them. 131 const { port1, port2 } = new MessageChannel(); 132 port2.on('message', common.mustCall((msg) => { 133 assert.strictEqual(msg.ab.byteLength, 10); 134 }, 4)); 135 136 { 137 const ab = new ArrayBuffer(10); 138 port1.postMessage({ ab }, [ ab ]); 139 assert.strictEqual(ab.byteLength, 0); 140 } 141 142 { 143 const ab = new ArrayBuffer(10); 144 port1.postMessage({ ab }, { transfer: [ ab ] }); 145 assert.strictEqual(ab.byteLength, 0); 146 } 147 148 { 149 const ab = new ArrayBuffer(10); 150 port1.postMessage({ ab }, (function*() { yield ab; })()); 151 assert.strictEqual(ab.byteLength, 0); 152 } 153 154 { 155 const ab = new ArrayBuffer(10); 156 port1.postMessage({ ab }, { 157 transfer: (function*() { yield ab; })() 158 }); 159 assert.strictEqual(ab.byteLength, 0); 160 } 161 162 port1.close(); 163} 164 165{ 166 // Test MessageEvent#ports 167 const c1 = new MessageChannel(); 168 const c2 = new MessageChannel(); 169 c1.port1.postMessage({ port: c2.port2 }, [ c2.port2 ]); 170 c1.port2.addEventListener('message', common.mustCall((ev) => { 171 assert.strictEqual(ev.ports.length, 1); 172 assert.strictEqual(ev.ports[0].constructor, MessagePort); 173 c1.port1.close(); 174 c2.port1.close(); 175 })); 176} 177 178{ 179 assert.deepStrictEqual( 180 Object.getOwnPropertyNames(MessagePort.prototype).sort(), 181 [ 182 'close', 'constructor', 'hasRef', 'onmessage', 'onmessageerror', 183 'postMessage', 'ref', 'start', 'unref', 184 ]); 185} 186