mirror of
https://github.com/oven-sh/bun
synced 2026-02-09 18:38:55 +00:00
test(bundler): improve test for compile asset paths
- Skip test in debug builds (compile is unreliable with debug builds) - Use fixed port instead of parsing output (simpler and more reliable) - Use HTTP polling to wait for server ready - Use await using for automatic process cleanup - Add timeout to handle slow builds Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,13 +1,16 @@
|
||||
import { expect, test } from "bun:test";
|
||||
import fs from "fs";
|
||||
import { bunEnv, bunExe, tempDirWithFiles } from "harness";
|
||||
import { bunEnv, bunExe, isDebug, tempDirWithFiles } from "harness";
|
||||
import path from "path";
|
||||
|
||||
// https://github.com/oven-sh/bun/issues/24180
|
||||
// When building fullstack apps with --compile, asset paths in HTML should be
|
||||
// absolute (starting with `/`) not relative (starting with `./`). Relative paths
|
||||
// cause 404 errors when navigating to routes other than `/`.
|
||||
test("fullstack compile uses absolute asset paths in generated HTML", async () => {
|
||||
test.skipIf(isDebug)("fullstack compile uses absolute asset paths in generated HTML", { timeout: 60_000 }, async () => {
|
||||
// Use a fixed port for testing - the compiled app will use this
|
||||
const port = 49842;
|
||||
|
||||
const dir = tempDirWithFiles("24180", {
|
||||
"index.html": `
|
||||
<!DOCTYPE html>
|
||||
@@ -33,7 +36,7 @@ console.log("loaded");
|
||||
import html from "./index.html";
|
||||
|
||||
export default {
|
||||
port: 0,
|
||||
port: ${port},
|
||||
static: {
|
||||
"/": html,
|
||||
"/about": html,
|
||||
@@ -66,69 +69,58 @@ export default {
|
||||
expect(buildExitCode).toBe(0);
|
||||
expect(fs.existsSync(outfile)).toBe(true);
|
||||
|
||||
// Run the compiled executable
|
||||
const serverProc = Bun.spawn({
|
||||
// Run the compiled executable with await using for automatic cleanup
|
||||
await using serverProc = Bun.spawn({
|
||||
cmd: [outfile],
|
||||
cwd: dir,
|
||||
env: bunEnv,
|
||||
stdout: "pipe",
|
||||
stderr: "pipe",
|
||||
stdout: "inherit",
|
||||
stderr: "inherit",
|
||||
});
|
||||
|
||||
// Wait for the server to start and capture the port
|
||||
const reader = serverProc.stdout.getReader();
|
||||
let output = "";
|
||||
let port: number | null = null;
|
||||
|
||||
while (true) {
|
||||
const { done, value } = await reader.read();
|
||||
if (done) break;
|
||||
output += new TextDecoder().decode(value);
|
||||
const match = output.match(/localhost:(\d+)/);
|
||||
if (match) {
|
||||
port = parseInt(match[1], 10);
|
||||
// Wait for server to be ready by polling the HTTP endpoint
|
||||
let res: Response | undefined;
|
||||
const deadline = Date.now() + 10_000;
|
||||
while (Date.now() < deadline) {
|
||||
try {
|
||||
res = await fetch(`http://localhost:${port}/`);
|
||||
break;
|
||||
} catch {
|
||||
await Bun.sleep(100);
|
||||
}
|
||||
}
|
||||
|
||||
expect(port).not.toBeNull();
|
||||
|
||||
try {
|
||||
// Fetch the HTML from the root route
|
||||
const res = await fetch(`http://localhost:${port}/`);
|
||||
const html = await res.text();
|
||||
|
||||
// Check that the CSS and JS paths are absolute, not relative
|
||||
// They should start with `/` not `./`
|
||||
const cssMatch = html.match(/href="([^"]+\.css)"/);
|
||||
const jsMatch = html.match(/src="([^"]+\.js)"/);
|
||||
|
||||
expect(cssMatch).not.toBeNull();
|
||||
expect(jsMatch).not.toBeNull();
|
||||
|
||||
const cssPath = cssMatch![1];
|
||||
const jsPath = jsMatch![1];
|
||||
|
||||
// Verify paths are absolute (start with /)
|
||||
expect(cssPath.startsWith("/")).toBe(true);
|
||||
expect(jsPath.startsWith("/")).toBe(true);
|
||||
|
||||
// Verify paths don't use relative notation
|
||||
expect(cssPath.startsWith("./")).toBe(false);
|
||||
expect(jsPath.startsWith("./")).toBe(false);
|
||||
|
||||
// Also verify the assets are actually accessible
|
||||
const cssRes = await fetch(`http://localhost:${port}${cssPath}`);
|
||||
expect(cssRes.status).toBe(200);
|
||||
const cssContent = await cssRes.text();
|
||||
expect(cssContent).toContain("background");
|
||||
|
||||
const jsRes = await fetch(`http://localhost:${port}${jsPath}`);
|
||||
expect(jsRes.status).toBe(200);
|
||||
const jsContent = await jsRes.text();
|
||||
expect(jsContent).toContain("loaded");
|
||||
} finally {
|
||||
serverProc.kill();
|
||||
await serverProc.exited;
|
||||
if (!res) {
|
||||
throw new Error("Server did not start within timeout");
|
||||
}
|
||||
const html = await res.text();
|
||||
|
||||
// Check that the CSS and JS paths are absolute, not relative
|
||||
// They should start with `/` not `./`
|
||||
const cssMatch = html.match(/href="([^"]+\.css)"/);
|
||||
const jsMatch = html.match(/src="([^"]+\.js)"/);
|
||||
|
||||
expect(cssMatch).not.toBeNull();
|
||||
expect(jsMatch).not.toBeNull();
|
||||
|
||||
const cssPath = cssMatch![1];
|
||||
const jsPath = jsMatch![1];
|
||||
|
||||
// Verify paths are absolute (start with /)
|
||||
expect(cssPath.startsWith("/")).toBe(true);
|
||||
expect(jsPath.startsWith("/")).toBe(true);
|
||||
|
||||
// Verify paths don't use relative notation
|
||||
expect(cssPath.startsWith("./")).toBe(false);
|
||||
expect(jsPath.startsWith("./")).toBe(false);
|
||||
|
||||
// Also verify the assets are actually accessible
|
||||
const cssRes = await fetch(`http://localhost:${port}${cssPath}`);
|
||||
expect(cssRes.status).toBe(200);
|
||||
const cssContent = await cssRes.text();
|
||||
expect(cssContent).toContain("background");
|
||||
|
||||
const jsRes = await fetch(`http://localhost:${port}${jsPath}`);
|
||||
expect(jsRes.status).toBe(200);
|
||||
const jsContent = await jsRes.text();
|
||||
expect(jsContent).toContain("loaded");
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user