1+ import { mkdir , mkdtemp , rm , writeFile } from "node:fs/promises" ;
2+ import { tmpdir } from "node:os" ;
3+ import { dirname , join } from "node:path" ;
4+ import { pathToFileURL } from "node:url" ;
5+
16import { describe , expect , it , vi } from "vitest" ;
27
3- import { injectCoreRoutes } from "../../../src/astro/integration/routes.js" ;
8+ import {
9+ hasUserDefinedPublicRoute ,
10+ injectCoreRoutes ,
11+ } from "../../../src/astro/integration/routes.js" ;
412import { GET as getMediaFile } from "../../../src/astro/routes/api/media/file/[...key].js" ;
513
614function mockMediaContext ( key : string | undefined ) {
@@ -24,6 +32,27 @@ function mockMediaContext(key: string | undefined) {
2432}
2533
2634describe ( "core media route injection" , ( ) => {
35+ async function withTempSrcDir ( files : Record < string , string > , fn : ( srcDir : URL ) => void ) {
36+ const root = await mkdtemp ( join ( tmpdir ( ) , "emdash-routes-" ) ) ;
37+ try {
38+ const srcDir = join ( root , "src" ) ;
39+ for ( const [ filePath , contents ] of Object . entries ( files ) ) {
40+ const fullPath = join ( srcDir , filePath ) ;
41+ await mkdir ( dirname ( fullPath ) , { recursive : true } ) ;
42+ await writeFile ( fullPath , contents ) ;
43+ }
44+ fn ( pathToFileURL ( srcDir ) ) ;
45+ } finally {
46+ await rm ( root , { recursive : true , force : true } ) ;
47+ }
48+ }
49+
50+ function collectRoutePatterns ( srcDir ?: URL ) : string [ ] {
51+ const routes : Array < { pattern : string ; entrypoint : string } > = [ ] ;
52+ injectCoreRoutes ( ( route ) => routes . push ( route ) , { srcDir } ) ;
53+ return routes . map ( ( route ) => route . pattern ) ;
54+ }
55+
2756 it ( "uses a catch-all media file route so storage keys can contain slashes" , ( ) => {
2857 const routes : Array < { pattern : string ; entrypoint : string } > = [ ] ;
2958 injectCoreRoutes ( ( route ) => {
@@ -43,6 +72,63 @@ describe("core media route injection", () => {
4372 } ) ,
4473 ) ;
4574 } ) ;
75+
76+ it ( "injects default root SEO routes when the site does not define them" , ( ) => {
77+ const routes = collectRoutePatterns ( ) ;
78+
79+ expect ( routes ) . toContain ( "/robots.txt" ) ;
80+ expect ( routes ) . toContain ( "/sitemap.xml" ) ;
81+ expect ( routes ) . toContain ( "/sitemap-[collection].xml" ) ;
82+ } ) ;
83+
84+ it ( "skips root SEO routes that are defined by the site" , async ( ) => {
85+ await withTempSrcDir (
86+ {
87+ "pages/robots.txt.ts" : "export const GET = () => new Response('');" ,
88+ "pages/sitemap.xml.ts" : "export const GET = () => new Response('');" ,
89+ } ,
90+ ( srcDir ) => {
91+ const routes = collectRoutePatterns ( srcDir ) ;
92+
93+ expect ( routes ) . not . toContain ( "/robots.txt" ) ;
94+ expect ( routes ) . not . toContain ( "/sitemap.xml" ) ;
95+ expect ( routes ) . toContain ( "/sitemap-[collection].xml" ) ;
96+ } ,
97+ ) ;
98+ } ) ;
99+
100+ it ( "detects index route files for root public route overrides" , async ( ) => {
101+ await withTempSrcDir (
102+ {
103+ "pages/robots.txt/index.ts" : "export const GET = () => new Response('');" ,
104+ } ,
105+ ( srcDir ) => {
106+ const routes = collectRoutePatterns ( srcDir ) ;
107+
108+ expect ( hasUserDefinedPublicRoute ( srcDir , "robots.txt" ) ) . toBe ( true ) ;
109+ expect ( hasUserDefinedPublicRoute ( srcDir , "sitemap.xml" ) ) . toBe ( false ) ;
110+ expect ( routes ) . not . toContain ( "/robots.txt" ) ;
111+ expect ( routes ) . toContain ( "/sitemap.xml" ) ;
112+ } ,
113+ ) ;
114+ } ) ;
115+
116+ it ( "detects markdown and html route files for root public route overrides" , async ( ) => {
117+ await withTempSrcDir (
118+ {
119+ "pages/robots.txt.md" : "# Robots" ,
120+ "pages/sitemap.xml/index.html" : "<html></html>" ,
121+ } ,
122+ ( srcDir ) => {
123+ const routes = collectRoutePatterns ( srcDir ) ;
124+
125+ expect ( hasUserDefinedPublicRoute ( srcDir , "robots.txt" ) ) . toBe ( true ) ;
126+ expect ( hasUserDefinedPublicRoute ( srcDir , "sitemap.xml" ) ) . toBe ( true ) ;
127+ expect ( routes ) . not . toContain ( "/robots.txt" ) ;
128+ expect ( routes ) . not . toContain ( "/sitemap.xml" ) ;
129+ } ,
130+ ) ;
131+ } ) ;
46132} ) ;
47133
48134describe ( "media file catch-all route" , ( ) => {
0 commit comments