import assert from "node:assert/strict"; import { headingOf, installPage, inViewOf, primaryOf, settle, timedTest, until } from "./boot.js"; import { StubElement } from "./stub-dom.js"; const cardTest = timedTest(3000); const page = installPage(); const { app, history, location, storage, fetches } = page; const keyMeta = new StubElement("meta"); keyMeta.setAttribute("id", "stripe-publishable-key"); keyMeta.setAttribute("name", "stripe-publishable-key"); keyMeta.setAttribute("content", ""); page.document.byId.set("stripe-publishable-key", keyMeta); function configureKey(key: string): void { keyMeta.setAttribute("content", key); } const stripe = await import("../src/stripe.js"); const screens = await import("../src/screens.js"); await import("../src/main.js"); type UnpaidOrder = import("../src/order.js").UnpaidOrder; type InvoiceView = import("../src/api.js").InvoiceView; const HELD_CODE = "SB-YDC8A-YGQTM-PUYZ9-2TUXP"; const CLIENT_SECRET = "cs_test_a1b2c3d4"; const PUBLISHABLE_KEY = "pk_test_51NotARealKey"; const APPEARANCE = { theme: "stripe" } as const; const RETURN_URL = "https://badges.example/"; function render(node: unknown): StubElement { return node as unknown as StubElement; } const order: UnpaidOrder = { orderId: "inv_card", badgeType: "legend", months: 12, createdAt: "2026-08-28T11:02:19Z", status: "open", code: HELD_CODE, } as unknown as UnpaidOrder; const cardInvoice: InvoiceView = { status: "open", amount: 42000, currency: "usd", clientSecret: CLIENT_SECRET, }; function assertNoCode(node: StubElement, where: string): void { const dump = node.serialize(); for (const form of [HELD_CODE, HELD_CODE.replace(/-/g, ""), "SB-"]) { assert.ok(!dump.includes(form), `${where} leaked a code (${form})`); } } cardTest("stripe: with no publishable key the card lane is unavailable, and nothing loads", () => { for (const [what, key] of [["absent", undefined], ["empty", ""], ["whitespace", " "]] as const) { const plan = stripe.cardPlan(key, false); assert.equal(plan.kind, "unavailable", `a ${what} key configures no card form`); assert.equal(plan.kind === "unavailable" ? plan.reason : "", "unconfigured"); } }); cardTest("stripe: with a key configured the plan is to LOAD, and carries the key", () => { const plan = stripe.cardPlan(` ${PUBLISHABLE_KEY} `, false); assert.equal(plan.kind, "load"); assert.equal(plan.kind === "load" ? plan.publishableKey : "", PUBLISHABLE_KEY, "trimmed, as a config value is"); }); cardTest("stripe: offline with a key is a failure screen, not a form that never fills", () => { const plan = stripe.cardPlan(PUBLISHABLE_KEY, true); assert.equal(plan.kind, "unavailable"); assert.equal(plan.kind === "unavailable" ? plan.reason : "", "offline"); }); cardTest("stripe: a missing key wins over offline — the page is unconfigured either way", () => { const plan = stripe.cardPlan("", true); assert.equal(plan.kind, "unavailable"); assert.equal(plan.kind === "unavailable" ? plan.reason : "", "unconfigured"); }); cardTest("stripe: the script URL is Stripe's own origin, which may not be self-hosted", () => { assert.ok(stripe.STRIPE_JS_URL.startsWith("https://js.stripe.com/"), stripe.STRIPE_JS_URL); }); interface Trace { calls: string[]; target: unknown; secret: string; key: string; createArg: string; appearance: string; returnUrl: string; destroys: number; } function fakeStripe(over: { elementsFails?: boolean; mountThrows?: boolean; destroyThrows?: boolean; confirmResult?: import("../src/stripe.js").PaymentIntentResult; confirmRejects?: boolean; } = {}): { load: import("../src/stripe.js").LoadStripeJs; trace: Trace; loaded: string[] } { const trace: Trace = { calls: [], target: null, secret: "", key: "", createArg: "", appearance: "", returnUrl: "", destroys: 0 }; const loaded: string[] = []; const elements = { create: (kind: "payment") => { trace.calls.push("create"); trace.createArg = kind; return { mount: (target: unknown) => { trace.calls.push("mount"); trace.target = target; if (over.mountThrows === true) throw new Error("no such node"); }, destroy: () => { trace.calls.push("destroy"); trace.destroys += 1; if (over.destroyThrows === true) throw new Error("already gone"); }, }; }, }; const load: import("../src/stripe.js").LoadStripeJs = async (src) => { loaded.push(src); return (key: string) => { trace.calls.push("Stripe"); trace.key = key; return { elements: (options: { clientSecret: string; appearance?: { theme?: string } }) => { trace.calls.push("elements"); trace.secret = options.clientSecret; trace.appearance = options.appearance?.theme ?? ""; if (over.elementsFails === true) throw new Error("no such intent"); return elements; }, confirmPayment: async (options: { confirmParams: { return_url: string } }) => { trace.calls.push("confirmPayment"); trace.returnUrl = options.confirmParams.return_url; if (over.confirmRejects === true) throw new Error("network"); return over.confirmResult ?? { paymentIntent: { status: "succeeded" } }; }, }; }; }; return { load, trace, loaded }; } function loadPlan(): import("../src/stripe.js").LoadPlan { const plan = stripe.cardPlan(PUBLISHABLE_KEY, false); assert.equal(plan.kind, "load"); return plan as import("../src/stripe.js").LoadPlan; } cardTest("stripe: mounting follows Stripe's script rule — init the SDK, create the element, mount it", async () => { const { load, trace, loaded } = fakeStripe(); const target = { the: "mount point" }; const result = await stripe.mountCard({ plan: loadPlan(), clientSecret: CLIENT_SECRET, target, appearance: APPEARANCE, returnUrl: RETURN_URL, loadStripe: load }); assert.equal(result.kind, "mounted"); assert.deepEqual(trace.calls, ["Stripe", "elements", "create", "mount"]); assert.deepEqual(loaded, [stripe.STRIPE_JS_URL], "loaded once, from js.stripe.com"); assert.equal(trace.key, PUBLISHABLE_KEY); assert.equal(trace.secret, CLIENT_SECRET, "the client_secret, and nothing else about the order"); assert.equal(trace.target, target, "the Element goes into the node it was handed"); assert.equal(trace.createArg, "payment", "the Payment Element, with no field configuration of ours"); }); cardTest("stripe: the appearance follows the site theme, resolving system by the OS", () => { for (const [label, t, osDark, ink] of [ ["forced light ignores a dark OS", "light", true, "#0D1B3A"], ["forced dark ignores a light OS", "dark", false, "#EAF2FF"], ["system follows a dark OS", "system", true, "#EAF2FF"], ["system follows a light OS", "system", false, "#0D1B3A"], ] as const) { const a = stripe.appearanceFor(t, osDark); assert.equal(a.theme, "flat", label); assert.equal(a.variables?.colorText, ink, label); } }); cardTest("stripe: the chosen appearance is handed to the SDK, so the Element matches the page", async () => { const { load, trace } = fakeStripe(); await stripe.mountCard({ plan: loadPlan(), clientSecret: CLIENT_SECRET, target: {}, appearance: { theme: "night" }, returnUrl: RETURN_URL, loadStripe: load }); assert.equal(trace.appearance, "night", "the dark theme reached elements()"); }); cardTest("stripe: a mounted form can be torn down, once, and a throwing teardown is survivable", async () => { const { load, trace } = fakeStripe(); const mounted = await stripe.mountCard({ plan: loadPlan(), clientSecret: CLIENT_SECRET, target: {}, appearance: APPEARANCE, returnUrl: RETURN_URL, loadStripe: load }); if (mounted.kind !== "mounted") throw new Error("expected a mounted form"); assert.equal(trace.destroys, 0, "mounting tears nothing down"); mounted.destroy(); assert.equal(trace.destroys, 1, "Stripe's own teardown is what takes the iframes with it"); mounted.destroy(); assert.equal(trace.destroys, 1, "idempotent: a second release destroys nothing twice"); const thrower = fakeStripe({ destroyThrows: true }); const second = await stripe.mountCard({ plan: loadPlan(), clientSecret: CLIENT_SECRET, target: {}, appearance: APPEARANCE, returnUrl: RETURN_URL, loadStripe: thrower.load }); if (second.kind !== "mounted") throw new Error("expected a mounted form"); assert.doesNotThrow(() => { second.destroy(); }); assert.equal(thrower.trace.destroys, 1); }); cardTest("stripe: a script that does not load is a failure, and nothing is mounted", async () => { const { trace } = fakeStripe(); const result = await stripe.mountCard({ plan: loadPlan(), clientSecret: CLIENT_SECRET, target: {}, appearance: APPEARANCE, returnUrl: RETURN_URL, loadStripe: async () => { throw new Error("blocked"); }, }); assert.equal(result.kind, "failed"); assert.equal(result.kind === "failed" ? result.reason : "", "script"); assert.deepEqual(trace.calls, [], "nothing of Stripe's was touched"); }); cardTest("stripe: an SDK that refuses the client secret is its own failure", async () => { const { load } = fakeStripe({ elementsFails: true }); const result = await stripe.mountCard({ plan: loadPlan(), clientSecret: "cs_gone", target: {}, appearance: APPEARANCE, returnUrl: RETURN_URL, loadStripe: load }); assert.equal(result.kind, "failed"); assert.equal(result.kind === "failed" ? result.reason : "", "sdk"); }); cardTest("stripe: a mount that throws leaves no half-usable form", async () => { const { load } = fakeStripe({ mountThrows: true }); const result = await stripe.mountCard({ plan: loadPlan(), clientSecret: CLIENT_SECRET, target: {}, appearance: APPEARANCE, returnUrl: RETURN_URL, loadStripe: load }); assert.equal(result.kind, "failed"); assert.equal(result.kind === "failed" ? result.reason : "", "sdk"); }); async function confirmWith(over: Parameters[0]): Promise<{ outcome: import("../src/stripe.js").ConfirmOutcome; trace: Trace; }> { const { load, trace } = fakeStripe(over); const mounted = await stripe.mountCard({ plan: loadPlan(), clientSecret: CLIENT_SECRET, target: {}, appearance: APPEARANCE, returnUrl: RETURN_URL, loadStripe: load }); if (mounted.kind !== "mounted") throw new Error(`expected a mounted form, got ${mounted.kind}`); return { outcome: await mounted.confirm(), trace }; } cardTest("stripe: confirming is confirmPayment(), and a succeeded intent is `submitted` only", async () => { const { outcome, trace } = await confirmWith({}); assert.deepEqual(outcome, { kind: "submitted" }); assert.equal(trace.calls.at(-1), "confirmPayment"); assert.equal(trace.returnUrl, RETURN_URL, "confirm is handed the return URL Stripe requires"); assert.ok(!("paid" in outcome) && !("settledAt" in outcome)); }); cardTest("stripe: a processing intent is also `submitted` — the poller settles it", async () => { const { outcome } = await confirmWith({ confirmResult: { paymentIntent: { status: "processing" } } }); assert.deepEqual(outcome, { kind: "submitted" }); }); cardTest("stripe: a refusal is the reason Stripe gave, and the form stays", async () => { const { outcome } = await confirmWith({ confirmResult: { error: { message: "Your card was declined." } } }); assert.deepEqual(outcome, { kind: "error", message: "Your card was declined." }); }); cardTest("stripe: an error with no message of its own still says something usable", async () => { const { outcome } = await confirmWith({ confirmResult: { error: {} } }); assert.deepEqual(outcome, { kind: "error", message: stripe.CONFIRM_FAILED }); }); cardTest("stripe: an intent left in a non-terminal status is an error, not a submission", async () => { const { outcome } = await confirmWith({ confirmResult: { paymentIntent: { status: "requires_payment_method" } } }); assert.deepEqual(outcome, { kind: "error", message: stripe.CONFIRM_FAILED }); }); cardTest("stripe: a confirm that THREW is an error, and never a submission", async () => { const { outcome } = await confirmWith({ confirmRejects: true }); assert.equal(outcome.kind, "error", "a rejected confirm must not move the page to the confirming screen"); }); cardTest("screens: the card fields are disabled until the Element is actually mounted", () => { let paid = 0; const mount = screens.cardMount(); const fields = screens.cardFields({ mount, total: "$420.00", onPay: () => { paid += 1; } }); const node = render(fields.node); assert.equal(node.all("div.card-mount")[0], render(mount), "the Element goes into the node handed in"); const pay = node.all("button.primary")[0]!; assert.ok(pay.textContent.includes("$420.00")); assert.ok(pay.hasAttribute("disabled"), "Stripe.js has not run yet"); assert.ok(node.textContent.includes(screens.CARD_LOADING)); pay.click(); assert.equal(paid, 0, "a disabled control does nothing"); fields.enable(); assert.ok(!pay.hasAttribute("disabled")); pay.click(); assert.equal(paid, 1); fields.busy(true); pay.click(); assert.equal(paid, 1, "one press, one attempt — there is no idempotency key"); fields.busy(false); fields.error("Your card was declined."); assert.ok(node.textContent.includes("Your card was declined.")); }); cardTest("screens: the card form renders the body it is given, and no second mount point", () => { const marker = new StubElement("p"); marker.textContent = "custom body marker"; const withBody = render(screens.cardForm({ order, invoice: cardInvoice, resumed: false, body: marker as unknown as HTMLElement, })); assert.ok(withBody.textContent.includes("custom body marker"), "the body handed in is rendered"); assert.ok(withBody.textContent.includes("Legend")); assert.ok(withBody.textContent.includes("$420.00")); assert.ok(withBody.textContent.includes("inv_card"), "the reference is on every screen that may need support"); assert.equal(withBody.all("div.card-mount").length, 0, "a supplied body brings no mount point of its own"); assert.ok(!withBody.textContent.includes(CLIENT_SECRET), "the client secret is never rendered"); assertNoCode(withBody, "cardForm/body"); assert.equal(withBody.all("svg.qr").length, 0, "the store rules: no QR on an unpaid screen"); const bare = render(screens.cardForm({ order, invoice: cardInvoice, resumed: false })); assert.equal(bare.all("div.card-mount").length, 1, "the default body is the mount point"); }); cardTest("screens: a card form that could not load is a screen, not a blank panel", () => { let retried = 0; let fresh = 0; for (const [reason, expected] of [["offline", "You are offline"], ["script", "served by Stripe"], ["sdk", "served by Stripe"]] as const) { const p = render(screens.cardUnavailable({ order, reason, onRetry: () => { retried += 1; }, onNewInvoice: () => { fresh += 1; }, })); assert.equal(p.all("h1")[0]!.textContent, "The card form did not load"); assert.ok(p.textContent.includes(expected), `${reason}: ${p.textContent}`); assert.ok(p.textContent.includes("Nothing was charged")); assert.ok(p.textContent.includes("still waiting to be paid")); assert.ok(p.textContent.includes("inv_card")); assert.equal(p.all("div.card-mount").length, 0, "no mount point on a screen with nothing to mount"); assertNoCode(p, `cardUnavailable/${reason}`); } const p = render(screens.cardUnavailable({ order, reason: "script", onRetry: () => { retried += 1; }, onNewInvoice: () => { fresh += 1; } })); p.all("button.primary")[0]!.click(); p.all("button.secondary")[0]!.click(); assert.equal(retried, 1, "[ Try again ] retries"); assert.equal(fresh, 1, "and the buyer is never stranded"); }); const screen = (): StubElement => inViewOf(app); const heading = (): string => headingOf(screen()); function expireStoredOrder(orderId: string): void { const orders = JSON.parse(storage.getItem("sb.orders.v1")!) as Array>; orders.find((o) => o.orderId === orderId)!.status = "expired"; storage.setItem("sb.orders.v1", JSON.stringify(orders)); } function scripts(): StubElement[] { return page.document.head.children.filter((c): c is StubElement => c instanceof StubElement); } function stripeTags(): StubElement[] { return scripts().filter((s) => (s.getAttribute("src") ?? "").includes("js.stripe.com")); } cardTest("main: nothing of Stripe's is fetched at page load", () => { assert.equal(heading(), "Support SimpleX", "the boot is the landing screen"); assert.equal(scripts().length, 0, "the shell adds no script of its own"); assert.equal(stripeTags().length, 0, "Stripe.js is loaded on the card path and nowhere else"); assert.ok(!fetches.some((f) => f.url.includes("stripe")), "and nothing requested it another way"); }); function walkToCard(): void { const primary = (): StubElement => primaryOf(screen())!; if (heading() === "Support SimpleX") primary().click(); if (heading() === "Choose your badge") { screen().all("button.choice").find((c) => c.textContent.startsWith("Legend"))!.click(); primary().click(); } if (heading() === "How long?") { screen().all("button.choice").find((c) => c.textContent.startsWith("12 months"))!.click(); primary().click(); } assert.equal(heading(), "Check your order"); screen().all("button.choice").find((c) => c.textContent.startsWith("Card"))!.click(); } function cardCreated(invoiceId: string): void { page.respondWith({ status: 200, body: { invoiceId, badgeType: "legend", months: 12, amount: 42000, currency: "usd", expiresAt: "2126-08-28T13:00:00Z", clientSecret: CLIENT_SECRET, }, }); } cardTest("main: with NO key the card path is unavailable, and still loads nothing", async () => { walkToCard(); cardCreated("inv_card_1"); screen().all("button.primary")[0]!.click(); await until(() => location.search === "?order=inv_card_1", "the card invoice"); await settle(); assert.equal(heading(), "The card form did not load"); assert.ok(screen().textContent.includes("Card payment is not available on this page."), "an unconfigured page names the card lane as unavailable, and offers no form"); assert.equal(screen().all("div.card-mount").length, 0); assert.equal(stripeTags().length, 0, "no key, no script — the gate is before the load"); assert.ok(!screen().textContent.includes(CLIENT_SECRET), "the client secret is never on screen"); const stored = JSON.parse(storage.getItem("sb.orders.v1")!) as Array>; assert.ok(stored[0]!.code!.startsWith("SB-")); assert.ok(!screen().serialize().includes(stored[0]!.code!), "and never on an unpaid screen"); assert.equal(storage.getItem("sb.orders.v1")!.includes(CLIENT_SECRET), false, "the store rules: clientSecret is never written to rest"); }); cardTest("main: the order summary withholds Pay while a card payment awaits confirmation", async () => { const orders = JSON.parse(storage.getItem("sb.orders.v1")!) as Array>; orders.find((o) => o.orderId === "inv_card_1")!.submitted = true; storage.setItem("sb.orders.v1", JSON.stringify(orders)); history.back(); await settle(); assert.equal(heading(), "How long?", "Back lands on the wizard"); primaryOf(screen())!.click(); assert.equal(heading(), "Check your order"); assert.ok(screen().textContent.includes(screens.AWAITING_CARD_TITLE), screen().textContent); assert.equal(screen().all("button.primary").length, 0, "and no Pay button at all"); assert.ok(!screen().textContent.includes("Pay $"), "not even a disabled one to press"); const link = screen().all("a.link")[0]!; assert.equal(link.getAttribute("href"), "?order=inv_card_1", "the order is linked, so nobody is stranded"); assert.ok(screen().textContent.includes("When its invoice expires, a new one can be started there."), "and the way out is named: the closed-window screen offers a new invoice once this one expires"); const before = fetches.length; await settle(); assert.equal(fetches.slice(before).filter((f) => f.url === "/api/invoice").length, 0); }); cardTest("main: Back from a payment screen to the order summary, and Pay still works", async () => { expireStoredOrder("inv_card_1"); history.back(); await settle(); assert.equal(heading(), "How long?", "Back lands on the wizard, not on the replaced #/checkout"); screen().all("button.choice").find((c) => c.textContent.startsWith("3 months"))!.click(); primaryOf(screen())!.click(); assert.equal(heading(), "Check your order"); assert.ok(screen().textContent.includes("$140.00"), `3 legend months are $140: ${screen().textContent}`); screen().all("button.choice").find((c) => c.textContent.startsWith("Card"))!.click(); configureKey(PUBLISHABLE_KEY); const before = fetches.length; page.respondWith({ status: 200, body: { invoiceId: "inv_card_2", badgeType: "legend", months: 3, amount: 14000, currency: "usd", expiresAt: "2126-08-28T13:00:00Z", clientSecret: CLIENT_SECRET, }, }); screen().all("button.primary")[0]!.click(); await until(() => location.search === "?order=inv_card_2", "the second card invoice"); await settle(); const post = fetches.slice(before).find((f) => f.url === "/api/invoice"); assert.ok(post, "Pay must actually submit — a dead primary button is worse than an error"); const body = JSON.parse(String(post.init!.body)) as Record; assert.equal(body.priceId, "price_legend", "the level the panel was drawn with"); assert.equal(body.offerId, "offer_3m", "and the duration the buyer just chose, not the old order's"); assert.equal(body.method, "card"); }); cardTest("main: with a key configured the card form loads Stripe.js and awaits its Element", () => { assert.equal(heading(), "Pay by card"); assert.equal(screen().all("div.card-mount").length, 1, "the Payment Element mounts here"); assert.equal(stripeTags().length, 1, "exactly one script tag, and only now"); assert.equal(stripeTags()[0]!.getAttribute("src"), stripe.STRIPE_JS_URL); const pay = screen().all("button.primary")[0]!; assert.ok(pay.hasAttribute("disabled"), "nothing is payable until the Element is mounted"); }); cardTest("main: a Stripe.js that fails to load lands on the failure screen, not a blank panel", async () => { stripeTags()[0]!.dispatch("error"); await settle(); assert.equal(heading(), "The card form did not load"); assert.ok(screen().textContent.includes("Nothing was charged")); assert.ok(screen().textContent.includes("inv_card"), "with the reference, so support is reachable"); assert.equal(screen().all("div.card-mount").length, 0, "and no empty box where the fields were"); }); const elements: Array<{ node: unknown; destroyed: boolean }> = []; const confirms: number[] = []; let lastReturnUrl = ""; let heldConfirm: { promise: Promise; release: () => void } | null = null; function holdNextConfirm(): void { let release = (): void => {}; const promise = new Promise((r) => { release = r; }); heldConfirm = { promise, release }; } (globalThis as unknown as { window: Record }).window.Stripe = (key: string) => { assert.equal(key, PUBLISHABLE_KEY, "the page's own configured key, and no other"); return { elements: (options: { clientSecret: string }) => { assert.equal(options.clientSecret, CLIENT_SECRET); return { create: (kind: string) => { assert.equal(kind, "payment", "the Payment Element, not a bare card field"); const element = { node: null as unknown, destroyed: false }; elements.push(element); return { mount: (node: unknown) => { element.node = node; }, destroy: () => { element.destroyed = true; }, }; }, }; }, confirmPayment: async (options: { confirmParams: { return_url: string } }) => { confirms.push(1); lastReturnUrl = options.confirmParams.return_url; if (heldConfirm !== null) await heldConfirm.promise; return { paymentIntent: { status: "succeeded" } }; }, }; }; cardTest("main: [ Try again ] asks for the script again, and a load mounts the Element", async () => { screen().all("button.primary")[0]!.click(); // [ Try again ] await settle(); assert.equal(heading(), "Pay by card"); assert.equal(stripeTags().length, 1, "the failed load is retried with a fresh tag, and only that"); stripeTags()[0]!.dispatch("load"); await settle(); assert.equal(elements.length, 1, "the Element was mounted"); assert.equal(elements[0]!.node, screen().all("div.card-mount")[0], "into the node on screen"); const pay = screen().all("button.primary")[0]!; assert.ok(!pay.hasAttribute("disabled"), "and only now is the order payable"); assert.equal(confirms.length, 0, "mounting confirms nothing"); }); cardTest("main: a remount DESTROYS the Element it replaces, and loads no second script", async () => { page.setOffline(true); await settle(); try { assert.equal(heading(), "The card form did not load"); assert.ok(screen().textContent.includes("You are offline"), screen().textContent); assert.equal(elements.length, 1, "and nothing new was mounted"); assert.equal(elements[0]!.destroyed, true, "the Element that was on screen is gone"); } finally { // Restored even if an assertion above fails, or the offline backoff on real timers would hang this process. page.setOffline(false); await settle(); } assert.equal(heading(), "Pay by card"); assert.equal(elements.length, 2, "coming back mounts a fresh Element"); assert.equal(elements[1]!.destroyed, false, "which is the live one"); assert.equal(elements[1]!.node, screen().all("div.card-mount")[0]); assert.equal(stripeTags().length, 1, "one load per page: the global is reused, not re-fetched"); assert.ok(!screen().all("button.primary")[0]!.hasAttribute("disabled"), "and it is payable again"); }); cardTest("main: a connectivity flap must not remount the form under an in-flight confirm", async () => { holdNextConfirm(); const mounted = elements.length; const node = screen().all("div.card-mount")[0]; screen().all("button.primary")[0]!.click(); // Pay await settle(); assert.equal(confirms.length, 1, "the press issued one confirm"); assert.ok(screen().all("button.primary")[0]!.hasAttribute("disabled"), "and the button went busy"); page.setOffline(true); await settle(); page.setOffline(false); await settle(); assert.equal(heading(), "Pay by card", "the form the confirm belongs to is still the screen"); assert.equal(elements.length, mounted, "nothing was remounted under the in-flight confirm"); assert.equal(elements[mounted - 1]!.destroyed, false, "and the live Element was not torn down"); assert.equal(screen().all("div.card-mount")[0], node, "it is the same form, with whatever was typed into it"); assert.ok(screen().all("button.primary")[0]!.hasAttribute("disabled"), "the busy state survives the repaint — a re-enabled button is a second charge"); assert.equal(confirms.length, 1, "and still exactly one confirm was issued"); heldConfirm!.release(); heldConfirm = null; await until(() => heading() === "Payment received", "the confirming screen once the confirm resolves"); assert.equal(confirms.length, 1); }); cardTest("main: a real confirm ALSO lands on the confirming screen, and the confirming screen alone", async () => { assert.equal(heading(), "Payment received"); assert.ok(screen().textContent.includes("Waiting for the card network to confirm."), "the confirming screen waits: a confirm is a hint, the provider is what settles it"); assert.equal(confirms.length, 1, "one press, one confirm"); assert.ok(fetches.some((f) => f.url.startsWith("/api/invoice/inv_card_2")), "the waiting loop is polling"); assert.ok(lastReturnUrl.length > 0 && !lastReturnUrl.includes("inv_card_2"), `the return URL leaks no order id: ${lastReturnUrl}`); assert.ok(elements.every((e) => e.destroyed), "and the form it left behind took its Element with it"); assert.equal(screen().all("button").filter((b) => b.textContent === "Buy a new code").length, 0); assert.ok(!screen().textContent.includes("Here is your code")); const stored = (JSON.parse(storage.getItem("sb.orders.v1")!) as Array>) .find((o) => o.orderId === "inv_card_2")!; assert.equal(stored.status, "open", "nothing about the order changed: the provider decides"); assert.ok(!screen().serialize().includes(stored.code!)); assert.equal(stored.submitted, true); assert.equal(storage.getItem("sb.session.v1"), null, "and not in the session"); }); cardTest("main: the code appears only when the SERVER says paid", async () => { const stored = (JSON.parse(storage.getItem("sb.orders.v1")!) as Array>) .find((o) => o.orderId === "inv_card_2")!; page.respondWith({ status: 200, body: { status: "paid", badgeType: "legend", months: 3, settledAt: "2026-08-28T11:20:00Z" }, }); page.fire("popstate"); await until(() => heading().startsWith("Paid"), "codeIssued"); assert.ok(screen().serialize().includes(stored.code!), "the code screen is the one screen that shows it"); });