• 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    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