Files
sql-server-query-ai/tests-e2e/session.spec.ts
T
ahmed mohammedandClaude Opus 4.7 2ebfcfb7a6 fix: session cookie over plain http, console onboarding gate, webkit qa coverage
- the session cookie was Secure whenever NODE_ENV=production, so a production build on http://localhost got no cookie back in Safari: every page after signup looked signed-out. It is now Secure only when X-Forwarded-Proto says https, or when COOKIE_SECURE=1.
- /app and /app/[id] now require an analyst and a Jev key, the same rule /api/analyze enforces with a 412. Closing the guide mid-way used to leave a console that could not run anything.
- Playwright runs the production server (pree2e builds first) and gains a webkit project for session survival; chromium-only QA could never see a Secure-cookie rejection.
- tests-e2e/session.spec.ts pins both; .env.example gains COOKIE_SECURE and stops shipping a blank APP_SECRET.
- e2e: 21 passed (setup, chromium, webkit, mobile).

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-09-22 10:45:12 +03:00

45 lines
2.2 KiB
TypeScript

import { test, expect } from "@playwright/test";
// WebKit-only on purpose. Chromium accepts a `Secure` cookie on http://localhost; Safari does not, and it
// silently drops it, so a production build on plain http looked like "the wizard signed me out".
// This file must stay self-contained: it signs up its own account and never uses .auth/user.json.
test("signup, wizard Next links, and /app stay logged in over plain http", async ({ page }) => {
const email = `safari${Date.now()}@qai.test`;
await page.goto("/signup");
await page.fill("#email", email);
await page.fill("#password", "0123456789ab");
await page.getByRole("button", { name: "Create account" }).click();
await expect(page).toHaveURL(/\/setup/, { timeout: 20_000 });
await expect(page.getByText("Step 1 of 3")).toBeVisible();
await page.getByRole("link", { name: "Next" }).click();
await expect(page).toHaveURL(/step=2/);
await expect(page.getByText("Say which models to ask.")).toBeVisible();
await page.getByRole("link", { name: "Next" }).click();
await expect(page).toHaveURL(/step=3/);
// Session proof: this user has no keys yet, so the console gate sends them to the guide.
// Signed-in lands on /setup?step=2; a lost session would land on /login.
await page.goto("/app");
await expect(page).toHaveURL(/\/setup\?step=2/);
});
test("a reload deep in the app keeps the session", async ({ page }) => {
const email = `reload${Date.now()}@qai.test`;
await page.goto("/signup");
await page.fill("#email", email);
await page.fill("#password", "0123456789ab");
await page.getByRole("button", { name: "Create account" }).click();
// Wait for the signup POST to finish: the cookie is not in effect until its response lands, and an
// immediate goto races it (which reads as "the session did not survive a reload").
await expect(page).toHaveURL(/\/setup/, { timeout: 20_000 });
await page.goto("/settings");
await page.reload();
await expect(page.getByRole("heading", { name: "Settings" })).toBeVisible();
// The form is still here after the reload: this is the account's own settings page, not the login form.
await expect(page.getByRole("button", { name: "Save" })).toBeVisible();
});