@@ -241,6 +241,191 @@ ROUTING_UNIVERSES.forEach((universe) => {
241241 expect ( navigateSpy ) . toHaveBeenCalledTimes ( 1 ) ;
242242 expect ( ruPath ( ) ) . toBe ( '/punch-line' ) ;
243243 } ) ;
244+
245+ describe ( "Constructor Signatures" , ( ) => {
246+ test ( "Should work with explicit hash constructor (hash, options)." , ( ) => {
247+ // Arrange.
248+ location . navigate ( '/explicit-hash' , { hash : universe . hash } ) ;
249+ navigateSpy . mockClear ( ) ;
250+
251+ // Act.
252+ const redirector = new Redirector ( universe . hash , { replace : false } ) ;
253+ redirector . redirections . push ( {
254+ pattern : '/explicit-hash' ,
255+ href : '/redirected-explicit'
256+ } ) ;
257+ flushSync ( ) ;
258+
259+ // Assert.
260+ expect ( navigateSpy ) . toHaveBeenCalledWith ( '/redirected-explicit' , expect . objectContaining ( {
261+ hash : resolvedHash ,
262+ replace : false
263+ } ) ) ;
264+ expect ( ruPath ( ) ) . toBe ( '/redirected-explicit' ) ;
265+ } ) ;
266+
267+ test ( "Should resolve hash correctly when using explicit constructor." , ( ) => {
268+ // This test works for all universes
269+ // Arrange.
270+ location . navigate ( '/hash-resolution-test' , { hash : universe . hash } ) ;
271+ navigateSpy . mockClear ( ) ;
272+
273+ // Act.
274+ const redirector = new Redirector ( universe . hash , { replace : true } ) ;
275+ redirector . redirections . push ( {
276+ pattern : '/hash-resolution-test' ,
277+ href : '/hash-resolved'
278+ } ) ;
279+ flushSync ( ) ;
280+
281+ // Assert.
282+ expect ( navigateSpy ) . toHaveBeenCalledWith ( '/hash-resolved' , expect . objectContaining ( {
283+ hash : resolvedHash // Should match the explicitly provided hash
284+ } ) ) ;
285+ expect ( ruPath ( ) ) . toBe ( '/hash-resolved' ) ;
286+ } ) ;
287+ } ) ;
288+
289+ describe ( "Options-Only Constructor" , ( ) => {
290+ // Only test the options-only constructor for universes that have a defaultHash
291+ // The options-only constructor is designed to work with the "default routing universe"
292+
293+ if ( universe . defaultHash !== undefined ) {
294+ test ( "Should work with default hash constructor (options only)." , ( ) => {
295+ // Arrange.
296+ location . navigate ( '/default-hash' , { hash : universe . hash } ) ;
297+ navigateSpy . mockClear ( ) ;
298+
299+ // Act.
300+ const redirector = new Redirector ( { replace : false } ) ;
301+ redirector . redirections . push ( {
302+ pattern : '/default-hash' ,
303+ href : '/redirected-default'
304+ } ) ;
305+ flushSync ( ) ;
306+
307+ // Assert.
308+ expect ( navigateSpy ) . toHaveBeenCalledWith ( '/redirected-default' , expect . objectContaining ( {
309+ hash : resolveHashValue ( undefined ) , // Should use the library's defaultHash
310+ replace : false
311+ } ) ) ;
312+ } ) ;
313+
314+ test ( "Should work with minimal options-only constructor." , ( ) => {
315+ // Arrange.
316+ location . navigate ( '/minimal-options' , { hash : universe . hash } ) ;
317+ navigateSpy . mockClear ( ) ;
318+
319+ // Act.
320+ const redirector = new Redirector ( { } ) ; // Empty options object
321+ redirector . redirections . push ( {
322+ pattern : '/minimal-options' ,
323+ href : '/redirected-minimal'
324+ } ) ;
325+ flushSync ( ) ;
326+
327+ // Assert.
328+ expect ( navigateSpy ) . toHaveBeenCalledWith ( '/redirected-minimal' , expect . objectContaining ( {
329+ hash : resolveHashValue ( undefined ) , // Should use the library's defaultHash
330+ replace : true // Should use default replace: true
331+ } ) ) ;
332+ } ) ;
333+ } else {
334+ test ( "Should skip options-only constructor tests for explicit hash universes." , ( ) => {
335+ // These universes (PR, HR, MHR) use explicit hash values and don't set a defaultHash
336+ // The options-only constructor wouldn't work correctly here since it relies on
337+ // the library's defaultHash matching the universe being tested
338+ expect ( universe . text ) . toMatch ( / ^ ( P R | H R | M H R ) $ / ) ;
339+ } ) ;
340+ }
341+ } ) ;
342+ } ) ;
343+ } ) ;
344+
345+ describe ( "Options-Only Constructor with Matching Library Defaults" , ( ) => {
346+ // Test the options-only constructor when the library is properly initialized
347+ // with matching defaultHash values for HR and MHR scenarios
348+
349+ describe ( "Hash Routing Universe" , ( ) => {
350+ let cleanup : ( ) => void ;
351+ let navigateSpy : MockInstance < typeof location . navigate > ;
352+
353+ beforeAll ( ( ) => {
354+ // Initialize library with hash routing as default
355+ cleanup = init ( { defaultHash : true } ) ;
356+ navigateSpy = vi . spyOn ( location , 'navigate' ) ;
357+ } ) ;
358+
359+ afterAll ( ( ) => {
360+ cleanup ( ) ;
361+ } ) ;
362+
363+ afterEach ( ( ) => {
364+ location . goTo ( '/' ) ;
365+ vi . clearAllMocks ( ) ;
366+ } ) ;
367+
368+ test ( "Should work with options-only constructor when library default matches hash routing." , ( ) => {
369+ // Arrange.
370+ location . navigate ( '/hash-default-test' , { hash : true } ) ;
371+ navigateSpy . mockClear ( ) ;
372+
373+ // Act.
374+ const redirector = new Redirector ( { replace : false } ) ;
375+ redirector . redirections . push ( {
376+ pattern : '/hash-default-test' ,
377+ href : '/hash-redirected'
378+ } ) ;
379+ flushSync ( ) ;
380+
381+ // Assert.
382+ expect ( navigateSpy ) . toHaveBeenCalledWith ( '/hash-redirected' , expect . objectContaining ( {
383+ hash : true , // Should use the library's defaultHash (true)
384+ replace : false
385+ } ) ) ;
386+ expect ( location . hashPaths . single ) . toBe ( '/hash-redirected' ) ;
387+ } ) ;
388+ } ) ;
389+
390+ describe ( "Multi-Hash Routing Universe" , ( ) => {
391+ let cleanup : ( ) => void ;
392+ let navigateSpy : MockInstance < typeof location . navigate > ;
393+
394+ beforeAll ( ( ) => {
395+ // Initialize library with multi-hash routing as default
396+ cleanup = init ( { defaultHash : 'p1' , hashMode : 'multi' } ) ;
397+ navigateSpy = vi . spyOn ( location , 'navigate' ) ;
398+ } ) ;
399+
400+ afterAll ( ( ) => {
401+ cleanup ( ) ;
402+ } ) ;
403+
404+ afterEach ( ( ) => {
405+ location . goTo ( '/' ) ;
406+ vi . clearAllMocks ( ) ;
407+ } ) ;
408+
409+ test ( "Should work with options-only constructor when library default matches multi-hash routing." , ( ) => {
410+ // Arrange.
411+ location . navigate ( '/multi-hash-default-test' , { hash : 'p1' } ) ;
412+ navigateSpy . mockClear ( ) ;
413+
414+ // Act.
415+ const redirector = new Redirector ( { replace : false } ) ;
416+ redirector . redirections . push ( {
417+ pattern : '/multi-hash-default-test' ,
418+ href : '/multi-hash-redirected'
419+ } ) ;
420+ flushSync ( ) ;
421+
422+ // Assert.
423+ expect ( navigateSpy ) . toHaveBeenCalledWith ( '/multi-hash-redirected' , expect . objectContaining ( {
424+ hash : 'p1' , // Should use the library's defaultHash ('p1')
425+ replace : false
426+ } ) ) ;
427+ expect ( location . hashPaths . p1 ) . toBe ( '/multi-hash-redirected' ) ;
428+ } ) ;
244429 } ) ;
245430} ) ;
246431
0 commit comments