orvacon

testkit

Drive orvacon flows in a test — no gateway, no database, no network.

@orvacon/testkit lets you (and orvacon itself) drive the full payment lifecycle in a unit test with no gateway account, no Postgres, and no network. It's a published dev dependency:

bun add -D @orvacon/testkit

The mock connector and database productize the core's own test doubles, so your test exercises the real orchestrator — not a stand-in that might drift from the contract.

A complete flow, in memory

import { idempotencyKey, money, orvacon } from "@orvacon/paykit";
import { mockConnector, mockDatabase, mockCallback, testCards, testSigningKey } from "@orvacon/testkit";

const db = mockDatabase();
const orva = orvacon({
  database: db,
  connectors: [mockConnector()],
  webhookSigningKey: testSigningKey,
});

const outcome = await orva.authorize({
  idempotencyKey: idempotencyKey(crypto.randomUUID()),
  amount: money(2500, "TRY"),
  source: { type: "card", card: testCards.success },
  threeDSecure: true,
});

// 3-D Secure: finalize with the callback the gateway would have POSTed.
if (outcome.ok && outcome.status === "requires_action") {
  await orva.handleWebhook(
    "mock",
    mockCallback({ paymentId: outcome.paymentId, amount: money(2500, "TRY") }),
  );
  // db.payments.get(outcome.paymentId)?.status === "captured"
}

What it provides

Export
mockConnector(opts?)A deterministic in-memory gateway — see below.
mockDatabase()An in-memory DatabaseAdapter; .payments, .ledger, .idempotency are exposed for assertions.
mockCallback(input)The RawWebhook a 3-D Secure callback delivers — pass it to handleWebhook.
mockReconcile(input)A resolved ReconcileOutcome for the reconcile option, to drive reconcile().
testCards / testTokenMagic fixtures: success, declined, gatewayError.
testSigningKey / testPublicKeyA throwaway Ed25519 pair, so no orvacon keys is needed.

The mock connector

Outcomes are deterministic — the card decides them, the way a gateway sandbox publishes fixed numbers:

testCards.…Result
successauthorizes; with threeDSecure: true, returns requires_action
declined{ ok: false, error: { code: "declined" } } — final
gatewayError{ ok: false, error: { code: "gateway_error" } } — the one auto-retry class

Tune it with options:

mockConnector({ capabilities: { autoCapture: true } }); // captures at authorize, no separate capture

Reconcile

mockConnector implements retrievePayment, so orva.reconcile() works. By default a pending payment stays pending (a no-op). To drive the settled-but-unreflected path, return mockReconcile:

mockConnector({
  reconcile: (input) =>
    mockReconcile({ paymentId: input.paymentId, type: "payment.captured", amount: money(2500, "TRY") }),
});
// orva.reconcile(paymentId) now advances a requires_action payment to captured.

Test fixtures only

testSigningKey is a real Ed25519 secret published in this package — it exists purely so a test can construct an orvacon instance. Never use it in production.

On this page