import { expect, test } from "@playwright/test"; import { readFileSync } from "node:fs"; import { resolve } from "node:path"; const ROUTES_WITH_LOCAL_FALLBACKS = [ "app/(chat)/api/models/route.ts", "app/api/favicon/route.ts", "app/api/site-settings/route.ts", "app/api/user/membership-summary/route.ts", ]; test("requires an explicit environment switch for local fallbacks", () => { for (const path of ROUTES_WITH_LOCAL_FALLBACKS) { const source = readFileSync(resolve(process.cwd(), path), "utf8"); expect(source, path).toContain( 'process.env.CANVAS_E2E_LOCAL === "true"' ); expect(source, path).not.toMatch( /CANVAS_E2E_LOCAL[\s\S]{0,220}\|\|[\s\S]{0,120}(localhost|127\.0\.0\.1|::1)/ ); } }); test("production deploy stages the main build and retains active static chunks", () => { const nextConfig = readFileSync( resolve(process.cwd(), "next.config.ts"), "utf8" ); const deployScript = readFileSync( resolve(process.cwd(), "scripts/deploy-pascal-production.sh"), "utf8" ); expect(nextConfig).toContain( 'distDir: process.env.NEXT_DIST_DIR?.trim() || ".next"' ); expect(deployScript).toContain("NEXT_DIST_DIR=.next-build"); expect(deployScript).toContain( 'rsync -a --ignore-existing "$current_build/static/" "$staged_build/static/"' ); expect(deployScript).toContain('curl -fsS "$MAIN_INTERNAL_URL/ping"'); }); test("atomic production deploy rejects the local E2E fallback switch", () => { const deployScript = readFileSync( resolve(process.cwd(), "scripts/deploy-production-atomic.sh"), "utf8" ); expect(deployScript).toContain("CANVAS_E2E_LOCAL"); expect(deployScript).toContain( "Refusing production deployment while CANVAS_E2E_LOCAL=true." ); });