examples/storefront Public
import assert from "node:assert/strict";import { test } from "node:test";import Stripe from "stripe";import { cancelOrder, markPaid } from "../src/orders.ts";import { handleWebhook, type Env } from "../workers/payments/src/webhook.ts";import { NOW, setup } from "./helpers/app.ts";const SECRET = "whsec_test_secret";const CHECKOUT = { email: "ada@park.test", ship_to: { name: "Ada Park", line1: "12 Alder St", city: "Portland", postal_code: "97205", country: "US" } };// A paid-for order waiting for its webhook, and the webhook Worker wired to the same database// the way the ORDERS service binding wires it in production.async function pendingOrder() { const s = setup(); await s.addProduct("wool-socks", { price_cents: 1800, stock: 3 }); const cartId = (await s.call("POST", "/carts")).body.cart.id; await s.call("PUT", `/carts/${cartId}/items/wool-socks`, { quantity: 2 }); const order = (await s.call("POST", `/carts/${cartId}/checkout`, CHECKOUT)).body.order; const env: Env = { STRIPE_WEBHOOK_SECRET: SECRET, STRIPE_SECRET_KEY: "sk_test_unused", ORDERS: { markPaid: (id, intent) => markPaid(s.env.DB, s.events, id, intent, NOW), cancel: (id) => cancelOrder(s.env.DB, s.events, id, NOW), }, }; const deliver = async (type: string, intent: Record<string, unknown>, secret = SECRET) => { const payload = JSON.stringify({ id: `evt_${type}`, object: "event", type, data: { object: { object: "payment_intent", ...intent } } }); const header = await Stripe.webhooks.generateTestHeaderStringAsync({ payload, secret, cryptoProvider: Stripe.createSubtleCryptoProvider() }); const req = new Request("https://hooks.shop.test/stripe/webhook", { method: "POST", body: payload, headers: { "stripe-signature": header } }); return handleWebhook(req, env); }; const status = async () => (await s.call("GET", `/orders/${order.id}`)).body.order.status; return { ...s, order, deliver, status };}test("payment_intent.succeeded marks the order paid and announces it", async () => { const s = await pendingOrder(); const res = await s.deliver("payment_intent.succeeded", { id: `pi_${s.order.id}`, metadata: { order_id: s.order.id } }); assert.equal(res.status, 200); assert.equal(await s.status(), "paid"); assert.deepEqual(s.events.sent, [{ type: "order.paid", order_id: s.order.id, at: new Date(NOW).toISOString() }]);});test("a repeated delivery changes nothing but sends the event again", async () => { const s = await pendingOrder(); const intent = { id: `pi_${s.order.id}`, metadata: { order_id: s.order.id } }; await s.deliver("payment_intent.succeeded", intent); assert.equal((await s.deliver("payment_intent.succeeded", intent)).status, 200); assert.equal(await s.status(), "paid"); assert.equal(s.events.sent.length, 2, "at least once: fulfilment dedupes by order id");});test("an intent that is not the order's own does not pay it", async () => { const s = await pendingOrder(); await s.deliver("payment_intent.succeeded", { id: "pi_someone_else", metadata: { order_id: s.order.id } }); assert.equal(await s.status(), "pending_payment"); assert.deepEqual(s.events.sent, []);});test("payment_intent.canceled cancels the order and returns the stock", async () => { const s = await pendingOrder(); await s.deliver("payment_intent.canceled", { id: `pi_${s.order.id}`, metadata: { order_id: s.order.id } }); assert.equal(await s.status(), "cancelled"); assert.equal((await s.call("GET", "/products/wool-socks")).body.product.stock, 3); await s.deliver("payment_intent.canceled", { id: `pi_${s.order.id}`, metadata: { order_id: s.order.id } }); assert.equal((await s.call("GET", "/products/wool-socks")).body.product.stock, 3, "only once"); assert.deepEqual(s.events.sent.map((e) => e.type), ["order.cancelled"]);});test("refuses a payload that Stripe did not sign", async () => { const s = await pendingOrder(); const res = await s.deliver("payment_intent.succeeded", { id: `pi_${s.order.id}`, metadata: { order_id: s.order.id } }, "whsec_wrong"); assert.equal(res.status, 400); assert.equal(await s.status(), "pending_payment");});test("acknowledges events it does not handle", async () => { const s = await pendingOrder(); assert.equal((await s.deliver("payment_intent.created", { id: "pi_1", metadata: {} })).status, 200); assert.equal((await s.deliver("payment_intent.succeeded", { id: "pi_2", metadata: {} })).status, 200);});