Skip to content
File

Blob: src/wpt/websockets-test.ts

typescript373 lines
1// Copyright (c) 2017-2026 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 
5import { type TestRunnerConfig } from 'harness/harness';
6 
7// The WPT WebSocket tests use addEventListener with useCapture=true, which workerd
8// doesn't support. This function removes the useCapture argument from those calls.
9// Pattern: addEventListener('event', handler, true) -> addEventListener('event', handler)
10function removeUseCapture(code: string): string {
11 return code.replace(/,\s*true\s*\)/g, ')');
12}
13 
14export default {
15 'Close-1000-reason.any.js': {
16 replace: removeUseCapture,
17 },
18 'Close-1000-verify-code.any.js': {
19 replace: removeUseCapture,
20 },
21 'Close-1000.any.js': {
22 replace: removeUseCapture,
23 },
24 'Close-1005-verify-code.any.js': {
25 replace: removeUseCapture,
26 },
27 'Close-1005.any.js': {
28 replace: (code: string): string => {
29 code = removeUseCapture(code);
30 // The test expects close(1005) to throw, leaving the WebSocket open.
31 // In workerd, the open connection's read loop is registered as a
32 // waitUntil task that keeps the IoContext alive indefinitely.
33 // Add a cleanup to close the WebSocket when the test completes so the
34 // connection is properly shut down.
35 return code.replace(
36 'var isOpenCalled = false;',
37 'var isOpenCalled = false;\ntest.add_cleanup(function() { wsocket.close(); });'
38 );
39 },
40 },
41 'Close-2999-reason.any.js': {
42 replace: (code: string): string => {
43 code = removeUseCapture(code);
44 // The test expects close(2999) to throw, leaving the WebSocket open.
45 // Add a cleanup to close the WebSocket when the test completes so the
46 // connection is properly shut down.
47 return code.replace(
48 'var wsocket = CreateWebSocket(false, false);',
49 'var wsocket = CreateWebSocket(false, false);\ntest.add_cleanup(function() { wsocket.close(); });'
50 );
51 },
52 },
53 'Close-3000-reason.any.js': {
54 replace: removeUseCapture,
55 },
56 'Close-3000-verify-code.any.js': {
57 replace: removeUseCapture,
58 },
59 'Close-4999-reason.any.js': {
60 replace: removeUseCapture,
61 },
62 'Close-Reason-124Bytes.any.js': {
63 replace: (code: string): string => {
64 code = removeUseCapture(code);
65 // The test expects close(1000, longReason) to throw SYNTAX_ERR, leaving
66 // the WebSocket still open. Add a cleanup to close the WebSocket when the
67 // test completes so the connection is properly shut down.
68 return code.replace(
69 'var isOpenCalled = false;',
70 'var isOpenCalled = false;\ntest.add_cleanup(function() { wsocket.close(); });'
71 );
72 },
73 },
74 'Close-delayed.any.js': {
75 replace: removeUseCapture,
76 },
77 'Close-onlyReason.any.js': {
78 replace: (code: string): string => {
79 code = removeUseCapture(code);
80 // The test expects close("reason") to throw, leaving the WebSocket open.
81 // Add a cleanup to close the WebSocket when the test completes so the
82 // connection is properly shut down.
83 return code.replace(
84 'var wsocket = CreateWebSocket(false, false);',
85 'var wsocket = CreateWebSocket(false, false);\ntest.add_cleanup(function() { wsocket.close(); });'
86 );
87 },
88 },
89 'Close-readyState-Closed.any.js': {
90 replace: removeUseCapture,
91 },
92 'Close-readyState-Closing.any.js': {
93 replace: removeUseCapture,
94 },
95 'Close-reason-unpaired-surrogates.any.js': {
96 replace: removeUseCapture,
97 },
98 'Close-server-initiated-close.any.js': {
99 replace: removeUseCapture,
100 },
101 'Close-undefined.any.js': {
102 replace: removeUseCapture,
103 },
104 'Create-asciiSep-protocol-string.any.js': {},
105 'Create-blocked-port.any.js': {
106 comment: 'Port blocking works differently in workerd',
107 disabledTests: true,
108 },
109 'Create-extensions-empty.any.js': {
110 comment: 'workerd WebSocket.extensions is null instead of empty string',
111 expectedFailures: [
112 "Create WebSocket - wsocket.extensions should be set to '' after connection is established - Connection should be closed",
113 ],
114 replace: removeUseCapture,
115 },
116 'Create-http-urls.any.js': {
117 comment: 'workerd requires ws/wss scheme, not http/https',
118 expectedFailures: ['WebSocket: ensure both HTTP schemes are supported'],
119 },
120 'Create-invalid-urls.any.js': {},
121 'Create-non-absolute-url.any.js': {
122 comment: 'workerd throws SyntaxError for non-absolute URLs',
123 expectedFailures: [
124 'Create WebSocket - Pass a non absolute URL: test',
125 'Create WebSocket - Pass a non absolute URL: ?',
126 'Create WebSocket - Pass a non absolute URL: null',
127 'Create WebSocket - Pass a non absolute URL: 123',
128 ],
129 },
130 'Create-nonAscii-protocol-string.any.js': {},
131 'Create-on-worker-shutdown.any.js': {
132 comment: 'Worker shutdown behavior is different in workerd',
133 disabledTests: true,
134 },
135 'Create-protocol-with-space.any.js': {},
136 'Create-protocols-repeated-case-insensitive.any.js': {
137 comment:
138 'workerd does not throw for case-insensitive duplicate protocols (allows "Echo" and "echo")',
139 expectedFailures: [
140 'Create WebSocket - Pass a valid URL and an array of protocol strings with repeated values but different case - SYNTAX_ERR is thrown',
141 ],
142 },
143 'Create-protocols-repeated.any.js': {},
144 'Create-url-with-space.any.js': {},
145 'Create-valid-url-array-protocols.any.js': {
146 replace: removeUseCapture,
147 },
148 'Create-valid-url-binaryType-blob.any.js': {
149 replace: removeUseCapture,
150 },
151 'Create-valid-url-protocol-empty.any.js': {
152 replace: removeUseCapture,
153 },
154 'Create-valid-url-protocol-setCorrectly.any.js': {
155 replace: removeUseCapture,
156 },
157 'Create-valid-url-protocol-string.any.js': {
158 replace: removeUseCapture,
159 },
160 'Create-valid-url-protocol.any.js': {
161 replace: removeUseCapture,
162 },
163 'Create-valid-url.any.js': {
164 replace: removeUseCapture,
165 },
166 'Send-0byte-data.any.js': {
167 comment:
168 'workerd returns 0 instead of undefined for empty message data; test hangs',
169 disabledTests: true,
170 },
171 'Send-65K-data.any.js': {
172 comment:
173 'workerd returns byte count instead of undefined for bufferedAmount; test hangs',
174 disabledTests: true,
175 },
176 'Send-before-open.any.js': {
177 comment:
178 'workerd throws TypeError instead of InvalidStateError DOMException for send() before open',
179 expectedFailures: [
180 'Send data on a WebSocket before connection is opened - INVALID_STATE_ERR is returned',
181 ],
182 },
183 // The following Send tests all check bufferedAmount which returns byte count in workerd
184 // instead of undefined as expected by the spec. They also hang after failures.
185 'Send-binary-65K-arraybuffer.any.js': {
186 comment:
187 'bufferedAmount returns byte count instead of undefined; test hangs',
188 disabledTests: true,
189 },
190 'Send-binary-arraybuffer.any.js': {
191 comment:
192 'bufferedAmount returns byte count instead of undefined; test hangs',
193 disabledTests: true,
194 },
195 'Send-binary-arraybufferview-float16.any.js': {
196 comment:
197 'bufferedAmount returns byte count instead of undefined; test hangs',
198 disabledTests: true,
199 },
200 'Send-binary-arraybufferview-float32.any.js': {
201 comment:
202 'bufferedAmount returns byte count instead of undefined; test hangs',
203 disabledTests: true,
204 },
205 'Send-binary-arraybufferview-float64.any.js': {
206 comment:
207 'bufferedAmount returns byte count instead of undefined; test hangs',
208 disabledTests: true,
209 },
210 'Send-binary-arraybufferview-int16-offset.any.js': {
211 comment:
212 'bufferedAmount returns byte count instead of undefined; test hangs',
213 disabledTests: true,
214 },
215 'Send-binary-arraybufferview-int32.any.js': {
216 comment:
217 'bufferedAmount returns byte count instead of undefined; test hangs',
218 disabledTests: true,
219 },
220 'Send-binary-arraybufferview-int8.any.js': {
221 comment:
222 'bufferedAmount returns byte count instead of undefined; test hangs',
223 disabledTests: true,
224 },
225 'Send-binary-arraybufferview-uint16-offset-length.any.js': {
226 comment:
227 'bufferedAmount returns byte count instead of undefined; test hangs',
228 disabledTests: true,
229 },
230 'Send-binary-arraybufferview-uint32-offset.any.js': {
231 comment:
232 'bufferedAmount returns byte count instead of undefined; test hangs',
233 disabledTests: true,
234 },
235 'Send-binary-arraybufferview-uint8-offset-length.any.js': {
236 comment:
237 'bufferedAmount returns byte count instead of undefined; test hangs',
238 disabledTests: true,
239 },
240 'Send-binary-arraybufferview-uint8-offset.any.js': {
241 comment:
242 'bufferedAmount returns byte count instead of undefined; test hangs',
243 disabledTests: true,
244 },
245 'Send-binary-blob.any.js': {
246 comment:
247 'bufferedAmount returns byte count instead of undefined; test hangs',
248 disabledTests: true,
249 },
250 'Send-data.any.js': {
251 comment:
252 'bufferedAmount returns byte count instead of undefined; test hangs',
253 disabledTests: true,
254 },
255 'Send-data.worker.js': {
256 comment:
257 'bufferedAmount returns byte count instead of undefined; test hangs',
258 disabledTests: true,
259 },
260 'Send-null.any.js': {
261 comment:
262 'bufferedAmount returns byte count instead of undefined; test hangs',
263 disabledTests: true,
264 },
265 'Send-paired-surrogates.any.js': {
266 comment:
267 'bufferedAmount returns byte count instead of undefined; test hangs',
268 disabledTests: true,
269 },
270 'Send-unicode-data.any.js': {
271 comment:
272 'bufferedAmount returns byte count instead of undefined; test hangs',
273 disabledTests: true,
274 },
275 'Send-unpaired-surrogates.any.js': {
276 comment:
277 'bufferedAmount returns byte count instead of undefined; test hangs',
278 disabledTests: true,
279 },
280 'back-forward-cache-with-closed-websocket-connection.window.js': {
281 comment: 'Back/forward cache tests are browser-specific',
282 omittedTests: true,
283 },
284 'back-forward-cache-with-open-websocket-connection-and-close-it-in-pagehide.window.js':
285 {
286 comment: 'Back/forward cache tests are browser-specific',
287 omittedTests: true,
288 },
289 'back-forward-cache-with-open-websocket-connection.window.js': {
290 comment: 'Back/forward cache tests are browser-specific',
291 omittedTests: true,
292 },
293 'basic-auth.any.js': {
294 comment: 'Basic authentication for WebSockets is not supported',
295 disabledTests: true,
296 },
297 'binaryType-wrong-value.any.js': {
298 replace: removeUseCapture,
299 },
300 'bufferedAmount-unchanged-by-sync-xhr.any.js': {
301 comment: 'Synchronous XHR is not supported in Workers',
302 omittedTests: true,
303 },
304 'close-invalid.any.js': {
305 replace: removeUseCapture,
306 },
307 'constants.sub.js': {},
308 'constructor.any.js': {},
309 'cookies/support/websocket-cookies-helper.sub.js': {
310 comment: 'Cookie support helper, not an actual test',
311 omittedTests: true,
312 },
313 'eventhandlers.any.js': {
314 comment: 'TreatNonCallableAsNull behavior differs from spec',
315 expectedFailures: [
316 'Event handler for open should have [TreatNonCallableAsNull]',
317 'Event handler for error should have [TreatNonCallableAsNull]',
318 'Event handler for close should have [TreatNonCallableAsNull]',
319 'Event handler for message should have [TreatNonCallableAsNull]',
320 ],
321 },
322 'idlharness.any.js': {
323 comment:
324 'Some interface/attribute tests still fail due to event handler and inherited property checks',
325 expectedFailures: [
326 'WebSocket interface: existence and properties of interface object',
327 'WebSocket interface: attribute bufferedAmount',
328 'WebSocket interface: attribute onopen',
329 'WebSocket interface: attribute onerror',
330 'WebSocket interface: attribute onclose',
331 'WebSocket interface: attribute onmessage',
332 'WebSocket interface: new WebSocket("ws://invalid") must inherit property "bufferedAmount" with the proper type',
333 'WebSocket interface: new WebSocket("ws://invalid") must inherit property "onopen" with the proper type',
334 'WebSocket interface: new WebSocket("ws://invalid") must inherit property "onerror" with the proper type',
335 'WebSocket interface: new WebSocket("ws://invalid") must inherit property "onclose" with the proper type',
336 'WebSocket interface: new WebSocket("ws://invalid") must inherit property "onmessage" with the proper type',
337 'CloseEvent interface: existence and properties of interface object',
338 'CloseEvent interface: attribute wasClean',
339 'CloseEvent interface: attribute code',
340 'CloseEvent interface: attribute reason',
341 'CloseEvent interface: new CloseEvent("close") must inherit property "wasClean" with the proper type',
342 'CloseEvent interface: new CloseEvent("close") must inherit property "code" with the proper type',
343 'CloseEvent interface: new CloseEvent("close") must inherit property "reason" with the proper type',
344 ],
345 },
346 'interfaces/WebSocket/close/close-connecting-async.any.js': {
347 comment:
348 'readyState is CONNECTING (1) instead of CLOSING (2) after close()',
349 expectedFailures: [
350 'close event should be fired asynchronously when WebSocket is connecting',
351 ],
352 },
353 'mixed-content.https.any.js': {
354 comment: 'Mixed content checks are browser-specific',
355 omittedTests: true,
356 },
357 'opening-handshake/003-sets-origin.worker.js': {
358 comment: 'importScripts is not available in Workers',
359 omittedTests: true,
360 },
361 'referrer.any.js': {
362 comment: 'Referrer behavior is different in workers',
363 disabledTests: true,
364 },
365 'remove-own-iframe-during-onerror.window.js': {
366 comment: 'iframe tests are browser-specific',
367 omittedTests: true,
368 },
369 'send-many-64K-messages-with-backpressure.any.js': {
370 replace: removeUseCapture,
371 },
372} satisfies TestRunnerConfig;