dánwòdánwò

Payments

Stripe.js and cards

A stand-in for Stripe.js on js.stripe.com, with card fields a test can fill and Stripe's test cards deciding each outcome.

Pages that load Stripe.js get danwo's stand-in from js.stripe.com. It gives you Stripe(key) and its Elements as plain inputs, so a test can type a card number like a person would.

Why a stand-in

The real Stripe.js runs inside Stripe's own iframes and talks to Stripe's servers. It can't run against an emulator. The stand-in keeps the same API, so your page's code doesn't change, and loadStripe and @stripe/react-stripe-js load it without knowing.

Set up

Nothing extra: stripeService answers js.stripe.com as well as the API. Your page keeps its own pk_test_ key.

danwo.config.ts
import { appEnvironment, defineConfig, stripeService } from "@danwo/sdk"

export default defineConfig({
  testDir: "tests",
  environment: () =>
    appEnvironment({
      app: { command: "npm run dev", url: "http://localhost:3000" },
      services: [stripeService()],
    }),
})

Use it in a test

Each Element is a labelled input. Fill them by label, then submit your own form:

tests/card.danwo.ts
import { test } from "@danwo/sdk"

test("saves a card", async ({ app, screen, expect }) => {
  await app.open("/billing")
  await screen.getByLabel("Card number").fill("4242 4242 4242 4242")
  await screen.getByLabel("Expiration date").fill("12/34")
  await screen.getByLabel("Security code").fill("123")
  await screen.getByRole("button", { name: "Save card" }).click()

  await expect(screen.getByText("Card saved")).toBeVisible()
})

The address Element's fields are labelled the same way: "Full name", "Address line 1" and so on.

Test cards

The card number decides what happens, as on Stripe:

Card numberOutcome
4242 4242 4242 4242Succeeds
4000 0000 0000 0002Declined
4000 0025 0000 3155Needs authentication (3-D Secure)

On the server side, use Stripe's test payment methods instead; see Stripe billing.

What's covered

AreaCovered
ElementsCard, payment, address, link and express checkout Elements, each a plain input.
ConfirmingConfirming payments and setups, for cards and the Payment Element.
Other callsCreating payment methods and reading intents back.
CheckoutredirectToCheckout opens the emulator's hosted page.
WalletspaymentRequest() reports that no wallet is available.

The emulator accepts a pk_test_ key only on these calls, and an intent only with its own client secret, as Stripe does.

Faults

Loading Stripe.js counts as loading the page, so the fault matrix leaves the script alone. The calls it makes to api.stripe.com get the usual Stripe faults: 500, 429, a reset, and an answer lost after a write.

Fidelity

Not checked live. The stand-in follows Stripe.js's documented API. The API calls behind it are the same ones the live Stripe suite checks.

Not covered yet

  • Apple Pay, Google Pay and Link wallets: express checkout shows no wallet
  • IBAN and other bank Elements
  • How the real Elements look: the stand-in's inputs are plain

Next

On this page

Run it on every pull request

A GitHub check and one comment per pull request, with the flight records attached.

Set up CI