File
Blob: src/workerd/api/tests/messageport-test.js
| 1 | // Copyright (c) 2025 Cloudflare, Inc. |
| 2 | // Licensed under the Apache 2.0 license found in the LICENSE file or at: |
| 3 | // https://opensource.org/licenses/Apache-2.0 |
| 4 | import { ok, strictEqual, throws } from 'node:assert'; |
| 5 | |
| 6 | import { mock } from 'node:test'; |
| 7 | |
| 8 | export const simple1 = { |
| 9 | async test() { |
| 10 | const { port1, port2 } = new MessageChannel(); |
| 11 | ok(port1 instanceof MessagePort); |
| 12 | ok(port2 instanceof MessagePort); |
| 13 | port1.postMessage(1); |
| 14 | port2.postMessage(1); |
| 15 | const { promise, resolve } = Promise.withResolvers(); |
| 16 | const handler = mock.fn((event) => { |
| 17 | strictEqual(event.data, 1); |
| 18 | strictEqual(event.isTrusted, true); |
| 19 | resolve(); |
| 20 | }); |
| 21 | port2.onmessage = handler; |
| 22 | port1.onmessage = handler; |
| 23 | await promise; |
| 24 | strictEqual(handler.mock.callCount(), 2); |
| 25 | }, |
| 26 | }; |
| 27 | |
| 28 | export const simple2 = { |
| 29 | async test() { |
| 30 | const { port1, port2 } = new MessageChannel(); |
| 31 | ok(port1 instanceof MessagePort); |
| 32 | ok(port2 instanceof MessagePort); |
| 33 | const { promise, resolve } = Promise.withResolvers(); |
| 34 | const handler = mock.fn((event) => { |
| 35 | strictEqual(event.data, 1); |
| 36 | resolve(); |
| 37 | }); |
| 38 | port2.onmessage = handler; |
| 39 | port1.onmessage = handler; |
| 40 | port1.postMessage(1); |
| 41 | port2.postMessage(1); |
| 42 | await promise; |
| 43 | strictEqual(handler.mock.callCount(), 2); |
| 44 | }, |
| 45 | }; |
| 46 | |
| 47 | export const simple3 = { |
| 48 | async test() { |
| 49 | const { port1, port2 } = new MessageChannel(); |
| 50 | |
| 51 | const closeHandler = mock.fn(); |
| 52 | port1.onclose = closeHandler; |
| 53 | port2.onclose = closeHandler; |
| 54 | |
| 55 | port1.close(); |
| 56 | port2.onmessage = () => { |
| 57 | throw new Error('should not be called'); |
| 58 | }; |
| 59 | port1.postMessage('nope'); |
| 60 | await scheduler.wait(10); |
| 61 | strictEqual(closeHandler.mock.callCount(), 2); |
| 62 | }, |
| 63 | }; |
| 64 | |
| 65 | export const simple4 = { |
| 66 | async test() { |
| 67 | const { port1, port2 } = new MessageChannel(); |
| 68 | port2.close(); |
| 69 | port2.onmessage = () => { |
| 70 | throw new Error('should not be called'); |
| 71 | }; |
| 72 | port1.onmessage = () => { |
| 73 | throw new Error('should not be called'); |
| 74 | }; |
| 75 | port1.postMessage('nope'); |
| 76 | port2.postMessage('nope'); |
| 77 | await scheduler.wait(10); |
| 78 | }, |
| 79 | }; |
| 80 | |
| 81 | export const simple5 = { |
| 82 | async test() { |
| 83 | const { port1, port2 } = new MessageChannel(); |
| 84 | throws(() => port1.postMessage(1, [1]), { |
| 85 | message: 'Transfer list is not supported', |
| 86 | }); |
| 87 | throws(() => port1.postMessage(1, { transfer: [1] }), { |
| 88 | message: 'Transfer list is not supported', |
| 89 | }); |
| 90 | // If the lists are empty it is ok. |
| 91 | port1.postMessage(1, []); |
| 92 | port1.postMessage(1, { transfer: [] }); |
| 93 | |
| 94 | const handler = mock.fn((event) => { |
| 95 | strictEqual(event.data, 1); |
| 96 | }); |
| 97 | port2.onmessage = handler; |
| 98 | await scheduler.wait(10); |
| 99 | strictEqual(handler.mock.callCount(), 2); |
| 100 | }, |
| 101 | }; |
| 102 | |
| 103 | // The following are a selected subset of web platform tests for MessageChannel and MessagePort |
| 104 | // that we know we pass. We don't support the full MessagePort spec so we're not going to run |
| 105 | // the full WPT's for these yet. |
| 106 | // Refs: https://github.com/web-platform-tests/wpt/blob/master/webmessaging/Channel_postMessage_Blob.any.js |
| 107 | // Refs: https://github.com/web-platform-tests/wpt/blob/master/webmessaging/Channel_postMessage_DataCloneErr.any.js |
| 108 | |
| 109 | export const postMessageBlob = { |
| 110 | test() { |
| 111 | // Per the spec, Blob is a serializable object, but we don't implement it as such currently. |
| 112 | // So attempting to post a blob should throw an error. |
| 113 | const { port1 } = new MessageChannel(); |
| 114 | throws(() => port1.postMessage(new Blob([''])), { |
| 115 | code: 25, // DATA_CLONE_ERR, |
| 116 | name: 'DataCloneError', |
| 117 | message: /Could not serialize/, |
| 118 | }); |
| 119 | }, |
| 120 | }; |
| 121 | |
| 122 | export const postMessageRpcTarget = { |
| 123 | async test() { |
| 124 | const { RpcTarget } = await import('cloudflare:workers'); |
| 125 | class Foo extends RpcTarget {} |
| 126 | |
| 127 | const { port1 } = new MessageChannel(); |
| 128 | throws(() => port1.postMessage(new Foo()), { |
| 129 | code: 25, // DATA_CLONE_ERR, |
| 130 | name: 'DataCloneError', |
| 131 | }); |
| 132 | }, |
| 133 | }; |
| 134 | |
| 135 | // Subset of the Web Platform Tests we know we don't pass, listed for future reference: |
| 136 | // Most the web messaging WPT's are set up to require a full implementation of MessagePort |
| 137 | // with web workers and most of the tests are in html files. We'll come back to these |
| 138 | // later. |
| 139 | // * https://github.com/web-platform-tests/wpt/blob/master/webmessaging/Channel_postMessage_clone_port.any.js |
| 140 | // * https://github.com/web-platform-tests/wpt/blob/master/webmessaging/Channel_postMessage_clone_port_error.any.js |
| 141 | // * https://github.com/web-platform-tests/wpt/blob/master/webmessaging/Channel_postMessage_ports_readonly_array.any.js |
| 142 | // * https://github.com/web-platform-tests/wpt/blob/master/webmessaging/Channel_postMessage_transfer_xsite_incoming_messages.window.js |
| 143 | // * https://github.com/web-platform-tests/wpt/blob/master/webmessaging/Channel_postMessage_transfer_xsite_incoming_messages.window.js |
| 144 | // * https://github.com/web-platform-tests/wpt/blob/master/webmessaging/Channel_postMessage_with_transfer_incoming_messages.any.js |
| 145 | // * https://github.com/web-platform-tests/wpt/blob/master/webmessaging/Channel_postMessage_with_transfer_outgoing_messages.any.js |
| 146 | |
| 147 | // This one is a bit special, per the spec we're supposed to fire off the close event |
| 148 | // on an entangled port when the other port is garbage collected. We don't do that yet |
| 149 | // and we might not ever. Need to investigate this further but it's not blocking us |
| 150 | // right now. |
| 151 | // * https://github.com/web-platform-tests/wpt/blob/master/webmessaging/message-channels/close-event/garbage-collected.tentative.any.js |