From e8eec567836e0c9aa3994a2f9e4fb3bacaca1fe2 Mon Sep 17 00:00:00 2001 From: Nick Sandstrom <32273437+nick4810@users.noreply.github.com> Date: Tue, 30 Jun 2026 16:21:04 -0700 Subject: [PATCH 1/2] Added localStorage polyfill --- frontend/src/test/setupTests.js | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/frontend/src/test/setupTests.js b/frontend/src/test/setupTests.js index b5f53af0..7651cad0 100644 --- a/frontend/src/test/setupTests.js +++ b/frontend/src/test/setupTests.js @@ -32,6 +32,35 @@ if (typeof window !== 'undefined' && !window.ResizeObserver) { window.ResizeObserver = ResizeObserver; } +if ( + typeof window !== 'undefined' && + typeof window.localStorage?.clear !== 'function' +) { + let store = {}; + const storage = { + getItem: (key) => store[key] ?? null, + setItem: (key, value) => { + store[key] = String(value); + }, + removeItem: (key) => { + delete store[key]; + }, + clear: () => { + store = {}; + }, + get length() { + return Object.keys(store).length; + }, + key: (i) => Object.keys(store)[i] ?? null, + }; + Object.defineProperty(window, 'localStorage', { + configurable: true, + enumerable: true, + writable: true, + value: storage, + }); +} + if (typeof window !== 'undefined') { if (!window.requestAnimationFrame) { window.requestAnimationFrame = (cb) => setTimeout(cb, 16); From 27fc812df935b596b174aa8969a491f4b3c98e69 Mon Sep 17 00:00:00 2001 From: SergeantPanda Date: Thu, 2 Jul 2026 14:39:26 -0500 Subject: [PATCH 2/2] Add comment explaining the Node 25 issue with localStorage. Also patch globalThis. --- frontend/src/test/setupTests.js | 62 +++++++++++++++++++-------------- 1 file changed, 35 insertions(+), 27 deletions(-) diff --git a/frontend/src/test/setupTests.js b/frontend/src/test/setupTests.js index 7651cad0..f3bc39f6 100644 --- a/frontend/src/test/setupTests.js +++ b/frontend/src/test/setupTests.js @@ -32,33 +32,41 @@ if (typeof window !== 'undefined' && !window.ResizeObserver) { window.ResizeObserver = ResizeObserver; } -if ( - typeof window !== 'undefined' && - typeof window.localStorage?.clear !== 'function' -) { - let store = {}; - const storage = { - getItem: (key) => store[key] ?? null, - setItem: (key, value) => { - store[key] = String(value); - }, - removeItem: (key) => { - delete store[key]; - }, - clear: () => { - store = {}; - }, - get length() { - return Object.keys(store).length; - }, - key: (i) => Object.keys(store)[i] ?? null, - }; - Object.defineProperty(window, 'localStorage', { - configurable: true, - enumerable: true, - writable: true, - value: storage, - }); +// Node 25+ exposes a broken native localStorage stub on globalThis (missing +// Storage methods) that shadows jsdom's implementation. +if (typeof window !== 'undefined') { + const brokenTargets = [globalThis, window].filter( + (target) => typeof target?.localStorage?.getItem !== 'function' + ); + + if (brokenTargets.length > 0) { + let store = {}; + const storage = { + getItem: (key) => store[key] ?? null, + setItem: (key, value) => { + store[key] = String(value); + }, + removeItem: (key) => { + delete store[key]; + }, + clear: () => { + store = {}; + }, + get length() { + return Object.keys(store).length; + }, + key: (i) => Object.keys(store)[i] ?? null, + }; + + for (const target of brokenTargets) { + Object.defineProperty(target, 'localStorage', { + configurable: true, + enumerable: true, + writable: true, + value: storage, + }); + } + } } if (typeof window !== 'undefined') {