@@ -646,7 +646,7 @@ describe('dedupe', () => {
646646 expect ( headTags ) . toContain ( 'atom.xml' )
647647 } )
648648
649- it ( 'bare alternate without hreflang or type falls through to generic deduping ' , async ( ) => {
649+ it ( 'bare alternate without hreflang or type dedupes by href ' , async ( ) => {
650650 const head = createServerHeadWithContext ( )
651651 head . push ( {
652652 link : [
@@ -655,7 +655,101 @@ describe('dedupe', () => {
655655 ] ,
656656 } )
657657 const { headTags } = await renderSSRHead ( head )
658- // both should exist since no dedupe key matched
658+ // both should exist since they have different hrefs
659659 expect ( headTags . split ( 'rel="alternate"' ) . length ) . toBe ( 3 )
660660 } )
661+
662+ it ( 'dedupes bare alternate links with same href on hydration' , async ( ) => {
663+ const head = createServerHeadWithContext ( )
664+ head . push ( {
665+ link : [
666+ { rel : 'alternate' , href : '/' } ,
667+ ] ,
668+ } )
669+ // Simulate hydration - push the same link again
670+ head . push ( {
671+ link : [
672+ { rel : 'alternate' , href : '/' } ,
673+ ] ,
674+ } )
675+ const { headTags } = await renderSSRHead ( head )
676+ // Should only have 1 alternate link
677+ expect ( headTags . split ( 'rel="alternate"' ) . length ) . toBe ( 2 )
678+ } )
679+
680+ it ( 'dedupes bare alternate links without href on hydration' , async ( ) => {
681+ const head = createServerHeadWithContext ( )
682+ head . push ( {
683+ link : [
684+ { rel : 'alternate' } ,
685+ ] ,
686+ } )
687+ // Simulate hydration - push the same link again
688+ head . push ( {
689+ link : [
690+ { rel : 'alternate' } ,
691+ ] ,
692+ } )
693+ const { headTags } = await renderSSRHead ( head )
694+ // Should only have 1 alternate link
695+ expect ( headTags . split ( 'rel="alternate"' ) . length ) . toBe ( 2 )
696+ } )
697+
698+ it ( 'dedupes alternate links by id (i18n use case)' , async ( ) => {
699+ const head = createServerHeadWithContext ( )
700+ head . push ( {
701+ link : [
702+ { id : 'i18n-alt-nl' , rel : 'alternate' , href : 'http://localhost:3000/nl/products/big-chair' , hreflang : 'nl' } ,
703+ ] ,
704+ } )
705+ // Simulate dynamic parameter translation update
706+ head . push ( {
707+ link : [
708+ { id : 'i18n-alt-nl' , rel : 'alternate' , href : 'http://localhost:3000/nl/products/grote-stoel' , hreflang : 'nl' } ,
709+ ] ,
710+ } )
711+ const { headTags } = await renderSSRHead ( head )
712+ // Should only have 1 alternate link - last one wins via hreflang dedupe
713+ expect ( headTags . split ( 'rel="alternate"' ) . length ) . toBe ( 2 )
714+ expect ( headTags ) . toContain ( 'grote-stoel' )
715+ expect ( headTags ) . not . toContain ( 'big-chair' )
716+ } )
717+
718+ it ( 'alternate links with key dedupe by key' , async ( ) => {
719+ const head = createServerHeadWithContext ( )
720+ head . push ( {
721+ link : [
722+ { key : 'my-alt' , rel : 'alternate' , href : 'https://example.com/a' } ,
723+ ] ,
724+ } )
725+ head . push ( {
726+ link : [
727+ { key : 'my-alt' , rel : 'alternate' , href : 'https://example.com/b' } ,
728+ ] ,
729+ } )
730+ const { headTags } = await renderSSRHead ( head )
731+ // Should have 1 alternate link deduped by key - last one wins
732+ expect ( headTags . split ( 'rel="alternate"' ) . length ) . toBe ( 2 )
733+ expect ( headTags ) . toContain ( 'https://example.com/b' )
734+ expect ( headTags ) . not . toContain ( 'https://example.com/a' )
735+ } )
736+
737+ it ( 'alternate links with id dedupe by id when no hreflang' , async ( ) => {
738+ const head = createServerHeadWithContext ( )
739+ head . push ( {
740+ link : [
741+ { id : 'my-feed' , rel : 'alternate' , href : 'https://example.com/feed-v1.xml' } ,
742+ ] ,
743+ } )
744+ head . push ( {
745+ link : [
746+ { id : 'my-feed' , rel : 'alternate' , href : 'https://example.com/feed-v2.xml' } ,
747+ ] ,
748+ } )
749+ const { headTags } = await renderSSRHead ( head )
750+ // Should have 1 alternate link deduped by id - last one wins
751+ expect ( headTags . split ( 'rel="alternate"' ) . length ) . toBe ( 2 )
752+ expect ( headTags ) . toContain ( 'feed-v2.xml' )
753+ expect ( headTags ) . not . toContain ( 'feed-v1.xml' )
754+ } )
661755} )
0 commit comments