/** * SPA fallback tests — validates that client-side routes return index.html. */ import { describe, it, expect, afterAll, beforeAll } from "vitest"; import { createServer, type DashboardServer } from "../server.js"; import path from "node:path"; import fs from "node:fs"; import { fileURLToPath } from "node:url"; const httpPort = 19100; const piPort = 19101; let server: DashboardServer; // Ensure dist/client/index.html exists for the test const __dirname = path.dirname(fileURLToPath(import.meta.url)); const clientDir = path.join(__dirname, "../../../dist/client"); const indexPath = path.join(clientDir, "index.html"); let createdDir = false; describe("SPA fallback", () => { beforeAll(async () => { // Create minimal dist/client/index.html if it doesn't exist if (!fs.existsSync(indexPath)) { fs.mkdirSync(clientDir, { recursive: true }); fs.writeFileSync(indexPath, "SPA"); createdDir = true; } server = await createServer({ port: httpPort, piPort, dev: false, // production mode enables static serving + SPA fallback autoShutdown: false, shutdownIdleSeconds: 999, tunnel: false, editor: { idleTimeoutMinutes: 10, maxInstances: 3 }, }); await server.start(); }); afterAll(async () => { if (server) await server.stop(); if (createdDir) { fs.rmSync(indexPath); } }); it("returns index.html for /session/:id route", async () => { const res = await fetch(`http://localhost:${httpPort}/session/abc-123`); expect(res.status).toBe(200); const body = await res.text(); expect(body).toContain("html"); }); it("returns index.html for unknown client routes", async () => { const res = await fetch(`http://localhost:${httpPort}/some/unknown/path`); expect(res.status).toBe(200); const body = await res.text(); expect(body).toContain("html"); }); it("still serves API routes normally", async () => { const res = await fetch(`http://localhost:${httpPort}/api/sessions`); expect(res.status).toBe(200); const json = await res.json(); expect(json.success).toBe(true); }); });