fix: make payment event reduction monotonic
This commit is contained in:
@@ -8,9 +8,35 @@ import {
|
||||
sandboxGateway,
|
||||
signSandboxWebhook,
|
||||
stripeGateway,
|
||||
derivePaymentStatus,
|
||||
verifyGatewayContract,
|
||||
} from "../src/index.ts";
|
||||
|
||||
test("gateway occurrence order and sticky terminal states prevent webhook regression", () => {
|
||||
const events = [
|
||||
{
|
||||
id: "refund",
|
||||
intentId: "p",
|
||||
type: "refunded",
|
||||
status: "refunded" as const,
|
||||
at: 100,
|
||||
occurredAt: 300,
|
||||
},
|
||||
{
|
||||
id: "late-capture-retry",
|
||||
intentId: "p",
|
||||
type: "captured",
|
||||
status: "captured" as const,
|
||||
at: 400,
|
||||
occurredAt: 200,
|
||||
},
|
||||
];
|
||||
expect(derivePaymentStatus(events)).toBe("refunded");
|
||||
expect(
|
||||
derivePaymentStatus([...events, { ...events[1], id: "new-id", at: 500, occurredAt: 500 }]),
|
||||
).toBe("refunded");
|
||||
});
|
||||
|
||||
test("sandbox drives webhook-authoritative capture and bounded partial refunds", async () => {
|
||||
const store = memoryPaymentStore(),
|
||||
gateway = sandboxGateway({ secret: "test-secret" });
|
||||
@@ -69,6 +95,34 @@ test("sandbox drives webhook-authoritative capture and bounded partial refunds",
|
||||
idempotencyKey: "refund-2",
|
||||
});
|
||||
expect(excessive).toMatchObject({ ok: false, fault: "refused" });
|
||||
expect(
|
||||
(
|
||||
await payment.refundPayment({
|
||||
id: created.value.id,
|
||||
amount: 600,
|
||||
reason: "remaining return",
|
||||
idempotencyKey: "refund-remaining",
|
||||
})
|
||||
).ok,
|
||||
).toBe(true);
|
||||
const stale = await signSandboxWebhook(
|
||||
{
|
||||
id: "evt-delayed-capture",
|
||||
intentRef: created.value.gatewayRef,
|
||||
type: "payment.captured",
|
||||
status: "captured",
|
||||
occurredAt: 1,
|
||||
},
|
||||
"test-secret",
|
||||
);
|
||||
await handler({
|
||||
req: new Request("https://app.test/webhook", {
|
||||
method: "POST",
|
||||
headers: { "x-wrnexus-signature": stale.signature },
|
||||
body: stale.body,
|
||||
}),
|
||||
});
|
||||
expect(await payment.checkPayment(created.value.id)).toBe("refunded");
|
||||
});
|
||||
|
||||
test("initialize, webhook, and refund replay change records once", async () => {
|
||||
|
||||
Reference in New Issue
Block a user