• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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    port2.close(common.mustCall());
38  });
39
40  port1.postMessage(2);
41
42  port2.onmessage = common.mustCall((message) => {
43    port2.postMessage(message.data * 2);
44  });
45}
46
47{
48  const { port1, port2 } = new MessageChannel();
49
50  const input = { a: 1 };
51  port1.postMessage(input);
52  // Check that the message still gets delivered if `port2` has its
53  // `on('message')` handler attached at a later point in time.
54  setImmediate(() => {
55    port2.on('message', common.mustCall((received) => {
56      assert.deepStrictEqual(received, input);
57      port2.close(common.mustCall());
58    }));
59  });
60}
61
62{
63  const { port1, port2 } = new MessageChannel();
64
65  const input = { a: 1 };
66
67  const dummy = common.mustNotCall();
68  // Check that the message still gets delivered if `port2` has its
69  // `on('message')` handler attached at a later point in time, even if a
70  // listener was removed previously.
71  port2.addListener('message', dummy);
72  setImmediate(() => {
73    port2.removeListener('message', dummy);
74    port1.postMessage(input);
75    setImmediate(() => {
76      port2.on('message', common.mustCall((received) => {
77        assert.deepStrictEqual(received, input);
78        port2.close(common.mustCall());
79      }));
80    });
81  });
82}
83
84{
85  const { port1, port2 } = new MessageChannel();
86  port2.on('message', common.mustCall(6));
87  port1.postMessage(1, null);
88  port1.postMessage(2, undefined);
89  port1.postMessage(3, []);
90  port1.postMessage(4, {});
91  port1.postMessage(5, { transfer: undefined });
92  port1.postMessage(6, { transfer: [] });
93
94  const err = {
95    constructor: TypeError,
96    code: 'ERR_INVALID_ARG_TYPE',
97    message: 'Optional transferList argument must be an iterable'
98  };
99
100  assert.throws(() => port1.postMessage(5, 0), err);
101  assert.throws(() => port1.postMessage(5, false), err);
102  assert.throws(() => port1.postMessage(5, 'X'), err);
103  assert.throws(() => port1.postMessage(5, Symbol('X')), err);
104
105  const err2 = {
106    constructor: TypeError,
107    code: 'ERR_INVALID_ARG_TYPE',
108    message: 'Optional options.transfer argument must be an iterable'
109  };
110
111  assert.throws(() => port1.postMessage(5, { transfer: null }), err2);
112  assert.throws(() => port1.postMessage(5, { transfer: 0 }), err2);
113  assert.throws(() => port1.postMessage(5, { transfer: false }), err2);
114  assert.throws(() => port1.postMessage(5, { transfer: {} }), err2);
115  assert.throws(() => port1.postMessage(5, {
116    transfer: { [Symbol.iterator]() { return {}; } }
117  }), err2);
118  assert.throws(() => port1.postMessage(5, {
119    transfer: { [Symbol.iterator]() { return { next: 42 }; } }
120  }), err2);
121  assert.throws(() => port1.postMessage(5, {
122    transfer: { [Symbol.iterator]() { return { next: null }; } }
123  }), err2);
124  port1.close();
125}
126
127{
128  // Make sure these ArrayBuffers end up detached, i.e. are actually being
129  // transferred because the transfer list provides them.
130  const { port1, port2 } = new MessageChannel();
131  port2.on('message', common.mustCall((msg) => {
132    assert.strictEqual(msg.ab.byteLength, 10);
133  }, 4));
134
135  {
136    const ab = new ArrayBuffer(10);
137    port1.postMessage({ ab }, [ ab ]);
138    assert.strictEqual(ab.byteLength, 0);
139  }
140
141  {
142    const ab = new ArrayBuffer(10);
143    port1.postMessage({ ab }, { transfer: [ ab ] });
144    assert.strictEqual(ab.byteLength, 0);
145  }
146
147  {
148    const ab = new ArrayBuffer(10);
149    port1.postMessage({ ab }, (function*() { yield ab; })());
150    assert.strictEqual(ab.byteLength, 0);
151  }
152
153  {
154    const ab = new ArrayBuffer(10);
155    port1.postMessage({ ab }, {
156      transfer: (function*() { yield ab; })()
157    });
158    assert.strictEqual(ab.byteLength, 0);
159  }
160
161  port1.close();
162}
163
164{
165  assert.deepStrictEqual(
166    Object.getOwnPropertyNames(MessagePort.prototype).sort(),
167    [
168      'close', 'constructor', 'onmessage', 'onmessageerror', 'postMessage',
169      'ref', 'start', 'unref',
170    ]);
171}
172