x402 Progressive Demo · Chapter 6 of 7

Testing Infrastructure

How do we know it all actually works?
Published 2026-04-16 · Northwoods Software · x402 Payment Protocol

The Incident That Triggered This

We shipped three pull requests to a live production site. All three broke the build. A TypeScript strict-mode error, a BigInt syntax incompatibility, and a DNS failure in a price API we depended on — any one of which would have been caught by a 5-second automated test run.

The framework had zero automated tests. We had a 36-threat security model, two formal architecture reviews, and a live deployment serving real buyers — but not a single test that would say "this code still works" after a change. That's how bugs ship to production.

What We Built

A test suite that runs in 1.3 seconds, covers 39 scenarios across every adapter and every known attack vector, and requires zero external dependencies — no real blockchain, no real wallets, no API keys, no browser binaries.

$ npx vitest run

 ✓ __tests__/x402-client.test.js        (10 tests)
 ✓ __tests__/adapters/solana.test.js    (13 tests)
 ✓ __tests__/adapters/evm.test.js        (7 tests)
 ✓ __tests__/adapters/walletconnect.test.js (9 tests)

 Test Files  4 passed (4)
      Tests  39 passed (39)
   Duration  1.32s

What the Tests Cover

Client Core (10 tests)

The X402Client class — creation with valid/invalid config, adapter registry (register, chain, reject incomplete adapters), event emitter (subscribe, emit, unsubscribe), wallet detection aggregation across multiple chains, and pay-path error handling for unsupported chains and missing amounts.

Solana Adapter (13 tests)

Wallet detection (Phantom installed, multiple wallets, no wallet). USDC verification with 8 attack scenarios drawn directly from our security threat model:

TestAttack Blocked
Non-existent txHashFake payment submission
Failed transaction (meta.err)Reverted tx used as proof
No transfer to expected recipientPayment sent to wrong wallet
Partial payment ($0.50 for a $12 item)Underpayment fraud
Correct amount (positive test)Proves legitimate payments work
Net-delta refund attackJupiter multi-hop: credit $10, claw back $9.50 in same tx
Wrong token (non-USDC program)Scam token impersonation
Stale transaction (older than order)Reusing an ancient unrelated payment
The net-delta refund attack test is the highest-value security test in the suite. It verifies that the framework correctly computes the NET received amount when a single transaction contains both a credit and a debit to the merchant's account — blocking a sophisticated attack where a DEX aggregator sends USDC then claws it back in the same atomic transaction.

EVM Adapter (7 tests)

Same attack coverage for Base/Polygon/Arbitrum USDC: valid transfer, not-found, failed, wrong recipient, partial payment, wrong token contract, and the EVM version of the net-delta refund attack (two Transfer events in one receipt — credit then debit).

WalletConnect Adapter (9 tests)

Deep link URL generation for Phantom and Solflare (including edge cases: query params, fragments, localhost). Mobile vs desktop user-agent detection. WalletConnect project ID handling. Deep-link redirect throw behavior. WC relay error messaging.

How the Tests Work

Vitest + jsdom — the test runner executes in Node with a simulated browser environment. No real browser binaries, no Playwright for the unit tests. Wallet providers are mocked via reusable factory functions:

// From __tests__/helpers/mock-providers.js
function mockPhantomProvider(opts = {}) {
  return {
    isPhantom: true,
    connect: async () => ({
      publicKey: { toString: () => opts.pubkey || 'FakePubkey...' }
    }),
    signTransaction: async (tx) => {
      if (opts.rejectSign) throw new Error('User rejected')
      return { serialize: () => new Uint8Array(256) }
    },
  }
}

Verification tests use real transaction JSON as fixtures. The $0.02 USDC payment from April 14 (the first live x402 sale) is captured as a fixture file. Attack scenarios are crafted variants of that real data. Because the fixtures are raw Solana/EVM RPC response JSON, they only break if the blockchain protocol itself changes — which is a governance-level event, not a routine update.

What This Prevents

Had this test suite existed earlier, three bugs would have been caught before they reached a production site:

Going forward, every PR to the framework runs npx vitest run before push. If it doesn't pass, it doesn't ship.