Skip to content

bake test harness: derive multi-HTML route keys from posix paths - #37892

Open
robobun wants to merge 2 commits into
mainfrom
farm/5b90d0eb/bake-harness-posix-html-routes
Open

bake test harness: derive multi-HTML route keys from posix paths#37892
robobun wants to merge 2 commits into
mainfrom
farm/5b90d0eb/bake-harness-posix-html-routes

Conversation

@robobun

@robobun robobun commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator

Problem

  • On Windows, a bake harness fixture with several HTML files answered the harness's 404 fallback for any nested one (GET /docs, GET /docs/guide).
  • On every platform, a top-level index.html in such a fixture was served at /index, not /.
  • The route keys were built from platform-native paths, so on Windows they came out as "/docs\\index"; the /index strip was a first-occurrence substring replace, so it missed a top-level index.html.
  • Surfaced in bake: speed up the css dev server tests by sharing servers and asserting served stylesheets #37868, which keeps one case on a separate server to work around this.

Fix

  • Normalize separators once, before both imports and keys are built, then derive each key per segment: strip .html, drop a trailing index segment.
  • Correct because the keys are now the routes bun ./index.html ./docs/index.html ./docs/guide.html itself serves (/, /docs, /docs/guide), which is what this branch imitates.
  • No test on main depends on the old keys: existing multi-HTML fixtures use flat files, whose routes are unchanged.
  • Verification: a new test fetches /, /about, /docs, /docs/guide and expects 404 at /docs/index. It fails without the harness change on every platform and passes on linux-x64 and windows-x64; the other tests using this code path were re-run on both and pass.

Background

  • The bake harness behind devTest/prodTest writes a bun.app.ts per fixture that imports each HTML file and exports a server config; this PR only changes that generated file.
  • In that config, static maps a route string to an imported HTML module. String keys match exactly, so a key with a backslash in it is never hit.
  • One HTML file goes on the /* catch-all; several get one exact route each, imitating bun ./a.html ./b.html, which serves a file at its path minus .html and an index.html at its directory (docs/bundler/html-static.mdx).
  • The relative paths come from path.relative, which uses the platform separator, so on Windows nested paths carry backslashes until converted.
Original description

What

test/bake/bake-harness.ts generates a bun.app.ts for every devTest/prodTest fixture that contains HTML files. With one HTML file it registers a /* catch-all; with several, indexHtmlScript registers one static route per file and derives each key from the result of path.relative(mainDir, file). Only the import line normalized path.sep; the key derivation did not, so on Windows any nested HTML file on a multi-route server was registered under a key containing a backslash and was unreachable. The same line also mapped a top-level index.html to /index.

Generated bun.app.ts for a fixture with about.html, docs/index.html and docs/guide.html on the Windows box, before this change (GET /docs and GET /docs/guide both returned the harness's 404 fallback):

import html0 from "./about.html";
import html1 from "./docs/index.html";
import html2 from "./docs/guide.html";
export default {
  static: {
    "/about": html0,
    "/docs\\index": html1,
    "/docs\\guide": html2,
  },
  ...

After: "/about", "/docs", "/docs/guide".

Fix

Normalize the separators once for both the import specifiers and the route keys, and derive the key per path segment (strip .html, drop a trailing index segment). That gives the routes bun ./index.html ./docs/index.html ./docs/guide.html itself would serve (/, /docs, /docs/guide, see docs/bundler/html-static.mdx and src/js/internal/html.ts), which is what the multi-route branch was imitating. The previous .replace("/index", "") was also a non-anchored first-occurrence replace, so it would have turned e.g. docs/index-page.html into /docs-page; the segment version does not have that problem.

Nothing on main depends on the old keys: the only multi-HTML fixtures are three tests in test/bake/dev/css.test.ts using flat first.html/second.html, which still map to /first//second. The one fixture that has a top-level index.html next to another HTML file (bundle.test.ts, "importing html file with text loader") passes htmlFiles: ["index.html"] and therefore still takes the /* branch. The htmlFiles option doc now states both behaviors so the next multi-route test does not have to read indexHtmlScript to find out which routes it gets.

This surfaced while restructuring the css tests in #37868, which currently keeps the html/index.html case on its own server because of this; with this change it can join a shared server.

Test

test/bake/dev/html.test.ts, "multiple html files are served at the routes bun derives from their paths": index.html, about.html, docs/index.html, docs/guide.html, each with a distinct body, fetched at /, /about, /docs, /docs/guide, plus a 404 for /docs/index to show these are exact routes rather than the single-file catch-all.

Without the harness change it fails on every platform at / (index.html was registered as /index); a variant of the same fixture without index.html fails only on Windows, at /docs (the output above). With the change it passes on linux-x64 (bun bd test, and USE_SYSTEM_BUN=1) and on windows-x64 (USE_SYSTEM_BUN=1, canary 9a543cc).

Also re-ran the other consumers of indexHtmlScript with the change, on both linux (bun bd test) and windows: the three multi-route css tests, "css import before create project relative" (nested single file), bundle.test.ts "directory cache bust case #17576" (mainDir, so the import specifier is ../web/index.html) and "importing html file with text loader" (explicit htmlFiles), and react-spa.test.ts (fixture directory branch). All pass.

indexHtmlScript builds one static route per HTML file when a test has
more than one. The route key was derived from the path.relative() result,
which uses backslashes on Windows, so a nested file such as
docs/index.html was registered as "/docs\\index" and every request for
it hit the harness's 404 fallback. The same line also left a top-level
index.html at "/index" instead of "/".

Normalize the separators once and derive the key per path segment, giving
the same routes as "bun ./index.html ./docs/index.html ./docs/guide.html".
@robobun

robobun commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator Author

Status: reproduced on a Windows x64 box against the unmodified harness (a multi-route fixture with docs/index.html got the route key "/docs\\index" and GET /docs returned the 404 fallback; generated file quoted in the PR body). Fix and test are in this PR; the new test fails without the harness change on every platform and passes with it on linux (bun bd test) and windows.

The diff is ready from my side. Both CI runs so far (builds 93405 and 93452) failed before any linux x64 tests ran because build-bun lanes could not download vendored dependencies (mimalloc, lol-html, c-ares and WebKit tarballs from github.com, "Failed to download after 5 attempts"); other builds running at the same time are failing on random build lanes the same way. The change only touches test/, so it cannot affect the build; it needs a CI re-run once the agents can fetch again. I am not going to keep pushing empty commits for that.

@coderabbitai

coderabbitai Bot commented Aug 12, 2026

Copy link
Copy Markdown
Contributor

Warning

Review limit reached

@robobun, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 8 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 3d0b0a40-64ad-4dea-af28-bcd56b19cdd8

📥 Commits

Reviewing files that changed from the base of the PR and between 9a543cc and d71215a.

📒 Files selected for processing (2)
  • test/bake/bake-harness.ts
  • test/bake/dev/html.test.ts

Comment @coderabbitai help to get the list of available commands.

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — test-harness-only fix with clear before/after semantics.

What was reviewed:

  • Traced htmlFileRoute against index.html, about.html, docs/index.html, docs/guide.html/, /about, /docs, /docs/guide; the old non-anchored .replace("/index", "") and Windows-separator issues are both gone.
  • Confirmed the only existing multi-HTML fixtures (three in css.test.ts, flat first.html/second.html) produce identical keys under the new derivation, and the htmlFiles: ["index.html"] / htmlFiles: [] callers still take their original branches.
  • New test asserts each route's distinct body plus a 404 for /docs/index, so it can't pass via the single-file catch-all.
Extended reasoning...

Overview

This PR touches only test infrastructure: test/bake/bake-harness.ts (the indexHtmlScript generator that writes bun.app.ts for bake dev/prod fixtures) and adds one devTest to test/bake/dev/html.test.ts. The harness change normalizes path.sep/ once up front (previously only the import line did this, so route keys on Windows contained backslashes) and replaces the ad-hoc .replace(/\.html$/, "").replace("/index", "").replace(/\/$/,"") chain with a segment-based htmlFileRoute that strips .html and drops a trailing index segment. A doc comment on htmlFiles now states the single-file vs multi-file routing behavior.

Security risks

None. This is test-harness code that generates a fixture bun.app.ts inside a temp directory during test runs; it does not ship in the runtime and processes no untrusted input.

Level of scrutiny

Low. No runtime code paths are touched. The blast radius is the bake test suite, and the PR body enumerates every existing consumer of indexHtmlScript and shows they are unchanged (flat filenames → same keys) or take a different branch. I spot-checked that claim against test/bake/dev/ — the three css.test.ts multi-HTML fixtures use flat first.html/second.html (identical output), bundle.test.ts passes htmlFiles: ["index.html"] (single-file /* branch), and the htmlFiles: [] cases skip the generator entirely.

Other factors

The new logic is easy to verify by hand: "index.html" → segments ["index"] → pop → "/", "docs/index.html"["docs"]"/docs", "docs/guide.html""/docs/guide". It also fixes a latent bug the old code had (non-anchored "/index" replace would mangle docs/index-page.html/docs-page). The added test exercises the multi-route branch with nested and top-level index.html, asserts distinct bodies per route, and checks /docs/index 404s to prove these are exact static routes rather than the single-file catch-all — so it fails for the right reason without the fix. The PR body reports it was verified on both linux and windows. No outstanding reviewer comments.

@robobun

robobun commented Aug 12, 2026

Copy link
Copy Markdown
Collaborator Author
Updated 3:06 PM PT - Aug 12th, 2026

@robobun, your commit d71215a has 3 failures in Build #93452 (All Failures):


🧪   To try this PR locally:

bunx bun-pr 37892

That installs a local version of the PR into your bun-37892 executable, so you can run:

bun-37892 --bun

@claude claude Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM — test-harness-only fix for Windows path separators and index.html route keys in multi-HTML bake fixtures.

What was reviewed:

  • htmlFileRoute derivation traced for index.html, about.html, docs/index.html, docs/guide.html — matches the routes bun ./*.html would produce.
  • Confirmed the only existing multi-HTML fixtures (three in css.test.ts, flat first.html/second.html) still map to /first//second; indexHtmlScript has no callers outside the harness.
  • Checked the mainDir case (../web/index.html) still hits the single-file /* branch, so the .. segment never reaches htmlFileRoute.
Extended reasoning...

Overview

This PR fixes route-key derivation in the bake test harness's indexHtmlScript generator (test/bake/bake-harness.ts). Previously, when a fixture had multiple HTML files, the generated bun.app.ts derived static-route keys from path.relative(mainDir, file) without normalizing path.sep, so nested files on Windows produced keys like "/docs\\index". It also mapped a top-level index.html to /index and used a non-anchored .replace("/index", "") that would corrupt paths like docs/index-page.html. The fix normalizes separators once, then derives the key per-segment (strip .html, drop a trailing index segment). A new test in test/bake/dev/html.test.ts covers /, /about, /docs, /docs/guide, plus a 404 for /docs/index.

Security risks

None. This is test-harness code that generates a fixture file inside a temp directory; no production/runtime code is touched, and no untrusted input is involved.

Level of scrutiny

Low. The change is confined to ~15 lines of a test-support helper plus a doc-comment and a new test. indexHtmlScript is only called from within bake-harness.ts itself. I verified the three existing multi-HTML fixtures in css.test.ts use flat first.html/second.html, so their keys are unchanged; the nested html/index.html fixture at css.test.ts:645 is single-file and still takes the /* catch-all branch. The mainDir caller (which can produce ../web/index.html) is also single-file per the PR body and repo grep, so the .. segment never reaches htmlFileRoute.

Other factors

The PR description is thorough: it shows the before/after generated output, cites the reference behavior in src/js/internal/html.ts, enumerates every existing consumer and confirms they were re-run on both Linux and Windows, and demonstrates the new test fails without the harness change (/ returned 404 because index.html was keyed as /index). The bug hunting system found no issues. This is a clean, well-scoped harness improvement that unblocks #37868.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant