node/test/parallel/test-worker-message-port.js

186 lines
5.2 KiB
JavaScript

'use strict';
const common = require('../common');
const assert = require('assert');
const { MessageChannel, MessagePort } = require('worker_threads');
{
const { port1, port2 } = new MessageChannel();
assert(port1 instanceof MessagePort);
assert(port2 instanceof MessagePort);
const input = { a: 1 };
port1.postMessage(input);
port2.on('message', common.mustCall((received) => {
assert.deepStrictEqual(received, input);
port2.close(common.mustCall());
}));
}
{
// Test emitting non-message events on a port
const { port2 } = new MessageChannel();
port2.addEventListener('foo', common.mustCall((received) => {
assert.strictEqual(received.type, 'foo');
assert.strictEqual(received.detail, 'bar');
}));
port2.on('foo', common.mustCall((received) => {
assert.strictEqual(received, 'bar');
}));
port2.emit('foo', 'bar');
}
{
const { port1, port2 } = new MessageChannel();
port1.onmessage = common.mustCall((message) => {
assert.strictEqual(message.data, 4);
assert.strictEqual(message.target, port1);
assert.deepStrictEqual(message.ports, []);
port2.close(common.mustCall());
});
port1.postMessage(2);
port2.onmessage = common.mustCall((message) => {
port2.postMessage(message.data * 2);
});
}
{
const { port1, port2 } = new MessageChannel();
const input = { a: 1 };
port1.postMessage(input);
// Check that the message still gets delivered if `port2` has its
// `on('message')` handler attached at a later point in time.
setImmediate(() => {
port2.on('message', common.mustCall((received) => {
assert.deepStrictEqual(received, input);
port2.close(common.mustCall());
}));
});
}
{
const { port1, port2 } = new MessageChannel();
const input = { a: 1 };
const dummy = common.mustNotCall();
// Check that the message still gets delivered if `port2` has its
// `on('message')` handler attached at a later point in time, even if a
// listener was removed previously.
port2.addListener('message', dummy);
setImmediate(() => {
port2.removeListener('message', dummy);
port1.postMessage(input);
setImmediate(() => {
port2.on('message', common.mustCall((received) => {
assert.deepStrictEqual(received, input);
port2.close(common.mustCall());
}));
});
});
}
{
const { port1, port2 } = new MessageChannel();
port2.on('message', common.mustCall(6));
port1.postMessage(1, null);
port1.postMessage(2, undefined);
port1.postMessage(3, []);
port1.postMessage(4, {});
port1.postMessage(5, { transfer: undefined });
port1.postMessage(6, { transfer: [] });
const err = {
constructor: TypeError,
code: 'ERR_INVALID_ARG_TYPE',
message: 'Optional transferList argument must be an iterable'
};
assert.throws(() => port1.postMessage(5, 0), err);
assert.throws(() => port1.postMessage(5, false), err);
assert.throws(() => port1.postMessage(5, 'X'), err);
assert.throws(() => port1.postMessage(5, Symbol('X')), err);
const err2 = {
constructor: TypeError,
code: 'ERR_INVALID_ARG_TYPE',
message: 'Optional options.transfer argument must be an iterable'
};
assert.throws(() => port1.postMessage(5, { transfer: null }), err2);
assert.throws(() => port1.postMessage(5, { transfer: 0 }), err2);
assert.throws(() => port1.postMessage(5, { transfer: false }), err2);
assert.throws(() => port1.postMessage(5, { transfer: {} }), err2);
assert.throws(() => port1.postMessage(5, {
transfer: { [Symbol.iterator]() { return {}; } }
}), err2);
assert.throws(() => port1.postMessage(5, {
transfer: { [Symbol.iterator]() { return { next: 42 }; } }
}), err2);
assert.throws(() => port1.postMessage(5, {
transfer: { [Symbol.iterator]() { return { next: null }; } }
}), err2);
port1.close();
}
{
// Make sure these ArrayBuffers end up detached, i.e. are actually being
// transferred because the transfer list provides them.
const { port1, port2 } = new MessageChannel();
port2.on('message', common.mustCall((msg) => {
assert.strictEqual(msg.ab.byteLength, 10);
}, 4));
{
const ab = new ArrayBuffer(10);
port1.postMessage({ ab }, [ ab ]);
assert.strictEqual(ab.byteLength, 0);
}
{
const ab = new ArrayBuffer(10);
port1.postMessage({ ab }, { transfer: [ ab ] });
assert.strictEqual(ab.byteLength, 0);
}
{
const ab = new ArrayBuffer(10);
port1.postMessage({ ab }, (function*() { yield ab; })());
assert.strictEqual(ab.byteLength, 0);
}
{
const ab = new ArrayBuffer(10);
port1.postMessage({ ab }, {
transfer: (function*() { yield ab; })()
});
assert.strictEqual(ab.byteLength, 0);
}
port1.close();
}
{
// Test MessageEvent#ports
const c1 = new MessageChannel();
const c2 = new MessageChannel();
c1.port1.postMessage({ port: c2.port2 }, [ c2.port2 ]);
c1.port2.addEventListener('message', common.mustCall((ev) => {
assert.strictEqual(ev.ports.length, 1);
assert.strictEqual(ev.ports[0].constructor, MessagePort);
c1.port1.close();
c2.port1.close();
}));
}
{
assert.deepStrictEqual(
Object.getOwnPropertyNames(MessagePort.prototype).sort(),
[
'close', 'constructor', 'hasRef', 'onmessage', 'onmessageerror',
'postMessage', 'ref', 'start', 'unref',
]);
}