Skip to main content

How to Test Multi-Vendor Marketplace Checkout

Short answer

Marketplaces combine checkout, inventory, shipping, and payouts—failure modes multiply. E2E must probe split cart payment allocation, commission per vendor_id, and vendor-specific shipping after Stripe payment succeeds—not a single order total alone.

Part of Testing Guides by business flow.

Who this is for

Multi-vendor platforms (Etsy-like, B2B marketplaces, food delivery) with split carts, Stripe Connect, or internal ledger payouts.

Why testing marketplaces matters

  • Seller trust — wrong commission or delayed payout.
  • Buyer experience — single checkout charge but split shipping confusion.
  • Compliance — KYC-gated vendors still selling when probe says suspended.

Complexity map

ScenarioEdge caseWhy tests breakApproach
Split cartTwo vendorsSingle payout wrongProbe ledger lines per vendor
Commission %Tiered by categoryWrong take rateSeed category; probe fee
Vendor shippingDifferent carriersBuyer one rate shownProbe per-vendor ship lines
Connect transferDelayed transferSeller UI wrongPoll transfer probe
Vendor suspendedStill in cartCheckout allowedSeed suspended; probe block
Partial cancelOne vendor lineRefund split wrongSee returns guide
Tax per vendorNexus differsWrong tax splitProbe tax by vendor
Single vendor cartRegressionSplit logic breaksControl scenario
Platform fee capMax feeUnderchargeProbe fee clamp
CurrencyVendor paid EURFX wrongProbe settlement currency
Inventory per vendorVendor A OOSWhole cart blocked?Probe partial checkout policy

Arrange: multi-vendor catalog

// POST /api/test/seed-marketplace
// { runId, vendors: [{ id: 'v1', commission: 0.15 }, { id: 'v2', commission: 0.10 }] }

const { vendorA, vendorB, skuA, skuB } = await request.post('/api/test/seed-marketplace', {
data: { runId },
}).then(r => r.json());

Split checkout E2E

await page.goto('/cart');
await page.getByTestId(`add-${skuA}`).click();
await page.getByTestId(`add-${skuB}`).click();
await page.goto(`/checkout?runId=${runId}`);
await completeStripeCheckout(page, runId);

const ledger = await request.get(`/api/test/probes/payouts/${runId}`).then(r => r.json());
expect(ledger.entries).toHaveLength(2);
expect(ledger.entries.find(e => e.vendorId === vendorA).commission).toBeCloseTo(0.15, 2);
expect(ledger.platformFee + ledger.entries.reduce((s, e) => s + e.net, 0)).toBe(ledger.gross);

Vendor shipping rules

Seed vendor A flat $5, vendor B free over $50; cart with both—probe two shipping sub-lines or combined policy per product rules.

Stripe Connect notes

Use Connect test accounts; transfers may async—expect.poll on transfer probe. Document Stripe Connect testing.

Connect transfer probe

await expect.poll(async () => {
const t = await request.get(`/api/test/probes/connect-transfers/${runId}`).then(r => r.json());
return t.every(entry => entry.status === 'paid');
}, { timeout: 45_000 }).toBe(true);

Buyer-facing order confirmation

After payment, probe per-vendor sub-orders if buyers receive split confirmations:

const orders = await request.get(`/api/test/probes/orders/${runId}`).then(r => r.json());
expect(orders.childOrders).toHaveLength(2);
expect(new Set(orders.childOrders.map(o => o.vendorId))).toEqual(new Set([vendorA, vendorB]));

CI checklist

  1. Seed marketplace catalog per runId—never shared vendor SKUs across workers
  2. Pass metadata.e2e_run on platform charge for teardown correlation
  3. Probe ledger before UI confirmation email specs
  4. Run split-cart scenario on every PR; Connect transfer poll optional on nightly
  5. Teardown test Connect accounts when your integration creates many per run

Anti-patterns

Anti-patternWhy it failsBetter approach
Single-vendor onlySplit math untestedTwo-vendor minimum
Assert order totalPayout wrongProbe ledger
Shared vendor idsParallel collisionrunId in vendor seed
Skip suspended vendorFraud pathNegative probe

Example scenario

Situation: Buyer checks out cart with items from two vendors in one payment.

Expected outcome: Single charge; ledger shows correct commission and net per vendor.

Why UI-only automation breaks: Order confirmation shows one vendor; second seller never notified.

  1. Arrange: Seed two vendors with distinct commission rates and SKUs.
  2. Act: Single checkout with 4242.
  3. Assert: Probe payout ledger + vendor notification flags per vendor_id.

TestChimp workflow: Track vendor_id × payout_rule in TrueCoverage when new sellers onboard.

Same Arrange/Act/Assert pattern as expired-coupon checkout.

Connect scenarios to your QA workflow

Capture business rules in markdown test plans and enforce them with seed routes and probe Assert. Link SmartTests with // @Scenario: for requirement traceability. Use /testchimp test on PRs; /testchimp explore on SmartTest paths for non-functional gaps (ExploreChimp).

External references

Frequently asked questions

How do I test split payouts in E2E?

Checkout cart with items from two seeded vendors, complete payment, probe ledger shows correct commission and net per vendor_id.

Do I need Stripe Connect test accounts?

If prod uses Connect, yes—create connected accounts in test mode and probe transfer ids. Internal ledger marketplaces probe your payout table instead.

How do vendor shipping rules combine at checkout?

Probe shipping line structure—per-vendor sub-lines or platform-combined rate—matching prod policy; seed vendors with different rules.

What if one vendor is out of stock?

Test prod policy: block whole cart vs allow partial checkout; probe inventory and order lines accordingly.

How do partial refunds work multi-vendor?

Refund one vendor line; probe refund splits commission reversal per vendor—see returns guide.

Suspended vendor still listed—how to test?

Seed vendor status suspended; probe checkout rejects or removes lines; API must not accept direct SKU buy URL.

How do we cover all active vendors?

TrueCoverage on vendor_id × payout_rule for top sellers. Run /testchimp evolve when new payout tiers ship—not every long-tail vendor needs E2E.

Apply these patterns in your repo

Run `/testchimp init` to connect TestChimp to your repo, then `/testchimp test` on PRs to turn these patterns into maintained SmartTests. Use `/testchimp evolve` when you want to expand coverage as your app grows.

Start free on TestChimp · Book a demo