diff --git a/examples/lit/package.json b/examples/lit/package.json index 4ac8c70bd..7b6c8f7c5 100644 --- a/examples/lit/package.json +++ b/examples/lit/package.json @@ -18,7 +18,7 @@ }, "devDependencies": { "@vitest/browser-playwright": "latest", - "jsdom": "^29.1.1", + "jsdom": "^30.1.1", "playwright": "^1.62.1", "vite": "latest", "vitest": "latest" diff --git a/examples/projects/package.json b/examples/projects/package.json index 5a36730dc..25ce729b8 100644 --- a/examples/projects/package.json +++ b/examples/projects/package.json @@ -16,7 +16,7 @@ "@vitejs/plugin-react": "^5.2.0", "@vitest/ui": "latest", "fastify": "^5.12.1", - "jsdom": "^29.1.1", + "jsdom": "^30.1.1", "react": "^19.2.8", "supertest": "^7.2.2", "tsx": "^4.23.13", diff --git a/packages/vitest/package.json b/packages/vitest/package.json index 16d32effc..2d7cfa231 100644 --- a/packages/vitest/package.json +++ b/packages/vitest/package.json @@ -187,7 +187,7 @@ "@jridgewell/trace-mapping": "catalog:", "@opentelemetry/api": "^1.9.1", "@sinonjs/fake-timers": "15.4.0", - "@types/jsdom": "^28.0.3", + "@types/jsdom": "^30.0.0", "@types/node": "^24.13.3", "@types/picomatch": "^4.0.3", "@types/prompts": "^2.4.9", @@ -204,7 +204,7 @@ "cac": "catalog:", "flatted": "catalog:", "happy-dom": "^20.12.0", - "jsdom": "^29.1.1", + "jsdom": "^30.1.1", "local-pkg": "^1.2.1", "mime": "^4.1.0", "pathe": "catalog:", diff --git a/packages/vitest/src/integrations/env/jsdom.ts b/packages/vitest/src/integrations/env/jsdom.ts index 383c9bcaa..86c51a865 100644 --- a/packages/vitest/src/integrations/env/jsdom.ts +++ b/packages/vitest/src/integrations/env/jsdom.ts @@ -1,6 +1,7 @@ import type { ConstructorOptions, DOMWindow, VirtualConsole as IVirtualConsole } from 'jsdom' import type { Environment } from '../../types/environment' import type { JSDOMOptions } from '../../types/jsdom-options' +import { createRequire } from 'node:module' import { URL as NodeURL } from 'node:url' import { populateGlobal } from './utils' @@ -292,12 +293,31 @@ interface CompatUtils { makeCompatFormData: (formData: FormData) => FormData } +// jsdom keeps Blob bytes on an internal "impl" object and exposes no synchronous +// public way to read them, so this reaches into its generated bindings +function createBlobImplGetter(window: DOMWindow): (blob: Blob) => any { + const _require = createRequire(import.meta.url) + // jsdom 28.1 moved the generated bindings; jsdom has no "exports" map, so both subpaths resolve + for (const id of [ + 'jsdom/lib/generated/idl/utils.js', + 'jsdom/lib/jsdom/living/generated/utils.js', + ]) { + try { + const { implForWrapper } = _require(id) + if (typeof implForWrapper === 'function') { + return implForWrapper + } + } catch {} + } + // jsdom < 30.1 also stores the impl under an own Symbol("impl") + const implSymbol = Object.getOwnPropertySymbols(new window.Blob())[0] + return (blob) => (blob as any)[implSymbol] +} + +let getBlobImpl: (blob: Blob) => any + function createCompatUtils(window: DOMWindow): CompatUtils { - // this returns a hidden Symbol(impl) - // this is cursed, and jsdom should just implement fetch API itself - const implSymbol = Object.getOwnPropertySymbols( - Object.getOwnPropertyDescriptors(new window.Blob()), - )[0] + getBlobImpl ??= createBlobImplGetter(window) const utils = { window, makeCompatFormData(formData: FormData) { @@ -312,7 +332,12 @@ function createCompatUtils(window: DOMWindow): CompatUtils { return nodeFormData }, makeCompatBlob(blob: Blob) { - const impl = (blob as any)[implSymbol] + const impl = getBlobImpl(blob) + if (!impl) { + throw new TypeError( + 'Vitest cannot read the bytes of a jsdom Blob. This is a Vitest bug, please report it with your jsdom version.', + ) + } // jsdom 28 renamed `_buffer` to `_bytes` return new NodeBlob_([impl._bytes ?? impl._buffer], { type: blob.type }) }, diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 4a8ffb99b..c8f61069a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -413,8 +413,8 @@ importers: specifier: workspace:* version: link:../../packages/browser-playwright jsdom: - specifier: ^29.1.1 - version: 29.1.1(@noble/hashes@1.8.0) + specifier: ^30.1.1 + version: 30.1.1(@noble/hashes@1.8.0) playwright: specifier: ^1.62.1 version: 1.62.1 @@ -488,8 +488,8 @@ importers: specifier: ^5.12.1 version: 5.12.1 jsdom: - specifier: ^29.1.1 - version: 29.1.1(@noble/hashes@1.8.0) + specifier: ^30.1.1 + version: 30.1.1(@noble/hashes@1.8.0) react: specifier: ^19.2.8 version: 19.2.8 @@ -1020,8 +1020,8 @@ importers: specifier: 15.4.0 version: 15.4.0(patch_hash=8fb375421f30746697394082b6fcf4a218fe07a8db36474ac335c48aff32c0cb) '@types/jsdom': - specifier: ^28.0.3 - version: 28.0.3 + specifier: ^30.0.0 + version: 30.0.0 '@types/node': specifier: 24.13.3 version: 24.13.3 @@ -1071,8 +1071,8 @@ importers: specifier: ^20.12.0 version: 20.12.0 jsdom: - specifier: ^29.1.1 - version: 29.1.1(@noble/hashes@1.8.0) + specifier: ^30.1.1 + version: 30.1.1(@noble/hashes@1.8.0) local-pkg: specifier: ^1.2.1 version: 1.2.1 @@ -1567,8 +1567,8 @@ importers: specifier: 'catalog:' version: 1.0.0 jsdom: - specifier: ^29.1.1 - version: 29.1.1(@noble/hashes@1.8.0) + specifier: ^30.1.1 + version: 30.1.1(@noble/hashes@1.8.0) vitest: specifier: workspace:* version: link:../../packages/vitest @@ -1611,20 +1611,13 @@ packages: peerDependencies: ajv: '>=8' - '@asamuzakjp/css-color@5.1.11': - resolution: {integrity: sha512-KVw6qIiCTUQhByfTd78h2yD1/00waTmm9uy/R7Ck/ctUyAPj+AEDLkQIdJW0T8+qGgj3j5bpNKK7Q3G+LedJWg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - - '@asamuzakjp/dom-selector@7.1.1': - resolution: {integrity: sha512-67RZDnYRc8H/8MLDgQCDE//zoqVFwajkepHZgmXrbwybzXOEwOWGPYGmALYl9J2DOLfFPPs6kKCqmbzV895hTQ==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} - - '@asamuzakjp/generational-cache@1.0.1': - resolution: {integrity: sha512-wajfB8KqzMCN2KGNFdLkReeHncd0AslUSrvHVvvYWuU8ghncRJoA50kT3zP9MVL0+9g4/67H+cdvBskj9THPzg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + '@asamuzakjp/css-color@7.1.2': + resolution: {integrity: sha512-99DHAnXDB5z6EEK+9GMpVI7Mw4oxj97dY5bpOzMnjADQWxI8rN6TvTduuFLUhUMlS7/CfVZ06tcZsus6cltnNw==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} - '@asamuzakjp/nwsapi@2.3.9': - resolution: {integrity: sha512-n8GuYSrI9bF7FFZ/SjhwevlHc8xaVlb/7HmHelnc/PZXBD2ZR49NnN9sMMuDdEGPeeRQ5d0hqlSlEpgCX3Wl0Q==} + '@asamuzakjp/dom-selector@9.2.2': + resolution: {integrity: sha512-lSWTBMjAcmu2xn5yEDU7jh6QDV+C8GEKtdJ4pIQhXh26RkKQ7S3FuQlt+zZkUbTdJ4d3XyV1kPI/G0zWXxqaqw==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} '@babel/code-frame@7.29.7': resolution: {integrity: sha512-Aup7aUOfpbAUg2ROOJN6Iw5f9DMBlzu0mIkm/malLQFN/YQgO48wCj0Kxa3sEHJvPVFg7siR+qRInwXd2qhQKw==} @@ -2283,40 +2276,40 @@ packages: '@canvas/image-data@1.0.0': resolution: {integrity: sha512-BxOqI5LgsIQP1odU5KMwV9yoijleOPzHL18/YvNqF9KFSGF2K/DLlYAbDQsWqd/1nbaFuSkYD/191dpMtNh4vw==} - '@csstools/color-helpers@6.0.2': - resolution: {integrity: sha512-LMGQLS9EuADloEFkcTBR3BwV/CGHV7zyDxVRtVDTwdI2Ca4it0CCVTT9wCkxSgokjE5Ho41hEPgb8OEUwoXr6Q==} + '@csstools/color-helpers@6.1.2': + resolution: {integrity: sha512-grhRy3OKmniaAEKXMjua5z/EODX0MSqBGjunw8+j/3HQjOnahs2AGhvEOIYVUWcU6ScApbhLhVrQTX8XqrMrow==} engines: {node: '>=20.19.0'} - '@csstools/css-calc@3.2.1': - resolution: {integrity: sha512-DtdHlgXh5ZkA43cwBcAm+huzgJiwx3ZTWVjBs94kwz2xKqSimDA3lBgCjphYgwgVUMWatSM0pDd8TILB1yrVVg==} + '@csstools/css-calc@3.4.1': + resolution: {integrity: sha512-EtC7SoN1j6J4E4DCwg5QgbO5TGxgxIA1RXqe+W+qUM+BUcezx9wT+/tiQ/WO2yCX4i5X+Cuf9ciJ22aP4UEwWw==} engines: {node: '>=20.19.0'} peerDependencies: - '@csstools/css-parser-algorithms': ^4.0.0 - '@csstools/css-tokenizer': ^4.0.0 + '@csstools/css-parser-algorithms': ^4.0.1 + '@csstools/css-tokenizer': ^4.0.2 - '@csstools/css-color-parser@4.1.1': - resolution: {integrity: sha512-eZ5XOtyhK+mggRafYUWzA0tvaYOFgdY8AkgQiCJF9qNAePnUo/zmsqqYubBBb3sQ8uNUaSKTY9s9klfRaAXL0g==} + '@csstools/css-color-parser@4.2.4': + resolution: {integrity: sha512-DyefytAZ735mX4Dq/WcDAXFtXhaEFvme0ZS9tVEBAc2whxUthXr0R0L2rmEPm59SrMBkGrFzQviBXMs/UtnABQ==} engines: {node: '>=20.19.0'} peerDependencies: - '@csstools/css-parser-algorithms': ^4.0.0 - '@csstools/css-tokenizer': ^4.0.0 + '@csstools/css-parser-algorithms': ^4.0.1 + '@csstools/css-tokenizer': ^4.0.2 - '@csstools/css-parser-algorithms@4.0.0': - resolution: {integrity: sha512-+B87qS7fIG3L5h3qwJ/IFbjoVoOe/bpOdh9hAjXbvx0o8ImEmUsGXN0inFOnk2ChCFgqkkGFQ+TpM5rbhkKe4w==} + '@csstools/css-parser-algorithms@4.0.1': + resolution: {integrity: sha512-ShL8BqPfbKJrJiKFH0xBbN0i7Nrh9HXYRuF+pzyj93R/BL2YAsUxJeqANErzqM+0JGl7vjHp+3OIgd/DL69YIA==} engines: {node: '>=20.19.0'} peerDependencies: - '@csstools/css-tokenizer': ^4.0.0 + '@csstools/css-tokenizer': ^4.0.2 - '@csstools/css-syntax-patches-for-csstree@1.1.4': - resolution: {integrity: sha512-wgsqt92b7C7tQhIdPNxj0n9zuUbQlvAuI1exyzeNrOKOi62SD7ren8zqszmpVREjAOqg8cD2FqYhQfAuKjk4sw==} + '@csstools/css-syntax-patches-for-csstree@1.1.14': + resolution: {integrity: sha512-HpbVXyrofRXpHpgkNIjU/3EWR4WJvOkO3emNK/L6X/mTJU7bGUI3AkkpoTNXznQLp0KRjLHELTGeKI5dIkI9JQ==} peerDependencies: css-tree: ^3.2.1 peerDependenciesMeta: css-tree: optional: true - '@csstools/css-tokenizer@4.0.0': - resolution: {integrity: sha512-QxULHAm7cNu72w97JUNCBFODFaXpbDg+dP8b/oWFAZ2MTRppA3U00Y2L1HqaS4J6yBqxwa/Y3nMBaxVKbB/NsA==} + '@csstools/css-tokenizer@4.0.2': + resolution: {integrity: sha512-OoKoR0f76dCY666JlcbhmVTs2drYj1GUXZTYTcbUgJjh9Nv41aFfZ21bPQTERm5+L5cBDo466NltB2lplS5GBw==} engines: {node: '>=20.19.0'} '@docsearch/css@4.7.0': @@ -2522,6 +2515,15 @@ packages: '@noble/hashes': optional: true + '@exodus/bytes@1.16.0': + resolution: {integrity: sha512-IcpW84uEn3N7ETtNZMlxKhfl6Pec8rUNGOTBtWbK1FKhJxIFAptZyVrvVRVBimAJxJCgc3PxepxkdWWG4DVzfA==} + engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + peerDependencies: + '@noble/hashes': ^1.8.0 || ^2.0.0 + peerDependenciesMeta: + '@noble/hashes': + optional: true + '@faker-js/faker@10.6.0': resolution: {integrity: sha512-3RQHgEtvL1Frl/d1cSreo7qhJ3Gk1OdNUai/CtZ8G+wYeRQnJih3s9xJ9/kgYekPQRdwgh0HXRPqMlzWGwivIQ==} engines: {node: ^20.19.0 || ^22.13.0 || ^23.5.0 || >=24.0.0, npm: '>=10'} @@ -5095,8 +5097,8 @@ packages: '@types/hast@3.0.5': resolution: {integrity: sha512-rp/ezSWaD1m44dPKICGhiskI13nVr7qTloFwDa/IYkhhf5nzwP+zIQcIJh3WIFSBOy/H1PzB40jPjMDksN4F+g==} - '@types/jsdom@28.0.3': - resolution: {integrity: sha512-/HQ2uFoetFTXuye8vzIcHw2z6Fwi7Hi/qcgC+RoS9NCyewiqxhVGqlG+ViGB6lkax481R6dmhf1I7lIGlzJStQ==} + '@types/jsdom@30.0.0': + resolution: {integrity: sha512-uAHGxujGE0cDaKGdK28zgDotFtNA7MKq5DXl8LrfdxdCI8VHcg15oJz+amHTChPNI5JpgEPQWc2xFdrw3em/nQ==} '@types/jsesc@2.5.1': resolution: {integrity: sha512-9VN+6yxLOPLOav+7PwjZbxiID2bVaeq0ED4qSQmdQTdjnXJSaCVKTR58t15oqH1H5t8Ng2ZX1SabJVoN9Q34bw==} @@ -5811,8 +5813,8 @@ packages: resolution: {integrity: sha512-bopVNp6ugyA150DDuZfPFdt1KZ5a94ZDiwX4hMgZDzF+GttD80lEy8kj98kbyhLXnPvhtIo93mdnLIjpCAeeOw==} engines: {node: '>=10.0.0'} - bidi-js@1.0.3: - resolution: {integrity: sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==} + bidi-js@1.1.0: + resolution: {integrity: sha512-fX1Onk0tdVPC7obPWB5EbJ1z7NVhLq4m2xZLq2YXBkxzMXIGRpNMU88n0EPgWseKl12J7zXs7qrDxPK4sRs2fg==} binary-extensions@2.2.0: resolution: {integrity: sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==} @@ -6950,9 +6952,9 @@ packages: hpack.js@2.1.6: resolution: {integrity: sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==} - html-encoding-sniffer@6.0.0: - resolution: {integrity: sha512-CV9TW3Y3f8/wT0BRFc1/KAVQ3TUHiXmaAb6VW9vtiMFf7SLoMd1PdAc4W3KFOFETBJUb90KatHqlsZMWV+R9Gg==} - engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + html-encoding-sniffer@7.0.0: + resolution: {integrity: sha512-UikN5yr7xsCDAq87Or5or0PAlD3HJJOKVzM05az588WnpDJ4Ux7a2A53Qi6gofGg2/EtvF/H4hCi/TXfCW4Y6w==} + engines: {node: ^22.13.0 || >=24.0.0} html-void-elements@3.0.0: resolution: {integrity: sha512-bEqo66MRXsUGxWHV5IP0PUiAWwoEjba4VCzg0LjFJBpchPaTfyfCKTG6bc5F8ucKec3q5y6qOdGyYTSBEvhCrg==} @@ -7319,11 +7321,11 @@ packages: resolution: {integrity: sha512-CY6crGq313MX8GkwvB7tzgp99vjQxY1++5y10/BKN/GUfHqWaOGQMNZkBvqSzsZKWk/ijwHlWzzkLulsGHhjWQ==} hasBin: true - jsdom@29.1.1: - resolution: {integrity: sha512-ECi4Fi2f7BdJtUKTflYRTiaMxIB0O6zfR1fX0GXpUrf6flp8QIYn1UT20YQqdSOfk2dfkCwS8LAFoJDEppNK5Q==} - engines: {node: ^20.19.0 || ^22.13.0 || >=24.0.0} + jsdom@30.1.1: + resolution: {integrity: sha512-FahmoPK5vbPc+jxV1iErMHmAZypCZ942NHF4+qqaWAuvaKKTBZxawnmAtrbGWLU7MtlxfqIP0qw6aSI+aWGtLg==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} peerDependencies: - canvas: ^3.0.0 + canvas: ^3.2.3 peerDependenciesMeta: canvas: optional: true @@ -7600,6 +7602,10 @@ packages: resolution: {integrity: sha512-W+R+kFL4HgVxONq2bhXPi3bGpzGe/yEhVOp233qw9wCRtgncJ15P3bC+e4zZMu4Cq7d+WAJjXGW0uUkifhcatA==} engines: {node: 20 || >=22} + lru-cache@11.5.3: + resolution: {integrity: sha512-U4N8FgzmWxc8k1VH8Kr6lQg18U7Fjvby6wXHVRX/ZZ7IwWbRMgrRbP0Wrb5q5NVinryp4SQampHKdvtecItxUg==} + engines: {node: 20 || >=22} + lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} @@ -9089,9 +9095,6 @@ packages: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} engines: {node: '>= 0.4'} - symbol-tree@3.2.4: - resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} - sync-child-process@1.0.2: resolution: {integrity: sha512-8lD+t2KrrScJ/7KXCSyfhT3/hRq78rC0wBFqNJXv3mZyn6hW2ypM05JmlSvtqRbeq6jqA94oHbxAr2vYsJ8vDA==} engines: {node: '>=16.0.0'} @@ -9248,6 +9251,10 @@ packages: resolution: {integrity: sha512-LktZQb3IeoUWB9lqR5EWTHgW/VTITCXg4D21M+lvybRVdylLrRMnqaIONLVb5mav8vM19m44HIcGq4qASeu2Qw==} engines: {node: '>=16'} + tough-cookie@6.0.2: + resolution: {integrity: sha512-exgYmnmL/sJpR3upZfXG5PoatXQii55xAiXGXzY+sROLZ/Y+SLcp9PgJNI9Vz37HpQ74WvDcLT8eqm+kV3FzrA==} + engines: {node: '>=16'} + tr46@1.0.1: resolution: {integrity: sha512-dTpowEjclQ7Kgx5SdBkqRzVhERQXov8/l9Ft9dVM9fmg0W0KQSVaXX9T4i6twCPNtYiZM53lpSSUAwJbFPOHxA==} @@ -9374,8 +9381,8 @@ packages: undici-types@7.18.2: resolution: {integrity: sha512-AsuCzffGHJybSaRrmr5eHr81mwJU3kjw6M+uprWvCXiNeN9SOGwQ3Jn8jb8m3Z6izVgknn1R0FTCEAP2QrLY/w==} - undici-types@7.29.0: - resolution: {integrity: sha512-vamA8dGlzMwhpyYpQp9d8vka3o4D/yn5I7ez7Or+msDA4bZ8Uh+Zy91WvWf3I73gDAkFha9JcYRqm2li0Npfgg==} + undici-types@8.11.2: + resolution: {integrity: sha512-iMVNmWZ0leK/goS6eXMizSzmm9CDWtyphwbaCms3DNLqRxDL+mMoNVcZMTyyVgXP0N+Z8neAMzDoUOUJL8veKg==} undici@6.27.0: resolution: {integrity: sha512-YmfV3YnEDzXRC5lZ2jWtWWHKGUm1zIt8AhesR1tens+HTNv+YZlN/dp6G727LOvMJ8xjP9Be7Y2Sdr96LDm+pg==} @@ -9385,6 +9392,10 @@ packages: resolution: {integrity: sha512-xXnp4kTyor2Zq+J1FfPI6Eq3ew5h6Vl0F/8d9XU5zZQf1tX9s2Su1/3PiMmUANFULpmksxkClamIZcaUqryHsQ==} engines: {node: '>=20.18.1'} + undici@8.11.2: + resolution: {integrity: sha512-u4UB2/IrKdU6lFxumHmmo1a3fCQO5tzQllRorfoRS63txhrB7xTpSn1PftwC4qEHkOaqP95fCWW4lJzwErwzhQ==} + engines: {node: '>=22.19.0'} + unicode-canonical-property-names-ecmascript@2.0.1: resolution: {integrity: sha512-dA8WbNeb2a6oQzAQ55YlT5vQAWGV9WXOsi3SskE3bcCdM0P4SDd+24zS/OCacdRq5BkdsRj9q3Pg6YyQoxIGqg==} engines: {node: '>=4'} @@ -9746,9 +9757,9 @@ packages: typescript: optional: true - w3c-xmlserializer@5.0.0: - resolution: {integrity: sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA==} - engines: {node: '>=18'} + w3c-xmlserializer@6.0.0: + resolution: {integrity: sha512-4Nsy8K5Tr6SPDH9jhKJOHf7ChDrc1zufZTVSF7x72hwuEXBqxqk9G6cK+K2NRUtB3iELRJqjXb4JPDMBjMTl2Q==} + engines: {node: ^22.22.2 || ^24.15.0 || >=26.0.0} wait-port@1.1.0: resolution: {integrity: sha512-3e04qkoN3LxTMLakdqeWth8nih8usyg+sf1Bgdf9wwUkp05iuK1eSY/QpLvscT/+F/gA89+LpUmmgBtesbqI2Q==} @@ -9806,6 +9817,10 @@ packages: resolution: {integrity: sha512-1to4zXBxmXHV3IiSSEInrreIlu02vUOvrhxJJH5vcxYTBDAx51cqZiKdyTxlecdKNSjj8EcxGBxNf6Vg+945gw==} engines: {node: ^20.19.0 || ^22.12.0 || >=24.0.0} + whatwg-url@17.1.2: + resolution: {integrity: sha512-TEZA+Zqxin7Jjsm2cjRohCmen5awh+hT6Zi3VZdqZlNRk7zvOI/9WpBFg/DWlA56bWnzwm6DuB8NS0EsxQH9uQ==} + engines: {node: ^22.14.0 || >=24.0.0} + whatwg-url@7.1.0: resolution: {integrity: sha512-WUu7Rg1DroM7oQvGWfOiAK21n74Gg+T4elXEQYkOhtyLeWiJFoOGLXPKI/9gzIie9CtwVLm8wtw6YJdKyxSjeg==} @@ -10014,25 +10029,20 @@ snapshots: jsonpointer: 5.0.1 leven: 3.1.0 - '@asamuzakjp/css-color@5.1.11': + '@asamuzakjp/css-color@7.1.2': dependencies: - '@asamuzakjp/generational-cache': 1.0.1 - '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-color-parser': 4.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 + '@csstools/css-calc': 3.4.1(@csstools/css-parser-algorithms@4.0.1(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2) + '@csstools/css-color-parser': 4.2.4(@csstools/css-parser-algorithms@4.0.1(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2) + '@csstools/css-parser-algorithms': 4.0.1(@csstools/css-tokenizer@4.0.2) + '@csstools/css-tokenizer': 4.0.2 + lru-cache: 11.5.3 - '@asamuzakjp/dom-selector@7.1.1': + '@asamuzakjp/dom-selector@9.2.2': dependencies: - '@asamuzakjp/generational-cache': 1.0.1 - '@asamuzakjp/nwsapi': 2.3.9 - bidi-js: 1.0.3 + bidi-js: 1.1.0 css-tree: 3.2.1 is-potential-custom-element-name: 1.0.1 - - '@asamuzakjp/generational-cache@1.0.1': {} - - '@asamuzakjp/nwsapi@2.3.9': {} + lru-cache: 11.5.3 '@babel/code-frame@7.29.7': dependencies: @@ -10867,29 +10877,29 @@ snapshots: '@canvas/image-data@1.0.0': {} - '@csstools/color-helpers@6.0.2': {} + '@csstools/color-helpers@6.1.2': {} - '@csstools/css-calc@3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + '@csstools/css-calc@3.4.1(@csstools/css-parser-algorithms@4.0.1(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2)': dependencies: - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 + '@csstools/css-parser-algorithms': 4.0.1(@csstools/css-tokenizer@4.0.2) + '@csstools/css-tokenizer': 4.0.2 - '@csstools/css-color-parser@4.1.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0)': + '@csstools/css-color-parser@4.2.4(@csstools/css-parser-algorithms@4.0.1(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2)': dependencies: - '@csstools/color-helpers': 6.0.2 - '@csstools/css-calc': 3.2.1(@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0))(@csstools/css-tokenizer@4.0.0) - '@csstools/css-parser-algorithms': 4.0.0(@csstools/css-tokenizer@4.0.0) - '@csstools/css-tokenizer': 4.0.0 + '@csstools/color-helpers': 6.1.2 + '@csstools/css-calc': 3.4.1(@csstools/css-parser-algorithms@4.0.1(@csstools/css-tokenizer@4.0.2))(@csstools/css-tokenizer@4.0.2) + '@csstools/css-parser-algorithms': 4.0.1(@csstools/css-tokenizer@4.0.2) + '@csstools/css-tokenizer': 4.0.2 - '@csstools/css-parser-algorithms@4.0.0(@csstools/css-tokenizer@4.0.0)': + '@csstools/css-parser-algorithms@4.0.1(@csstools/css-tokenizer@4.0.2)': dependencies: - '@csstools/css-tokenizer': 4.0.0 + '@csstools/css-tokenizer': 4.0.2 - '@csstools/css-syntax-patches-for-csstree@1.1.4(css-tree@3.2.1)': + '@csstools/css-syntax-patches-for-csstree@1.1.14(css-tree@3.2.1)': optionalDependencies: css-tree: 3.2.1 - '@csstools/css-tokenizer@4.0.0': {} + '@csstools/css-tokenizer@4.0.2': {} '@docsearch/css@4.7.0': {} @@ -11022,6 +11032,10 @@ snapshots: optionalDependencies: '@noble/hashes': 1.8.0 + '@exodus/bytes@1.16.0(@noble/hashes@1.8.0)': + optionalDependencies: + '@noble/hashes': 1.8.0 + '@faker-js/faker@10.6.0': {} '@fastify/ajv-compiler@4.0.5': @@ -12934,12 +12948,12 @@ snapshots: dependencies: '@types/unist': 3.0.2 - '@types/jsdom@28.0.3': + '@types/jsdom@30.0.0': dependencies: '@types/node': 24.13.3 '@types/tough-cookie': 4.0.5 parse5: 8.0.1 - undici-types: 7.29.0 + undici-types: 8.11.2 '@types/jsesc@2.5.1': {} @@ -13803,7 +13817,7 @@ snapshots: basic-ftp@5.3.1: {} - bidi-js@1.0.3: + bidi-js@1.1.0: dependencies: require-from-string: 2.0.2 @@ -15183,9 +15197,9 @@ snapshots: readable-stream: 2.3.7 wbuf: 1.7.3 - html-encoding-sniffer@6.0.0(@noble/hashes@1.8.0): + html-encoding-sniffer@7.0.0(@noble/hashes@1.8.0): dependencies: - '@exodus/bytes': 1.15.0(@noble/hashes@1.8.0) + '@exodus/bytes': 1.16.0(@noble/hashes@1.8.0) transitivePeerDependencies: - '@noble/hashes' @@ -15526,28 +15540,27 @@ snapshots: dependencies: argparse: 2.0.1 - jsdom@29.1.1(@noble/hashes@1.8.0): + jsdom@30.1.1(@noble/hashes@1.8.0): dependencies: - '@asamuzakjp/css-color': 5.1.11 - '@asamuzakjp/dom-selector': 7.1.1 + '@asamuzakjp/css-color': 7.1.2 + '@asamuzakjp/dom-selector': 9.2.2 '@bramus/specificity': 2.4.2 - '@csstools/css-syntax-patches-for-csstree': 1.1.4(css-tree@3.2.1) - '@exodus/bytes': 1.15.0(@noble/hashes@1.8.0) + '@csstools/css-syntax-patches-for-csstree': 1.1.14(css-tree@3.2.1) + '@exodus/bytes': 1.16.0(@noble/hashes@1.8.0) css-tree: 3.2.1 data-urls: 7.0.0(@noble/hashes@1.8.0) decimal.js: 10.6.0 - html-encoding-sniffer: 6.0.0(@noble/hashes@1.8.0) + html-encoding-sniffer: 7.0.0(@noble/hashes@1.8.0) is-potential-custom-element-name: 1.0.1 - lru-cache: 11.4.0 + lru-cache: 11.5.3 parse5: 8.0.1 saxes: 6.0.0 - symbol-tree: 3.2.4 - tough-cookie: 6.0.1 - undici: 7.25.0 - w3c-xmlserializer: 5.0.0 + tough-cookie: 6.0.2 + undici: 8.11.2 + w3c-xmlserializer: 6.0.0 webidl-conversions: 8.0.1 whatwg-mimetype: 5.0.0 - whatwg-url: 16.0.1(@noble/hashes@1.8.0) + whatwg-url: 17.1.2(@noble/hashes@1.8.0) xml-name-validator: 5.0.0 transitivePeerDependencies: - '@noble/hashes' @@ -15777,6 +15790,8 @@ snapshots: lru-cache@11.4.0: {} + lru-cache@11.5.3: {} + lru-cache@5.1.1: dependencies: yallist: 3.1.1 @@ -17749,8 +17764,6 @@ snapshots: supports-preserve-symlinks-flag@1.0.0: {} - symbol-tree@3.2.4: {} - sync-child-process@1.0.2: dependencies: sync-message-port: 1.1.3 @@ -17904,6 +17917,10 @@ snapshots: dependencies: tldts: 7.0.13 + tough-cookie@6.0.2: + dependencies: + tldts: 7.0.13 + tr46@1.0.1: dependencies: punycode: 2.3.1 @@ -18042,12 +18059,14 @@ snapshots: undici-types@7.18.2: {} - undici-types@7.29.0: {} + undici-types@8.11.2: {} undici@6.27.0: {} undici@7.25.0: {} + undici@8.11.2: {} + unicode-canonical-property-names-ecmascript@2.0.1: {} unicode-match-property-ecmascript@2.0.0: @@ -18469,7 +18488,7 @@ snapshots: optionalDependencies: typescript: 5.9.3 - w3c-xmlserializer@5.0.0: + w3c-xmlserializer@6.0.0: dependencies: xml-name-validator: 5.0.0 @@ -18567,6 +18586,14 @@ snapshots: transitivePeerDependencies: - '@noble/hashes' + whatwg-url@17.1.2(@noble/hashes@1.8.0): + dependencies: + '@exodus/bytes': 1.16.0(@noble/hashes@1.8.0) + tr46: 6.0.0 + webidl-conversions: 8.0.1 + transitivePeerDependencies: + - '@noble/hashes' + whatwg-url@7.1.0: dependencies: lodash.sortby: 4.7.0 diff --git a/test/unit/test/environments/jsdom.spec.ts b/test/unit/test/environments/jsdom.spec.ts index fe41a0998..2f82eda82 100644 --- a/test/unit/test/environments/jsdom.spec.ts +++ b/test/unit/test/environments/jsdom.spec.ts @@ -349,6 +349,17 @@ test('URL.createObjectUrl works properly', () => { }).not.toThrow() }) +test('URL.createObjectURL keeps the Blob bytes', async () => { + const url = URL.createObjectURL(new Blob(['hello world'], { type: 'text/plain' })) + expect(url).toMatch(/^blob:/) + + const response = await fetch(url) + URL.revokeObjectURL(url) + + expect(response.headers.get('content-type')).toBe('text/plain') + expect(await response.text()).toBe('hello world') +}) + test('compat classes preserve their .name property', () => { expect(URL.name).toBe('URL') expect(Request.name).toBe('Request') diff --git a/test/workspaces/package.json b/test/workspaces/package.json index 2fae47fd2..9beec53dd 100644 --- a/test/workspaces/package.json +++ b/test/workspaces/package.json @@ -10,7 +10,7 @@ "devDependencies": { "@jridgewell/remapping": "catalog:", "@vitest/istanbul-lib-coverage": "catalog:", - "jsdom": "^29.1.1", + "jsdom": "^30.1.1", "vitest": "workspace:*" } }