@@ -155,6 +155,13 @@ function countOccurrences(value: string, needle: string): number {
155155 return value . split ( needle ) . length - 1 ;
156156}
157157
158+ function expectSlashlessRootRedirectBeforeBase ( html : string , baseHref : string ) : void {
159+ const redirectIndex = html . indexOf ( "location.replace(location.pathname" ) ;
160+ const baseIndex = html . indexOf ( `<base href="${ baseHref } "` ) ;
161+ expect ( redirectIndex ) . toBeGreaterThanOrEqual ( 0 ) ;
162+ expect ( baseIndex ) . toBeGreaterThan ( redirectIndex ) ;
163+ }
164+
158165async function createStaticTestServer (
159166 options : {
160167 files ?: Record < string , string > ;
@@ -231,7 +238,7 @@ describe("createOrpcServer", () => {
231238 expect ( uiRes . status ) . toBe ( 200 ) ;
232239 const uiText = await uiRes . text ( ) ;
233240 expect ( uiText ) . toContain ( "mux" ) ;
234- expect ( uiText ) . toContain ( '<base href="/"' ) ;
241+ expect ( uiText ) . toContain ( '<base href="./../.. /"' ) ;
235242
236243 const apiRes = await fetch ( `${ server . baseUrl } /api/not-a-real-route` ) ;
237244 expect ( apiRes . status ) . toBe ( 404 ) ;
@@ -248,7 +255,18 @@ describe("createOrpcServer", () => {
248255 const rootRes = await fetch ( `${ server . baseUrl } /` ) ;
249256 expect ( rootRes . status ) . toBe ( 200 ) ;
250257 const rootHtml = await rootRes . text ( ) ;
251- expect ( countOccurrences ( rootHtml , '<base href="/" />' ) ) . toBe ( 1 ) ;
258+ expect ( countOccurrences ( rootHtml , '<base href="./" />' ) ) . toBe ( 1 ) ;
259+ expectSlashlessRootRedirectBeforeBase ( rootHtml , "./" ) ;
260+
261+ const deepRouteRes = await fetch ( `${ server . baseUrl } /some/spa/route` ) ;
262+ expect ( deepRouteRes . status ) . toBe ( 200 ) ;
263+ const deepRouteHtml = await deepRouteRes . text ( ) ;
264+ expect ( deepRouteHtml ) . toContain ( '<base href="./../../" />' ) ;
265+ expect ( deepRouteHtml ) . not . toContain ( "location.replace(location.pathname" ) ;
266+
267+ const directoryRouteRes = await fetch ( `${ server . baseUrl } /some/spa/route/` ) ;
268+ expect ( directoryRouteRes . status ) . toBe ( 200 ) ;
269+ expect ( await directoryRouteRes . text ( ) ) . toContain ( '<base href="./../../../" />' ) ;
252270
253271 const forwardedPrefixRes = await fetch ( `${ server . baseUrl } /some/spa/route` , {
254272 headers : { "X-Forwarded-Prefix" : APP_PROXY_BASE_PATH } ,
@@ -297,6 +315,23 @@ describe("createOrpcServer", () => {
297315 expect ( prefixedAssetRes . status ) . toBe ( 200 ) ;
298316 expect ( await prefixedAssetRes . text ( ) ) . toBe ( await rootAssetRes . text ( ) ) ;
299317
318+ const prefixedRootRes = await fetch ( `${ server . baseUrl } ${ APP_PROXY_BASE_PATH } ` ) ;
319+ expect ( prefixedRootRes . status ) . toBe ( 200 ) ;
320+ const prefixedRootHtml = await prefixedRootRes . text ( ) ;
321+ expect ( prefixedRootHtml ) . toContain ( `<base href="${ APP_PROXY_BASE_PATH } /" />` ) ;
322+ expectSlashlessRootRedirectBeforeBase ( prefixedRootHtml , `${ APP_PROXY_BASE_PATH } /` ) ;
323+
324+ const coderUrlRes = await fetch (
325+ `${ server . baseUrl } /@admin/mux-workspace-095801.main/apps/mux/?token=redacted`
326+ ) ;
327+ expect ( coderUrlRes . status ) . toBe ( 200 ) ;
328+ const coderUrlHtml = await coderUrlRes . text ( ) ;
329+ expect ( coderUrlHtml ) . toContain ( '<base href="/@admin/mux-workspace-095801.main/apps/mux/" />' ) ;
330+ expectSlashlessRootRedirectBeforeBase (
331+ coderUrlHtml ,
332+ "/@admin/mux-workspace-095801.main/apps/mux/"
333+ ) ;
334+
300335 const prefixedSpaRes = await fetch ( `${ server . baseUrl } ${ APP_PROXY_BASE_PATH } /settings` ) ;
301336 expect ( prefixedSpaRes . status ) . toBe ( 200 ) ;
302337 expect ( await prefixedSpaRes . text ( ) ) . toContain ( `<base href="${ APP_PROXY_BASE_PATH } /" />` ) ;
@@ -323,7 +358,7 @@ describe("createOrpcServer", () => {
323358
324359 const falsePositiveRes = await fetch ( `${ server . baseUrl } /projects/apps/other` ) ;
325360 expect ( falsePositiveRes . status ) . toBe ( 200 ) ;
326- expect ( await falsePositiveRes . text ( ) ) . toContain ( '<base href="/" />' ) ;
361+ expect ( await falsePositiveRes . text ( ) ) . toContain ( '<base href="./../.. /" />' ) ;
327362 } finally {
328363 await close ( ) ;
329364 }
@@ -477,8 +512,10 @@ describe("createOrpcServer", () => {
477512 expect ( uiRes . status ) . toBe ( 200 ) ;
478513 const uiText = await uiRes . text ( ) ;
479514
515+ expect ( rootHtml ) . toContain ( '<base href="./"' ) ;
516+ expect ( uiText ) . toContain ( '<base href="./../../"' ) ;
517+
480518 for ( const html of [ rootHtml , uiText ] ) {
481- expect ( html ) . toContain ( '<base href="/"' ) ;
482519 expect ( html ) . toContain ( "window.__MUX_PROXY_URI_TEMPLATE__ =" ) ;
483520 expect ( html ) . toContain (
484521 'window.__MUX_PROXY_URI_TEMPLATE__ = "https://proxy-{{port}}.example.test/path\\u003c/script>";'
0 commit comments