@@ -528,7 +528,7 @@ describe('dedupe', () => {
528528 expect ( headTags ) . toContain ( 'https://example.com/en/page' )
529529 } )
530530
531- it ( 'allows different hrefs for same hreflang ( different pages) ' , async ( ) => {
531+ it ( 'dedupes same hreflang with different hrefs ' , async ( ) => {
532532 const head = createServerHeadWithContext ( )
533533 head . push ( {
534534 link : [
@@ -539,7 +539,7 @@ describe('dedupe', () => {
539539 } ,
540540 ] ,
541541 } )
542- // Different href for same hreflang should be treated as different link
542+ // Same hreflang should be deduped regardless of href
543543 head . push ( {
544544 link : [
545545 {
@@ -550,10 +550,10 @@ describe('dedupe', () => {
550550 ] ,
551551 } )
552552 const { headTags } = await renderSSRHead ( head )
553- // Should have 2 alternate links since hrefs are different
554- expect ( headTags . split ( 'rel="alternate"' ) . length ) . toBe ( 3 ) // 2 tags + 1 base = 3 parts
555- expect ( headTags ) . toContain ( 'https://example.com/en/page1' )
553+ // Should have 1 alternate link - last one wins
554+ expect ( headTags . split ( 'rel="alternate"' ) . length ) . toBe ( 2 )
556555 expect ( headTags ) . toContain ( 'https://example.com/en/page2' )
556+ expect ( headTags ) . not . toContain ( 'https://example.com/en/page1' )
557557 } )
558558
559559 it ( 'dedupes alternate links without hreflang using href' , async ( ) => {
@@ -613,4 +613,49 @@ describe('dedupe', () => {
613613 expect ( headTags ) . toContain ( 'hreflang="de"' )
614614 expect ( headTags ) . toContain ( 'hreflang="fr"' )
615615 } )
616+
617+ it ( 'dedupes RSS feeds with same type' , async ( ) => {
618+ const head = createServerHeadWithContext ( )
619+ head . push ( {
620+ link : [
621+ { rel : 'alternate' , type : 'application/rss+xml' , href : 'https://example.com/feed.xml' , title : 'RSS Feed' } ,
622+ ] ,
623+ } )
624+ head . push ( {
625+ link : [
626+ { rel : 'alternate' , type : 'application/rss+xml' , href : 'https://example.com/feed2.xml' , title : 'RSS Feed 2' } ,
627+ ] ,
628+ } )
629+ const { headTags } = await renderSSRHead ( head )
630+ expect ( headTags . split ( 'rel="alternate"' ) . length ) . toBe ( 2 )
631+ expect ( headTags ) . toContain ( 'feed2.xml' )
632+ expect ( headTags ) . not . toContain ( 'feed.xml"' )
633+ } )
634+
635+ it ( 'allows RSS and Atom feeds to coexist' , async ( ) => {
636+ const head = createServerHeadWithContext ( )
637+ head . push ( {
638+ link : [
639+ { rel : 'alternate' , type : 'application/rss+xml' , href : 'https://example.com/rss.xml' , title : 'RSS' } ,
640+ { rel : 'alternate' , type : 'application/atom+xml' , href : 'https://example.com/atom.xml' , title : 'Atom' } ,
641+ ] ,
642+ } )
643+ const { headTags } = await renderSSRHead ( head )
644+ expect ( headTags . split ( 'rel="alternate"' ) . length ) . toBe ( 3 )
645+ expect ( headTags ) . toContain ( 'rss.xml' )
646+ expect ( headTags ) . toContain ( 'atom.xml' )
647+ } )
648+
649+ it ( 'bare alternate without hreflang or type falls through to generic deduping' , async ( ) => {
650+ const head = createServerHeadWithContext ( )
651+ head . push ( {
652+ link : [
653+ { rel : 'alternate' , href : 'https://example.com/a' } ,
654+ { rel : 'alternate' , href : 'https://example.com/b' } ,
655+ ] ,
656+ } )
657+ const { headTags } = await renderSSRHead ( head )
658+ // both should exist since no dedupe key matched
659+ expect ( headTags . split ( 'rel="alternate"' ) . length ) . toBe ( 3 )
660+ } )
616661} )
0 commit comments