Files
openwork/apps/app/tests/den-handoff.test.ts

212 lines
7.5 KiB
TypeScript

import { afterEach, describe, expect, test } from "bun:test";
import { exchangeHandoffAndSignIn } from "../src/app/lib/den-handoff";
import {
hasActiveDesktopSignInIntent,
markDesktopSignInInitiated,
markOrgSelectionPending,
readOrgSelectionPending,
} from "../src/app/lib/den-sign-in-intent";
const originalWindow = globalThis.window;
const originalFetch = globalThis.fetch;
function memoryStorage(): Storage {
const map = new Map<string, string>();
return {
get length() {
return map.size;
},
clear() {
map.clear();
},
getItem(key: string) {
return map.get(key) ?? null;
},
key(index: number) {
return Array.from(map.keys())[index] ?? null;
},
removeItem(key: string) {
map.delete(key);
},
setItem(key: string, value: string) {
map.set(key, value);
},
};
}
function stubWindow() {
Object.defineProperty(globalThis, "window", {
configurable: true,
value: {
localStorage: memoryStorage(),
sessionStorage: memoryStorage(),
dispatchEvent: () => true,
},
});
}
function stubExchangeResponse(payload: Record<string, unknown>) {
Object.defineProperty(globalThis, "fetch", {
configurable: true,
value: (async () => new Response(JSON.stringify(payload), {
status: 200,
headers: { "Content-Type": "application/json" },
})) satisfies typeof fetch,
});
}
const exchangeUser = { id: "user_invited", email: "invited@example.com", name: "Invited Member" };
afterEach(() => {
Object.defineProperty(globalThis, "window", {
configurable: true,
value: originalWindow,
});
Object.defineProperty(globalThis, "fetch", {
configurable: true,
value: originalFetch,
});
});
describe("exchangeHandoffAndSignIn", () => {
test("persists the organization resolved by the handoff exchange", async () => {
stubWindow();
stubExchangeResponse({
token: "tok_handoff",
user: exchangeUser,
organization: { id: "org_invited", slug: "invited-org", name: "Invited Org" },
connectEnabled: false,
});
const result = await exchangeHandoffAndSignIn("grant_test", { baseUrl: "https://den.test" });
expect(result.ok).toBe(true);
if (!result.ok) throw new Error(result.error);
expect(window.localStorage.getItem("openwork.den.activeOrgId")).toBe("org_invited");
expect(window.localStorage.getItem("openwork.den.activeOrgSlug")).toBe("invited-org");
expect(window.localStorage.getItem("openwork.den.activeOrgName")).toBe("Invited Org");
expect(result.exchange.connectEnabled).toBe(false);
expect(window.localStorage.getItem("openwork.den.desktopConfig:https://den.test::org_invited"))
.toBe(JSON.stringify({ connectEnabled: false }));
});
test("prefers the caller-provided organization over the exchange payload", async () => {
stubWindow();
stubExchangeResponse({
token: "tok_handoff",
user: exchangeUser,
organization: { id: "org_exchange", slug: "exchange-org", name: "Exchange Org" },
});
const result = await exchangeHandoffAndSignIn("grant_test", {
baseUrl: "https://den.test",
activeOrg: { id: "org_bootstrap", slug: "bootstrap-org", name: "Bootstrap Org" },
});
expect(result.ok).toBe(true);
expect(window.localStorage.getItem("openwork.den.activeOrgId")).toBe("org_bootstrap");
expect(window.localStorage.getItem("openwork.den.desktopConfig:https://den.test::org_bootstrap")).toBeNull();
});
test("preserves the stored organization when the exchange has none", async () => {
stubWindow();
window.localStorage.setItem("openwork.den.activeOrgId", "org_stored");
window.localStorage.setItem("openwork.den.activeOrgSlug", "stored-org");
window.localStorage.setItem("openwork.den.activeOrgName", "Stored Org");
stubExchangeResponse({ token: "tok_handoff", user: exchangeUser });
const result = await exchangeHandoffAndSignIn("grant_test", { baseUrl: "https://den.test" });
expect(result.ok).toBe(true);
if (!result.ok) throw new Error(result.error);
expect(window.localStorage.getItem("openwork.den.activeOrgId")).toBe("org_stored");
expect(window.localStorage.getItem("openwork.den.activeOrgSlug")).toBe("stored-org");
expect(window.localStorage.getItem("openwork.den.activeOrgName")).toBe("Stored Org");
expect(result.exchange.connectEnabled).toBeNull();
expect(window.localStorage.getItem("openwork.den.desktopConfig:https://den.test::org_stored"))
.toBeNull();
});
test("a desktop-initiated sign-in defers the org choice to the chooser", async () => {
stubWindow();
stubExchangeResponse({
token: "tok_handoff",
user: exchangeUser,
organization: { id: "org_default", slug: "default-org", name: "Default Org" },
});
const result = await exchangeHandoffAndSignIn("grant_test", {
baseUrl: "https://den.test",
desktopInitiated: true,
});
expect(result.ok).toBe(true);
// Token persists, but no organization is committed…
expect(window.localStorage.getItem("openwork.den.authToken")).toBe("tok_handoff");
expect(window.localStorage.getItem("openwork.den.activeOrgId")).toBeNull();
// …and the chooser sees the pending state with the exchange org suggested.
expect(readOrgSelectionPending()).toEqual({
pending: true,
suggestion: { id: "org_default", slug: "default-org", name: "Default Org" },
});
});
test("the desktop sign-in intent marker classifies an unlabeled handoff", async () => {
stubWindow();
markDesktopSignInInitiated();
stubExchangeResponse({
token: "tok_handoff",
user: exchangeUser,
organization: { id: "org_default", slug: "default-org", name: "Default Org" },
});
const result = await exchangeHandoffAndSignIn("grant_test", { baseUrl: "https://den.test" });
expect(result.ok).toBe(true);
expect(window.localStorage.getItem("openwork.den.activeOrgId")).toBeNull();
expect(readOrgSelectionPending().pending).toBe(true);
// The marker is consumed: a later remote handoff is not reclassified.
expect(hasActiveDesktopSignInIntent()).toBe(false);
});
test("an explicitly scoped org connects straight through even when desktop-initiated", async () => {
stubWindow();
markDesktopSignInInitiated();
stubExchangeResponse({
token: "tok_handoff",
user: exchangeUser,
organization: { id: "org_exchange", slug: "exchange-org", name: "Exchange Org" },
});
const result = await exchangeHandoffAndSignIn("grant_test", {
baseUrl: "https://den.test",
activeOrg: { id: "org_invite", slug: "invite-org", name: "Invite Org" },
desktopInitiated: true,
});
expect(result.ok).toBe(true);
expect(window.localStorage.getItem("openwork.den.activeOrgId")).toBe("org_invite");
expect(readOrgSelectionPending().pending).toBe(false);
});
test("a remote handoff clears stale pending state and commits its organization", async () => {
stubWindow();
markOrgSelectionPending({ id: "org_stale", slug: null, name: null });
stubExchangeResponse({
token: "tok_handoff",
user: exchangeUser,
organization: { id: "org_remote", slug: "remote-org", name: "Remote Org" },
});
const result = await exchangeHandoffAndSignIn("grant_test", {
baseUrl: "https://den.test",
desktopInitiated: false,
});
expect(result.ok).toBe(true);
expect(window.localStorage.getItem("openwork.den.activeOrgId")).toBe("org_remote");
expect(readOrgSelectionPending()).toEqual({ pending: false, suggestion: null });
});
});