@@ -82,6 +82,20 @@ describe('SchemeUrlSync', () => {
8282 expect ( resolveInitialSchemeSearch ( '?utm_source=readme' , null ) ) . toBe ( '?utm_source=readme' ) ;
8383 } ) ;
8484
85+ it ( 'normalizes current search strings that omit the leading question mark' , ( ) => {
86+ expect ( resolveInitialSchemeSearch ( 'utm_source=readme' , null ) ) . toBe ( '?utm_source=readme' ) ;
87+ } ) ;
88+
89+ it ( 'ignores persisted search read errors and keeps the current URL search' , ( ) => {
90+ const storage = {
91+ getItem : vi . fn ( ( ) => {
92+ throw new Error ( 'storage unavailable' ) ;
93+ } ) ,
94+ } ;
95+
96+ expect ( resolveInitialSchemeSearch ( '?utm_source=readme' , storage ) ) . toBe ( '?utm_source=readme' ) ;
97+ } ) ;
98+
8599 it ( 'falls back to persisted scheme params and preserves unrelated URL params' , ( ) => {
86100 const storage = {
87101 getItem : vi . fn ( ( ) => '?hue=45&dyeScope=all' ) ,
@@ -91,6 +105,14 @@ describe('SchemeUrlSync', () => {
91105 . toBe ( '?utm_source=readme&hue=45&dyeScope=all' ) ;
92106 } ) ;
93107
108+ it ( 'ignores persisted search values that do not contain any actual params' , ( ) => {
109+ const storage = {
110+ getItem : vi . fn ( ( ) => '?' ) ,
111+ } ;
112+
113+ expect ( resolveInitialSchemeSearch ( '' , storage ) ) . toBe ( '' ) ;
114+ } ) ;
115+
94116 it ( 'hydrates the store from persisted search when the URL has no scheme params' , ( ) => {
95117 const pinia = createPinia ( ) ;
96118 const storage = {
@@ -122,6 +144,76 @@ describe('SchemeUrlSync', () => {
122144 ) ;
123145 } ) ;
124146
147+ it ( 'hydrates from the string overload using browser fallbacks in non-browser tests' , ( ) => {
148+ const pinia = createPinia ( ) ;
149+
150+ const schemeStore = hydrateSchemeStoreFromLocation ( pinia , '?hue=12&dyeScope=all' ) ;
151+
152+ expect ( schemeStore . scheme . hue ) . toBe ( 12 ) ;
153+ expect ( schemeStore . scheme . dyeScope ) . toBe ( 'all' ) ;
154+ } ) ;
155+
156+ it ( 'hydrates from global browser objects when options are omitted' , ( ) => {
157+ const pinia = createPinia ( ) ;
158+ const originalWindow = globalThis . window ;
159+ const hadWindow = Object . prototype . hasOwnProperty . call ( globalThis , 'window' ) ;
160+ const history = {
161+ state : { from : 'browser' } ,
162+ replaceState : vi . fn ( ) ,
163+ } ;
164+
165+ globalThis . window = {
166+ location : {
167+ pathname : '/4bit/' ,
168+ search : '' ,
169+ hash : '#preview' ,
170+ } ,
171+ history,
172+ localStorage : {
173+ getItem : vi . fn ( ( ) => '?hue=33' ) ,
174+ } ,
175+ } ;
176+
177+ try {
178+ const schemeStore = hydrateSchemeStoreFromLocation ( pinia ) ;
179+
180+ expect ( schemeStore . scheme . hue ) . toBe ( 33 ) ;
181+ expect ( history . replaceState ) . toHaveBeenCalledWith (
182+ history . state ,
183+ '' ,
184+ '/4bit/?hue=33#preview'
185+ ) ;
186+ } finally {
187+ if ( hadWindow ) {
188+ globalThis . window = originalWindow ;
189+ } else {
190+ delete globalThis . window ;
191+ }
192+ }
193+ } ) ;
194+
195+ it ( 'does not replace history during hydration when the URL already matches' , ( ) => {
196+ const pinia = createPinia ( ) ;
197+ const history = {
198+ state : { from : 'test' } ,
199+ replaceState : vi . fn ( ) ,
200+ } ;
201+ const location = {
202+ pathname : '/4bit/' ,
203+ search : '?hue=12' ,
204+ hash : '#preview' ,
205+ } ;
206+
207+ hydrateSchemeStoreFromLocation ( pinia , {
208+ search : '?hue=12' ,
209+ storage : null ,
210+ location,
211+ history,
212+ } ) ;
213+
214+ expect ( history . replaceState ) . not . toHaveBeenCalled ( ) ;
215+ } ) ;
216+
125217 it ( 'persists the current scheme search for future visits' , ( ) => {
126218 const scheme = createDefaultScheme ( ) ;
127219 scheme . hue = 10 ;
@@ -180,4 +272,47 @@ describe('SchemeUrlSync', () => {
180272 '/4bit/?hue=10'
181273 ) ;
182274 } ) ;
275+
276+ it ( 'does not replace history when the current URL already matches the scheme' , ( ) => {
277+ const scheme = createDefaultScheme ( ) ;
278+ scheme . hue = 10 ;
279+ const history = {
280+ state : null ,
281+ replaceState : vi . fn ( ) ,
282+ } ;
283+
284+ new SchemeUrlSync ( {
285+ schemeStore : { scheme } ,
286+ location : {
287+ pathname : '/4bit/' ,
288+ search : '?hue=10' ,
289+ hash : '' ,
290+ } ,
291+ history,
292+ storage : null ,
293+ } ) . updateLocation ( scheme ) ;
294+
295+ expect ( history . replaceState ) . not . toHaveBeenCalled ( ) ;
296+ } ) ;
297+
298+ it ( 'keeps the URL empty for the default scheme when no extra params are present' , ( ) => {
299+ const scheme = createDefaultScheme ( ) ;
300+ const history = {
301+ state : null ,
302+ replaceState : vi . fn ( ) ,
303+ } ;
304+
305+ new SchemeUrlSync ( {
306+ schemeStore : { scheme } ,
307+ location : {
308+ pathname : '/4bit/' ,
309+ search : '' ,
310+ hash : '' ,
311+ } ,
312+ history,
313+ storage : null ,
314+ } ) . updateLocation ( scheme ) ;
315+
316+ expect ( history . replaceState ) . not . toHaveBeenCalled ( ) ;
317+ } ) ;
183318} ) ;
0 commit comments