File
Blob: src/workerd/api/node/tests/url-nodejs-test.js
| 1 | // Copyright (c) 2017-2022 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 | // |
| 5 | // Adapted from Node.js. Copyright Joyent, Inc. and other Node contributors. |
| 6 | // |
| 7 | // Permission is hereby granted, free of charge, to any person obtaining a |
| 8 | // copy of this software and associated documentation files (the |
| 9 | // "Software"), to deal in the Software without restriction, including |
| 10 | // without limitation the rights to use, copy, modify, merge, publish, |
| 11 | // distribute, sublicense, and/or sell copies of the Software, and to permit |
| 12 | // persons to whom the Software is furnished to do so, subject to the |
| 13 | // following conditions: |
| 14 | // |
| 15 | // The above copyright notice and this permission notice shall be included |
| 16 | // in all copies or substantial portions of the Software. |
| 17 | // |
| 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| 19 | // OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF |
| 20 | // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN |
| 21 | // NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, |
| 22 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR |
| 23 | // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE |
| 24 | // USE OR OTHER DEALINGS IN THE SOFTWARE. |
| 25 | |
| 26 | import { |
| 27 | strictEqual, |
| 28 | throws, |
| 29 | ok as assert, |
| 30 | match, |
| 31 | deepStrictEqual, |
| 32 | } from 'node:assert'; |
| 33 | import { |
| 34 | domainToASCII, |
| 35 | domainToUnicode, |
| 36 | URL as URLImpl, |
| 37 | URLSearchParams as URLSearchParamsImpl, |
| 38 | fileURLToPath, |
| 39 | pathToFileURL, |
| 40 | } from 'node:url'; |
| 41 | |
| 42 | // Tests are taken from: |
| 43 | // https://github.com/nodejs/node/blob/321a14b36d6b3304aedfd183e12ddba35dc704bd/test/parallel/test-url-domain-ascii-unicode.js |
| 44 | export const testDomainAsciiUnicode = { |
| 45 | test() { |
| 46 | const domainWithASCII = [ |
| 47 | ['ıíd', 'xn--d-iga7r'], |
| 48 | ['يٴ', 'xn--mhb8f'], |
| 49 | ['www.ϧƽəʐ.com', 'www.xn--cja62apfr6c.com'], |
| 50 | ['новини.com', 'xn--b1amarcd.com'], |
| 51 | ['名がドメイン.com', 'xn--v8jxj3d1dzdz08w.com'], |
| 52 | ['افغانستا.icom.museum', 'xn--mgbaal8b0b9b2b.icom.museum'], |
| 53 | ['الجزائر.icom.fake', 'xn--lgbbat1ad8j.icom.fake'], |
| 54 | ['भारत.org', 'xn--h2brj9c.org'], |
| 55 | ['aaa', 'aaa'], |
| 56 | ]; |
| 57 | |
| 58 | for (const [domain, ascii] of domainWithASCII) { |
| 59 | strictEqual(domainToASCII(domain), ascii); |
| 60 | strictEqual(domainToUnicode(ascii), domain); |
| 61 | } |
| 62 | }, |
| 63 | }; |
| 64 | |
| 65 | // Tests are taken from: |
| 66 | // https://github.com/nodejs/node/blob/321a14b36d6b3304aedfd183e12ddba35dc704bd/test/parallel/test-whatwg-url-custom-domainto.js |
| 67 | export const whatwgURLCustomDomainTo = { |
| 68 | test() { |
| 69 | { |
| 70 | const expectedError = { code: 'ERR_MISSING_ARGS', name: 'TypeError' }; |
| 71 | throws(() => domainToASCII(), expectedError); |
| 72 | throws(() => domainToUnicode(), expectedError); |
| 73 | strictEqual(domainToASCII(undefined), 'undefined'); |
| 74 | strictEqual(domainToUnicode(undefined), 'undefined'); |
| 75 | } |
| 76 | }, |
| 77 | }; |
| 78 | |
| 79 | export const urlAndSearchParams = { |
| 80 | test() { |
| 81 | assert(URLImpl, 'URL should be exported from node:url'); |
| 82 | assert( |
| 83 | URLSearchParamsImpl, |
| 84 | 'URLSearchParams should be exported by node:url' |
| 85 | ); |
| 86 | }, |
| 87 | }; |
| 88 | |
| 89 | export const getBuiltinModule = { |
| 90 | async test() { |
| 91 | const bim = process.getBuiltinModule('node:url'); |
| 92 | const url = await import('node:url'); |
| 93 | strictEqual(bim, url.default); |
| 94 | }, |
| 95 | }; |
| 96 | |
| 97 | // Ref: https://github.com/nodejs/node/blob/e92446536ed4e268c9eef6ae6f911e384c98eecf/test/parallel/test-url-fileurltopath.js |
| 98 | export const testFileURLToPath = { |
| 99 | async test() { |
| 100 | // invalid arguments |
| 101 | for (const arg of [null, undefined, 1, {}, true]) { |
| 102 | throws(() => fileURLToPath(arg), { |
| 103 | code: 'ERR_INVALID_ARG_TYPE', |
| 104 | }); |
| 105 | } |
| 106 | |
| 107 | // input must be a file URL |
| 108 | throws(() => fileURLToPath('https://a/b/c'), { |
| 109 | code: 'ERR_INVALID_URL_SCHEME', |
| 110 | }); |
| 111 | |
| 112 | { |
| 113 | // fileURLToPath with host |
| 114 | const withHost = new URL('file://host/a'); |
| 115 | |
| 116 | throws(() => fileURLToPath(withHost), { |
| 117 | code: 'ERR_INVALID_FILE_URL_HOST', |
| 118 | }); |
| 119 | } |
| 120 | |
| 121 | const windowsTestCases = [ |
| 122 | // Lowercase ascii alpha |
| 123 | { path: 'C:\\foo', fileURL: 'file:///C:/foo' }, |
| 124 | // Uppercase ascii alpha |
| 125 | { path: 'C:\\FOO', fileURL: 'file:///C:/FOO' }, |
| 126 | // dir |
| 127 | { path: 'C:\\dir\\foo', fileURL: 'file:///C:/dir/foo' }, |
| 128 | // trailing separator |
| 129 | { path: 'C:\\dir\\', fileURL: 'file:///C:/dir/' }, |
| 130 | // dot |
| 131 | { path: 'C:\\foo.mjs', fileURL: 'file:///C:/foo.mjs' }, |
| 132 | // space |
| 133 | { path: 'C:\\foo bar', fileURL: 'file:///C:/foo%20bar' }, |
| 134 | // question mark |
| 135 | { path: 'C:\\foo?bar', fileURL: 'file:///C:/foo%3Fbar' }, |
| 136 | // number sign |
| 137 | { path: 'C:\\foo#bar', fileURL: 'file:///C:/foo%23bar' }, |
| 138 | // ampersand |
| 139 | { path: 'C:\\foo&bar', fileURL: 'file:///C:/foo&bar' }, |
| 140 | // equals |
| 141 | { path: 'C:\\foo=bar', fileURL: 'file:///C:/foo=bar' }, |
| 142 | // colon |
| 143 | { path: 'C:\\foo:bar', fileURL: 'file:///C:/foo:bar' }, |
| 144 | // semicolon |
| 145 | { path: 'C:\\foo;bar', fileURL: 'file:///C:/foo;bar' }, |
| 146 | // percent |
| 147 | { path: 'C:\\foo%bar', fileURL: 'file:///C:/foo%25bar' }, |
| 148 | // backslash |
| 149 | { path: 'C:\\foo\\bar', fileURL: 'file:///C:/foo/bar' }, |
| 150 | // backspace |
| 151 | { path: 'C:\\foo\bbar', fileURL: 'file:///C:/foo%08bar' }, |
| 152 | // tab |
| 153 | { path: 'C:\\foo\tbar', fileURL: 'file:///C:/foo%09bar' }, |
| 154 | // newline |
| 155 | { path: 'C:\\foo\nbar', fileURL: 'file:///C:/foo%0Abar' }, |
| 156 | // carriage return |
| 157 | { path: 'C:\\foo\rbar', fileURL: 'file:///C:/foo%0Dbar' }, |
| 158 | // latin1 |
| 159 | { path: 'C:\\fóóbàr', fileURL: 'file:///C:/f%C3%B3%C3%B3b%C3%A0r' }, |
| 160 | // Euro sign (BMP code point) |
| 161 | { path: 'C:\\€', fileURL: 'file:///C:/%E2%82%AC' }, |
| 162 | // Rocket emoji (non-BMP code point) |
| 163 | { path: 'C:\\🚀', fileURL: 'file:///C:/%F0%9F%9A%80' }, |
| 164 | // UNC path (see https://docs.microsoft.com/en-us/archive/blogs/ie/file-uris-in-windows) |
| 165 | { |
| 166 | path: '\\\\nas\\My Docs\\File.doc', |
| 167 | fileURL: 'file://nas/My%20Docs/File.doc', |
| 168 | }, |
| 169 | ]; |
| 170 | |
| 171 | const posixTestCases = [ |
| 172 | // Lowercase ascii alpha |
| 173 | { path: '/foo', fileURL: 'file:///foo' }, |
| 174 | // Uppercase ascii alpha |
| 175 | { path: '/FOO', fileURL: 'file:///FOO' }, |
| 176 | // dir |
| 177 | { path: '/dir/foo', fileURL: 'file:///dir/foo' }, |
| 178 | // trailing separator |
| 179 | { path: '/dir/', fileURL: 'file:///dir/' }, |
| 180 | // dot |
| 181 | { path: '/foo.mjs', fileURL: 'file:///foo.mjs' }, |
| 182 | // space |
| 183 | { path: '/foo bar', fileURL: 'file:///foo%20bar' }, |
| 184 | // question mark |
| 185 | { path: '/foo?bar', fileURL: 'file:///foo%3Fbar' }, |
| 186 | // number sign |
| 187 | { path: '/foo#bar', fileURL: 'file:///foo%23bar' }, |
| 188 | // ampersand |
| 189 | { path: '/foo&bar', fileURL: 'file:///foo&bar' }, |
| 190 | // equals |
| 191 | { path: '/foo=bar', fileURL: 'file:///foo=bar' }, |
| 192 | // colon |
| 193 | { path: '/foo:bar', fileURL: 'file:///foo:bar' }, |
| 194 | // semicolon |
| 195 | { path: '/foo;bar', fileURL: 'file:///foo;bar' }, |
| 196 | // percent |
| 197 | { path: '/foo%bar', fileURL: 'file:///foo%25bar' }, |
| 198 | // backslash |
| 199 | { path: '/foo\\bar', fileURL: 'file:///foo%5Cbar' }, |
| 200 | // backspace |
| 201 | { path: '/foo\bbar', fileURL: 'file:///foo%08bar' }, |
| 202 | // tab |
| 203 | { path: '/foo\tbar', fileURL: 'file:///foo%09bar' }, |
| 204 | // newline |
| 205 | { path: '/foo\nbar', fileURL: 'file:///foo%0Abar' }, |
| 206 | // carriage return |
| 207 | { path: '/foo\rbar', fileURL: 'file:///foo%0Dbar' }, |
| 208 | // latin1 |
| 209 | { path: '/fóóbàr', fileURL: 'file:///f%C3%B3%C3%B3b%C3%A0r' }, |
| 210 | // Euro sign (BMP code point) |
| 211 | { path: '/€', fileURL: 'file:///%E2%82%AC' }, |
| 212 | // Rocket emoji (non-BMP code point) |
| 213 | { path: '/🚀', fileURL: 'file:///%F0%9F%9A%80' }, |
| 214 | ]; |
| 215 | |
| 216 | // fileURLToPath with windows path |
| 217 | for (const { path, fileURL } of windowsTestCases) { |
| 218 | const fromString = fileURLToPath(fileURL, { windows: true }); |
| 219 | strictEqual(fromString, path); |
| 220 | const fromURL = fileURLToPath(new URL(fileURL), { windows: true }); |
| 221 | strictEqual(fromURL, path); |
| 222 | } |
| 223 | |
| 224 | // fileURLToPath with posix path |
| 225 | for (const { path, fileURL } of posixTestCases) { |
| 226 | const fromString = fileURLToPath(fileURL, { windows: false }); |
| 227 | strictEqual(fromString, path); |
| 228 | const fromURL = fileURLToPath(new URL(fileURL), { windows: false }); |
| 229 | strictEqual(fromURL, path); |
| 230 | } |
| 231 | |
| 232 | { |
| 233 | // options is null |
| 234 | const whenNullActual = fileURLToPath( |
| 235 | new URL(posixTestCases[0].fileURL), |
| 236 | null |
| 237 | ); |
| 238 | strictEqual(whenNullActual, posixTestCases[0].path); |
| 239 | |
| 240 | // default test cases |
| 241 | for (const { path, fileURL } of posixTestCases) { |
| 242 | const fromString = fileURLToPath(fileURL); |
| 243 | strictEqual(fromString, path); |
| 244 | const fromURL = fileURLToPath(new URL(fileURL)); |
| 245 | strictEqual(fromURL, path); |
| 246 | } |
| 247 | } |
| 248 | }, |
| 249 | }; |
| 250 | |
| 251 | // Ref: https://github.com/nodejs/node/blob/e92446536ed4e268c9eef6ae6f911e384c98eecf/test/parallel/test-url-pathtofileurl.js |
| 252 | export const testPathToFileURL = { |
| 253 | async test() { |
| 254 | { |
| 255 | const fileURL = pathToFileURL('test/').href; |
| 256 | assert(fileURL.startsWith('file:///')); |
| 257 | assert(fileURL.endsWith('/')); |
| 258 | } |
| 259 | |
| 260 | { |
| 261 | const fileURL = pathToFileURL('test\\', { windows: false }).href; |
| 262 | assert(fileURL.startsWith('file:///')); |
| 263 | match(fileURL, /%5C$/); |
| 264 | } |
| 265 | |
| 266 | { |
| 267 | const fileURL = pathToFileURL('test\\', { windows: true }).href; |
| 268 | assert(fileURL.startsWith('file:///')); |
| 269 | match(fileURL, /\/$/); |
| 270 | } |
| 271 | |
| 272 | { |
| 273 | const fileURL = pathToFileURL('test/%').href; |
| 274 | assert(fileURL.includes('%25')); |
| 275 | } |
| 276 | |
| 277 | { |
| 278 | // UNC path: \\server\share\resource |
| 279 | // Missing server: |
| 280 | throws(() => pathToFileURL('\\\\\\no-server', { windows: true }), { |
| 281 | code: 'ERR_INVALID_ARG_VALUE', |
| 282 | }); |
| 283 | |
| 284 | // Missing share or resource: |
| 285 | throws(() => pathToFileURL('\\\\host', { windows: true }), { |
| 286 | code: 'ERR_INVALID_ARG_VALUE', |
| 287 | }); |
| 288 | |
| 289 | // Regression test for direct String.prototype.startsWith call |
| 290 | throws( |
| 291 | () => |
| 292 | pathToFileURL( |
| 293 | ['\\\\', { [Symbol.toPrimitive]: () => 'blep\\blop' }], |
| 294 | { windows: true } |
| 295 | ), |
| 296 | { |
| 297 | code: 'ERR_INVALID_ARG_TYPE', |
| 298 | } |
| 299 | ); |
| 300 | throws(() => pathToFileURL(['\\\\', 'blep\\blop'], { windows: true }), { |
| 301 | code: 'ERR_INVALID_ARG_TYPE', |
| 302 | }); |
| 303 | throws( |
| 304 | () => |
| 305 | pathToFileURL( |
| 306 | { |
| 307 | [Symbol.toPrimitive]: () => '\\\\blep\\blop', |
| 308 | }, |
| 309 | { windows: true } |
| 310 | ), |
| 311 | { |
| 312 | code: 'ERR_INVALID_ARG_TYPE', |
| 313 | } |
| 314 | ); |
| 315 | |
| 316 | // UNC paths on Posix are considered a single path that has backslashes: |
| 317 | const fileURL = pathToFileURL('\\\\nas\\share\\path.txt').href; |
| 318 | match(fileURL, /file:\/\/.+%5C%5Cnas%5Cshare%5Cpath\.txt$/); |
| 319 | } |
| 320 | |
| 321 | const windowsTestCases = [ |
| 322 | // Lowercase ascii alpha |
| 323 | { path: 'C:\\foo', expected: 'file:///C:/foo' }, |
| 324 | // Uppercase ascii alpha |
| 325 | { path: 'C:\\FOO', expected: 'file:///C:/FOO' }, |
| 326 | // dir |
| 327 | { path: 'C:\\dir\\foo', expected: 'file:///C:/dir/foo' }, |
| 328 | // trailing separator |
| 329 | { path: 'C:\\dir\\', expected: 'file:///C:/dir/' }, |
| 330 | // dot |
| 331 | { path: 'C:\\foo.mjs', expected: 'file:///C:/foo.mjs' }, |
| 332 | // space |
| 333 | { path: 'C:\\foo bar', expected: 'file:///C:/foo%20bar' }, |
| 334 | // question mark |
| 335 | { path: 'C:\\foo?bar', expected: 'file:///C:/foo%3Fbar' }, |
| 336 | // number sign |
| 337 | { path: 'C:\\foo#bar', expected: 'file:///C:/foo%23bar' }, |
| 338 | // ampersand |
| 339 | { path: 'C:\\foo&bar', expected: 'file:///C:/foo&bar' }, |
| 340 | // equals |
| 341 | { path: 'C:\\foo=bar', expected: 'file:///C:/foo=bar' }, |
| 342 | // colon |
| 343 | { path: 'C:\\foo:bar', expected: 'file:///C:/foo:bar' }, |
| 344 | // semicolon |
| 345 | { path: 'C:\\foo;bar', expected: 'file:///C:/foo;bar' }, |
| 346 | // percent |
| 347 | { path: 'C:\\foo%bar', expected: 'file:///C:/foo%25bar' }, |
| 348 | // backslash |
| 349 | { path: 'C:\\foo\\bar', expected: 'file:///C:/foo/bar' }, |
| 350 | // backspace |
| 351 | { path: 'C:\\foo\bbar', expected: 'file:///C:/foo%08bar' }, |
| 352 | // tab |
| 353 | { path: 'C:\\foo\tbar', expected: 'file:///C:/foo%09bar' }, |
| 354 | // newline |
| 355 | { path: 'C:\\foo\nbar', expected: 'file:///C:/foo%0Abar' }, |
| 356 | // carriage return |
| 357 | { path: 'C:\\foo\rbar', expected: 'file:///C:/foo%0Dbar' }, |
| 358 | // latin1 |
| 359 | { path: 'C:\\fóóbàr', expected: 'file:///C:/f%C3%B3%C3%B3b%C3%A0r' }, |
| 360 | // Euro sign (BMP code point) |
| 361 | { path: 'C:\\€', expected: 'file:///C:/%E2%82%AC' }, |
| 362 | // Rocket emoji (non-BMP code point) |
| 363 | { path: 'C:\\🚀', expected: 'file:///C:/%F0%9F%9A%80' }, |
| 364 | // caret |
| 365 | { path: 'C:\\foo^bar', expected: 'file:///C:/foo%5Ebar' }, |
| 366 | // left bracket |
| 367 | { path: 'C:\\foo[bar', expected: 'file:///C:/foo%5Bbar' }, |
| 368 | // right bracket |
| 369 | { path: 'C:\\foo]bar', expected: 'file:///C:/foo%5Dbar' }, |
| 370 | // Local extended path |
| 371 | { |
| 372 | path: '\\\\?\\C:\\path\\to\\file.txt', |
| 373 | expected: 'file:///C:/path/to/file.txt', |
| 374 | }, |
| 375 | // UNC path (see https://docs.microsoft.com/en-us/archive/blogs/ie/file-uris-in-windows) |
| 376 | { |
| 377 | path: '\\\\nas\\My Docs\\File.doc', |
| 378 | expected: 'file://nas/My%20Docs/File.doc', |
| 379 | }, |
| 380 | // Extended UNC path |
| 381 | { |
| 382 | path: '\\\\?\\UNC\\server\\share\\folder\\file.txt', |
| 383 | expected: 'file://server/share/folder/file.txt', |
| 384 | }, |
| 385 | ]; |
| 386 | const posixTestCases = [ |
| 387 | // Lowercase ascii alpha |
| 388 | { path: '/foo', expected: 'file:///foo' }, |
| 389 | // Uppercase ascii alpha |
| 390 | { path: '/FOO', expected: 'file:///FOO' }, |
| 391 | // dir |
| 392 | { path: '/dir/foo', expected: 'file:///dir/foo' }, |
| 393 | // trailing separator |
| 394 | { path: '/dir/', expected: 'file:///dir/' }, |
| 395 | // dot |
| 396 | { path: '/foo.mjs', expected: 'file:///foo.mjs' }, |
| 397 | // space |
| 398 | { path: '/foo bar', expected: 'file:///foo%20bar' }, |
| 399 | // question mark |
| 400 | { path: '/foo?bar', expected: 'file:///foo%3Fbar' }, |
| 401 | // number sign |
| 402 | { path: '/foo#bar', expected: 'file:///foo%23bar' }, |
| 403 | // ampersand |
| 404 | { path: '/foo&bar', expected: 'file:///foo&bar' }, |
| 405 | // equals |
| 406 | { path: '/foo=bar', expected: 'file:///foo=bar' }, |
| 407 | // colon |
| 408 | { path: '/foo:bar', expected: 'file:///foo:bar' }, |
| 409 | // semicolon |
| 410 | { path: '/foo;bar', expected: 'file:///foo;bar' }, |
| 411 | // percent |
| 412 | { path: '/foo%bar', expected: 'file:///foo%25bar' }, |
| 413 | // backslash |
| 414 | { path: '/foo\\bar', expected: 'file:///foo%5Cbar' }, |
| 415 | // backspace |
| 416 | { path: '/foo\bbar', expected: 'file:///foo%08bar' }, |
| 417 | // tab |
| 418 | { path: '/foo\tbar', expected: 'file:///foo%09bar' }, |
| 419 | // newline |
| 420 | { path: '/foo\nbar', expected: 'file:///foo%0Abar' }, |
| 421 | // carriage return |
| 422 | { path: '/foo\rbar', expected: 'file:///foo%0Dbar' }, |
| 423 | // latin1 |
| 424 | { path: '/fóóbàr', expected: 'file:///f%C3%B3%C3%B3b%C3%A0r' }, |
| 425 | // Euro sign (BMP code point) |
| 426 | { path: '/€', expected: 'file:///%E2%82%AC' }, |
| 427 | // Rocket emoji (non-BMP code point) |
| 428 | { path: '/🚀', expected: 'file:///%F0%9F%9A%80' }, |
| 429 | // "unsafe" chars |
| 430 | { |
| 431 | path: '/foo\r\n\t<>"#%{}|^[\\~]`?bar', |
| 432 | expected: |
| 433 | 'file:///foo%0D%0A%09%3C%3E%22%23%25%7B%7D%7C%5E%5B%5C%7E%5D%60%3Fbar', |
| 434 | }, |
| 435 | ]; |
| 436 | |
| 437 | for (const { path, expected } of windowsTestCases) { |
| 438 | const actual = pathToFileURL(path, { windows: true }).href; |
| 439 | strictEqual(actual, expected); |
| 440 | } |
| 441 | |
| 442 | for (const { path, expected } of posixTestCases) { |
| 443 | const actual = pathToFileURL(path, { windows: false }).href; |
| 444 | strictEqual(actual, expected); |
| 445 | } |
| 446 | |
| 447 | for (const { path, expected } of windowsTestCases) { |
| 448 | const actual = pathToFileURL(path, { windows: true }).href; |
| 449 | strictEqual(actual, expected); |
| 450 | } |
| 451 | |
| 452 | for (const { path, expected } of posixTestCases) { |
| 453 | const actual = pathToFileURL(path, { windows: false }).href; |
| 454 | strictEqual(actual, expected); |
| 455 | } |
| 456 | |
| 457 | // Test for non-string parameter |
| 458 | { |
| 459 | for (const badPath of [ |
| 460 | undefined, |
| 461 | null, |
| 462 | true, |
| 463 | 42, |
| 464 | 42n, |
| 465 | Symbol('42'), |
| 466 | NaN, |
| 467 | {}, |
| 468 | [], |
| 469 | () => {}, |
| 470 | Promise.resolve('foo'), |
| 471 | new Date(), |
| 472 | new String('notPrimitive'), |
| 473 | { |
| 474 | toString() { |
| 475 | return 'amObject'; |
| 476 | }, |
| 477 | }, |
| 478 | { [Symbol.toPrimitive]: (hint) => 'amObject' }, |
| 479 | ]) { |
| 480 | throws(() => pathToFileURL(badPath), { |
| 481 | code: 'ERR_INVALID_ARG_TYPE', |
| 482 | }); |
| 483 | } |
| 484 | } |
| 485 | }, |
| 486 | }; |
| 487 | |
| 488 | // Regression test for: https://github.com/cloudflare/workerd/issues/5144 |
| 489 | export const testUrlPattern = { |
| 490 | async test(ctrl, env) { |
| 491 | const url = 'https://example.com/??'; |
| 492 | const pattern = new URLPattern({ hostname: '*' }); |
| 493 | const obj = new URL(url); |
| 494 | deepStrictEqual(pattern.exec(obj), { |
| 495 | inputs: [ |
| 496 | { |
| 497 | protocol: 'https:', |
| 498 | username: '', |
| 499 | password: '', |
| 500 | hostname: 'example.com', |
| 501 | port: '', |
| 502 | pathname: '/', |
| 503 | search: '??', |
| 504 | hash: '', |
| 505 | }, |
| 506 | ], |
| 507 | protocol: { input: 'https', groups: { 0: 'https' } }, |
| 508 | username: { input: '', groups: { 0: '' } }, |
| 509 | password: { input: '', groups: { 0: '' } }, |
| 510 | hostname: { input: 'example.com', groups: { 0: 'example.com' } }, |
| 511 | port: { input: '', groups: { 0: '' } }, |
| 512 | pathname: { input: '/', groups: { 0: '/' } }, |
| 513 | search: { input: '', groups: { 0: '' } }, |
| 514 | hash: { input: '', groups: { 0: '' } }, |
| 515 | }); |
| 516 | }, |
| 517 | }; |