// Cloud-specific: the auth-hint lifecycle that lets the app paint the REAL// authenticated shell with no full-page skeleton, ever. The sealed session is// HttpOnly, so the SPA can't derive identity from it — instead the SSR gate// verifies the session per document request, renders the shell from that// verified identity, and MINTS the non-HttpOnly hint cookie// (executor-auth-hint) when the browser doesn't hold a current one. From// then on AuthProvider keeps the hint fresh on every confirmed /account/me// and logout takes it away with the session.import { expect } from "@effect/vitest";import { Effect } from "effect";import { scenario } from "../src/scenario";import { Browser, Target } from "../src/services";const HINT_COOKIE = "executor-auth-hint";scenario( "Auth hint · the FIRST load on a fresh browser paints the real shell — the gate minted the hint", {}, Effect.gen(function* () { const browser = yield* Browser; const target = yield* Target; const identity = yield* target.newIdentity(); yield* browser.session(identity, async ({ page, step }) => { // Hold the auth probe open from the very first request. This browser // has NEVER loaded the app — no hint cookie exists — which used to be // the one case that still showed a full-page skeleton for the whole // /account/me round trip. let probeResolved = false; await page.route("**/api/account/me", async (route) => { await new Promise((resolve) => setTimeout(resolve, 2_000)); probeResolved = true; await route.continue(); }); await step("First-ever load: the real app shell, immediately", async () => { await page.goto("/", { waitUntil: "commit" }); // Real nav text — a skeleton has no text at all. await page.getByRole("link", { name: "Policies" }).waitFor(); }); expect(probeResolved, "the shell did NOT wait for /account/me").toBe(false); // The full-page skeleton was a text-free silhouette; the real shell has // the nav AND this identity's own data in the footer — the SSR render // knew who it was serving. (Per-SECTION skeletons for in-flight data // are fine; the silhouette of the whole app is what must never paint.) // newIdentity names the org after the user (`Org user-xxxx`), so the // footer's org line is identity-specific text no other user would show. const orgName = `Org ${identity.label.split("@")[0]}`; expect( await page.getByText(orgName).first().isVisible(), "the shell footer shows THIS identity's organization", ).toBe(true); // The identity the shell painted from is now pinned for next time: the // gate minted the hint cookie on the document response itself. const hint = (await page.context().cookies()).find((c) => c.name === HINT_COOKIE); expect(hint, "the gate minted the hint on the first response").toBeTruthy(); expect(hint!.httpOnly, "the hint is readable by the SPA — that's its job").toBe(false); expect( decodeURIComponent(hint!.value), "it carries the verified identity (display data only)", ).toContain(identity.label); }); }),);scenario( "Auth hint · logout clears the hint with the session", {}, Effect.gen(function* () { const browser = yield* Browser; const target = yield* Target; const identity = yield* target.newIdentity(); yield* browser.session(identity, async ({ page, step }) => { await step("Load the app signed in (the hint arrives with it)", async () => { await page.goto("/", { waitUntil: "commit" }); await page.getByRole("link", { name: "Policies" }).waitFor(); await expect .poll(async () => (await page.context().cookies()).some((c) => c.name === HINT_COOKIE), { timeout: 10_000, }) .toBe(true); }); await step("Sign out through the product flow", async () => { // The shell's sign-out is a top-level navigation: POST the logout // endpoint, ride its redirect through WorkOS's session-end page, and // land back on the public homepage. (A fetch can't make this trip — // the WorkOS hop is cross-origin.) // Bounded retry: a click can land while the shell is still hydrating // and the radix menu never opens (same idiom as org-switcher). for (let attempt = 1; ; attempt++) { try { await page.keyboard.press("Escape"); await page.getByRole("button", { name: /Test User/ }).click(); await page.getByRole("menuitem", { name: "Sign out" }).click({ timeout: 5_000 }); break; } catch (error) { if (attempt >= 3) throw error; } } // The return URL is "/", which the SSR gate bounces to /login for a // signed-out browser — either is proof the round trip landed home. await page.waitForURL((url) => url.pathname === "/" || url.pathname === "/login", { timeout: 15_000, }); }); const names = (await page.context().cookies()).map((cookie) => cookie.name); expect(names, "the hint never outlives the session").not.toContain(HINT_COOKIE); expect(names, "the session itself is gone too").not.toContain("wos-session"); }); }),);
// Cloud-specific: the auth-hint lifecycle that lets the app paint the REAL
// authenticated shell with no full-page skeleton, ever. The sealed session is
// HttpOnly, so the SPA can't derive identity from it — instead the SSR gate
// verifies the session per document request, renders the shell from that
// verified identity, and MINTS the non-HttpOnly hint cookie
// (executor-auth-hint) when the browser doesn't hold a current one. From
// then on AuthProvider keeps the hint fresh on every confirmed /account/me
// and logout takes it away with the session.
import { expect } from "@effect/vitest";
import { Effect } from "effect";
import { scenario } from "../src/scenario";
import { Browser, Target } from "../src/services";
const HINT_COOKIE = "executor-auth-hint";
scenario(
"Auth hint · the FIRST load on a fresh browser paints the real shell — the gate minted the hint",
{},
Effect.gen(function* () {
const browser = yield* Browser;
const target = yield* Target;
const identity = yield* target.newIdentity();
yield* browser.session(identity, async ({ page, step }) => {
// Hold the auth probe open from the very first request. This browser
// has NEVER loaded the app — no hint cookie exists — which used to be
// the one case that still showed a full-page skeleton for the whole
// /account/me round trip.
let probeResolved = false;
await page.route("**/api/account/me", async (route) => {
await new Promise((resolve) => setTimeout(resolve, 2_000));
probeResolved = true;
await route.continue();
});
await step("First-ever load: the real app shell, immediately", async () => {
await page.goto("/", { waitUntil: "commit" });
// Real nav text — a skeleton has no text at all.
await page.getByRole("link", { name: "Policies" }).waitFor();
});
expect(probeResolved, "the shell did NOT wait for /account/me").toBe(false);
// The full-page skeleton was a text-free silhouette; the real shell has
// the nav AND this identity's own data in the footer — the SSR render
// knew who it was serving. (Per-SECTION skeletons for in-flight data
// are fine; the silhouette of the whole app is what must never paint.)
// newIdentity names the org after the user (`Org user-xxxx`), so the
// footer's org line is identity-specific text no other user would show.
const orgName = `Org ${identity.label.split("@")[0]}`;
expect(
await page.getByText(orgName).first().isVisible(),
"the shell footer shows THIS identity's organization",
).toBe(true);
// The identity the shell painted from is now pinned for next time: the
// gate minted the hint cookie on the document response itself.
const hint = (await page.context().cookies()).find((c) => c.name === HINT_COOKIE);
expect(hint, "the gate minted the hint on the first response").toBeTruthy();
expect(hint!.httpOnly, "the hint is readable by the SPA — that's its job").toBe(false);
expect(
decodeURIComponent(hint!.value),
"it carries the verified identity (display data only)",
).toContain(identity.label);
});
}),
);
scenario(
"Auth hint · logout clears the hint with the session",
{},
Effect.gen(function* () {
const browser = yield* Browser;
const target = yield* Target;
const identity = yield* target.newIdentity();
yield* browser.session(identity, async ({ page, step }) => {
await step("Load the app signed in (the hint arrives with it)", async () => {
await page.goto("/", { waitUntil: "commit" });
await page.getByRole("link", { name: "Policies" }).waitFor();
await expect
.poll(async () => (await page.context().cookies()).some((c) => c.name === HINT_COOKIE), {
timeout: 10_000,
})
.toBe(true);
});
await step("Sign out through the product flow", async () => {
// The shell's sign-out is a top-level navigation: POST the logout
// endpoint, ride its redirect through WorkOS's session-end page, and
// land back on the public homepage. (A fetch can't make this trip —
// the WorkOS hop is cross-origin.)
// Bounded retry: a click can land while the shell is still hydrating
// and the radix menu never opens (same idiom as org-switcher).
for (let attempt = 1; ; attempt++) {
try {
await page.keyboard.press("Escape");
await page.getByRole("button", { name: /Test User/ }).click();
await page.getByRole("menuitem", { name: "Sign out" }).click({ timeout: 5_000 });
break;
} catch (error) {
if (attempt >= 3) throw error;
}
}
// The return URL is "/", which the SSR gate bounces to /login for a
// signed-out browser — either is proof the round trip landed home.
await page.waitForURL((url) => url.pathname === "/" || url.pathname === "/login", {
timeout: 15_000,
});
});
const names = (await page.context().cookies()).map((cookie) => cookie.name);
expect(names, "the hint never outlives the session").not.toContain(HINT_COOKIE);
expect(names, "the session itself is gone too").not.toContain("wos-session");
});
}),
);