@@ -7,6 +7,33 @@ const KEY = 'test/storage@v1';
77const ORIGINAL_ENV = process . env . NODE_ENV ;
88
99describe ( 'storage utils' , ( ) => {
10+ function ensureWindowWithLocalStorage ( ) {
11+ // Ensure a Window-like global for Node environment
12+ if ( typeof window === 'undefined' ) {
13+ Object . defineProperty ( globalThis , 'window' , {
14+ // unknown avoids explicit any; cast to Window shape for tests
15+ value : { } as unknown as Window & typeof globalThis ,
16+ configurable : true
17+ } ) ;
18+ }
19+ // Polyfill localStorage if missing
20+ if ( ! ( 'localStorage' in window ) ) {
21+ const store = new Map < string , string > ( ) ;
22+ Object . defineProperty ( window , 'localStorage' , {
23+ value : {
24+ getItem : ( k : string ) => store . get ( k ) ?? null ,
25+ setItem : ( k : string , v : string ) => {
26+ store . set ( k , v ) ;
27+ } ,
28+ removeItem : ( k : string ) => {
29+ store . delete ( k ) ;
30+ }
31+ } ,
32+ configurable : true
33+ } ) ;
34+ }
35+ }
36+
1037 beforeEach ( ( ) => {
1138 // Ensure clean slate
1239 try {
@@ -35,45 +62,15 @@ describe('storage utils', () => {
3562 it ( 'Malformed JSON returns fallback' , ( ) => {
3663 // Enable storage access by switching to a non-test env for this test
3764 process . env . NODE_ENV = 'development' ;
38- // Ensure localStorage exists in case test env didn't provide it
39- if ( typeof window === 'undefined' || ! ( 'localStorage' in window ) ) {
40- // @ts -ignore
41- global . window = { } as any ;
42- }
43- if ( ! ( 'localStorage' in window ) ) {
44- const store = new Map < string , string > ( ) ;
45- Object . defineProperty ( window , 'localStorage' , {
46- value : {
47- getItem : ( k : string ) => store . get ( k ) ?? null ,
48- setItem : ( k : string , v : string ) => void store . set ( k , v ) ,
49- removeItem : ( k : string ) => void store . delete ( k )
50- } ,
51- configurable : true
52- } ) ;
53- }
65+ ensureWindowWithLocalStorage ( ) ;
5466 window . localStorage . setItem ( KEY , '{not json' ) ;
5567 const result = loadFromStorage ( KEY , { good : true } ) ;
5668 expect ( result ) . toEqual ( { good : true } ) ;
5769 } ) ;
5870
5971 it ( 'save/remove round-trip behavior works' , ( ) => {
6072 process . env . NODE_ENV = 'development' ;
61- // Ensure localStorage exists (same polyfill as above)
62- if ( typeof window === 'undefined' || ! ( 'localStorage' in window ) ) {
63- // @ts -ignore
64- global . window = { } as any ;
65- }
66- if ( ! ( 'localStorage' in window ) ) {
67- const store = new Map < string , string > ( ) ;
68- Object . defineProperty ( window , 'localStorage' , {
69- value : {
70- getItem : ( k : string ) => store . get ( k ) ?? null ,
71- setItem : ( k : string , v : string ) => void store . set ( k , v ) ,
72- removeItem : ( k : string ) => void store . delete ( k )
73- } ,
74- configurable : true
75- } ) ;
76- }
73+ ensureWindowWithLocalStorage ( ) ;
7774
7875 const value = { a : 1 , b : 'two' } ;
7976 saveToStorage ( KEY , value ) ;
@@ -88,39 +85,33 @@ describe('storage utils', () => {
8885
8986 it ( 'validate guard: rejects invalid shape and returns fallback' , ( ) => {
9087 process . env . NODE_ENV = 'development' ;
91- const store = new Map < string , string > ( ) ;
92- Object . defineProperty ( window , 'localStorage' , {
93- value : {
94- getItem : ( k : string ) => store . get ( k ) ?? null ,
95- setItem : ( k : string , v : string ) => void store . set ( k , v ) ,
96- removeItem : ( k : string ) => void store . delete ( k )
97- } ,
98- configurable : true
99- } ) ;
88+ ensureWindowWithLocalStorage ( ) ;
10089
10190 window . localStorage . setItem ( KEY , JSON . stringify ( { nope : true } ) ) ;
10291
10392 const fallback = { ok : true } ;
104- const result = loadFromStorage ( KEY , fallback , ( v ) : v is typeof fallback => typeof ( v as any ) . ok === 'boolean' ) ;
93+ const result = loadFromStorage (
94+ KEY ,
95+ fallback ,
96+ ( v ) : v is typeof fallback =>
97+ typeof v === 'object' && v !== null && 'ok' in v && typeof ( v as { ok : unknown } ) . ok === 'boolean'
98+ ) ;
10599 expect ( result ) . toEqual ( fallback ) ;
106100 } ) ;
107101
108102 it ( 'validate guard: accepts valid shape' , ( ) => {
109103 process . env . NODE_ENV = 'development' ;
110- const store = new Map < string , string > ( ) ;
111- Object . defineProperty ( window , 'localStorage' , {
112- value : {
113- getItem : ( k : string ) => store . get ( k ) ?? null ,
114- setItem : ( k : string , v : string ) => void store . set ( k , v ) ,
115- removeItem : ( k : string ) => void store . delete ( k )
116- } ,
117- configurable : true
118- } ) ;
104+ ensureWindowWithLocalStorage ( ) ;
119105
120106 const value = { ok : true } ;
121107 window . localStorage . setItem ( KEY , JSON . stringify ( value ) ) ;
122108
123- const result = loadFromStorage ( KEY , { ok : false } , ( v ) : v is typeof value => typeof ( v as any ) . ok === 'boolean' ) ;
109+ const result = loadFromStorage (
110+ KEY ,
111+ { ok : false } ,
112+ ( v ) : v is typeof value =>
113+ typeof v === 'object' && v !== null && 'ok' in v && typeof ( v as { ok : unknown } ) . ok === 'boolean'
114+ ) ;
124115 expect ( result ) . toEqual ( value ) ;
125116 } ) ;
126117} ) ;
0 commit comments