@@ -84,3 +84,110 @@ test('getting values from document', () => {
8484 delete global . document
8585 }
8686} )
87+
88+ test ( 'handles malformed URI in cookie values gracefully' , ( ) => {
89+ const hints = getHintUtils ( {
90+ colorScheme : colorSchemeHint ,
91+ timeZone : timeZoneHint ,
92+ reducedMotion : reducedMotionHint ,
93+ } )
94+
95+ // Test with malformed URI that would cause decodeURIComponent to fail
96+ const request = new Request ( 'https://example.com' , {
97+ headers : {
98+ Cookie :
99+ 'CH-prefers-color-scheme=dark; CH-time-zone=%C0%AF; CH-reduced-motion=reduce' ,
100+ } ,
101+ } )
102+
103+ // The malformed timezone should fall back to the fallback value
104+ const result = hints . getHints ( request )
105+ assert . strictEqual ( result . colorScheme , 'dark' )
106+ assert . strictEqual ( result . timeZone , timeZoneHint . fallback ) // Should fall back due to malformed URI
107+ assert . strictEqual ( result . reducedMotion , 'reduce' )
108+ } )
109+
110+ test ( 'handles completely malformed cookie values' , ( ) => {
111+ const hints = getHintUtils ( {
112+ colorScheme : colorSchemeHint ,
113+ timeZone : timeZoneHint ,
114+ reducedMotion : reducedMotionHint ,
115+ } )
116+
117+ // Test with completely invalid URI sequences
118+ const request = new Request ( 'https://example.com' , {
119+ headers : {
120+ Cookie :
121+ 'CH-prefers-color-scheme=%C0%AF; CH-time-zone=%FF%FE; CH-reduced-motion=%E0%80%80' ,
122+ } ,
123+ } )
124+
125+ // All malformed values should fall back to their fallback values
126+ const result = hints . getHints ( request )
127+ assert . strictEqual ( result . colorScheme , colorSchemeHint . fallback )
128+ assert . strictEqual ( result . timeZone , timeZoneHint . fallback )
129+ assert . strictEqual ( result . reducedMotion , reducedMotionHint . fallback )
130+ } )
131+
132+ test ( 'handles mixed valid and invalid cookie values' , ( ) => {
133+ const hints = getHintUtils ( {
134+ colorScheme : colorSchemeHint ,
135+ timeZone : timeZoneHint ,
136+ reducedMotion : reducedMotionHint ,
137+ } )
138+
139+ // Test with mix of valid and invalid values
140+ const request = new Request ( 'https://example.com' , {
141+ headers : {
142+ Cookie :
143+ 'CH-prefers-color-scheme=light; CH-time-zone=%C0%AF; CH-reduced-motion=no-preference' ,
144+ } ,
145+ } )
146+
147+ // Valid values should work, invalid ones should fall back
148+ const result = hints . getHints ( request )
149+ assert . strictEqual ( result . colorScheme , 'light' ) // Valid value
150+ assert . strictEqual ( result . timeZone , timeZoneHint . fallback ) // Invalid value, should fall back
151+ assert . strictEqual ( result . reducedMotion , 'no-preference' ) // Valid value
152+ } )
153+
154+ test ( 'handles empty cookie values gracefully' , ( ) => {
155+ const hints = getHintUtils ( {
156+ colorScheme : colorSchemeHint ,
157+ timeZone : timeZoneHint ,
158+ reducedMotion : reducedMotionHint ,
159+ } )
160+
161+ // Test with empty cookie values
162+ const request = new Request ( 'https://example.com' , {
163+ headers : {
164+ Cookie : 'CH-prefers-color-scheme=; CH-time-zone=; CH-reduced-motion=' ,
165+ } ,
166+ } )
167+
168+ // Empty values should fall back to fallback values
169+ const result = hints . getHints ( request )
170+ assert . strictEqual ( result . colorScheme , colorSchemeHint . fallback )
171+ assert . strictEqual ( result . timeZone , timeZoneHint . fallback )
172+ assert . strictEqual ( result . reducedMotion , reducedMotionHint . fallback )
173+ } )
174+
175+ test ( 'client script includes infinite refresh prevention' , ( ) => {
176+ const hints = getHintUtils ( {
177+ colorScheme : colorSchemeHint ,
178+ timeZone : timeZoneHint ,
179+ reducedMotion : reducedMotionHint ,
180+ } )
181+
182+ const checkScript = hints . getClientHintCheckScript ( )
183+
184+ // Should include sessionStorage check for infinite refresh prevention
185+ assert . ok ( checkScript . includes ( 'sessionStorage.getItem' ) )
186+ assert . ok ( checkScript . includes ( 'clientHintReloadAttempts' ) )
187+ assert . ok ( checkScript . includes ( 'Too many client hint reload attempts' ) )
188+
189+ // Should include try-catch around decodeURIComponent
190+ assert . ok ( checkScript . includes ( 'try' ) )
191+ assert . ok ( checkScript . includes ( 'catch' ) )
192+ assert . ok ( checkScript . includes ( 'decodeURIComponent' ) )
193+ } )
0 commit comments