VALIDATION LAB•PAYMENT FORM
Form Lab
Payment Form
Test a payment form with clearly labeled test card data only, covering success, declined card, authentication-required, expiry, CVV, ZIP, and save-card behavior.
Scenario
Payment forms are high-risk. QA must never use real card data, and automated tests should cover card formatting, decline handling, authentication states, and success feedback using provider-approved test cards.
Live widget · interact freely
Manual test checklist
- 1Read the visible warning before typing card details
- 2Submit an empty form and confirm required errors
- 3Use 4242 4242 4242 4242 and confirm successful payment
- 4Use 4000 0000 0000 0002 and confirm declined card error
- 5Use 4000 0025 0000 3155 and confirm authentication required
- 6Enter invalid CVV and expired date values and confirm validation errors
Expected result
Only test card numbers are accepted in the playground. Successful test payment shows a success message; declined and authentication-required cards show visible errors.
Automation challenge
Use only the labeled test card numbers. Fill card fields by label, use getByText() for the warning, assert declined-card errors, then assert the success toast for 4242.
Stable selectors
- Payment form
[data-testid="form-payment-form"] - Test card warning
[data-testid="form-payment-test-card-warning"] - Cardholder Name
[data-testid="form-payment-cardholder-name"] - Card Number
[data-testid="form-payment-card-number"] - Expiry Date
[data-testid="form-payment-expiry-date"] - CVV
[data-testid="form-payment-cvv"] - Billing ZIP
[data-testid="form-payment-billing-zip"] - Save card
[data-testid="form-payment-save-card"] - Validation result
[data-testid="form-payment-result"]
Locator strategy
Three levels from simple IDs to scoped Playwright locators. IDs and names are easy to learn but are not always the best long-term choice when labels change or components repeat.
Use simple IDs and names to understand how locating elements works. Form Lab pages expose predictable field ids and data-testid values for every control.
1234
await page.goto('https://lab.hakdogan.com/practice/form-payment');
await page.locator('[data-testid="form-payment-form"]').waitFor();
await page.locator('[data-testid="form-payment-submit"]').click();Avoid as primary strategies
XPath (unless there is no alternative), long CSS chains, Tailwind-style utility class selectors, generated or unstable IDs, and volatile framework internals break when layout, styling, or DOM structure shifts.
12
await page.locator('.w-full.rounded-xl.border.bg-blue-500').fill('demo@example.com');
await page.locator('//div[2]/form/div[1]/input').fill('demo@example.com');Reference Playwright spec
12345678910111213141516171819202122232425262728293031
import { test, expect } from '@playwright/test';
test.describe('form lab — payment form', () => {
test('successful test card payment', async ({ page }) => {
await page.goto('https://lab.hakdogan.com/practice/form-payment');
await expect(page.getByText(/test card data only/i)).toBeVisible();
await page.getByLabel('Cardholder Name').fill('QA Test');
await page.getByLabel('Card Number').fill('4242 4242 4242 4242');
await page.getByLabel('Expiry Date').fill('12/30');
await page.getByLabel('CVV').fill('123');
await page.getByLabel('Billing ZIP').fill('34000');
await page.getByLabel(/save card/i).check();
await page.getByRole('button', { name: /pay with test card/i }).click();
await expect(page.getByText(/payment successful/i)).toBeVisible();
});
test('declined test card shows error', async ({ page }) => {
await page.goto('https://lab.hakdogan.com/practice/form-payment');
await page.getByLabel('Cardholder Name').fill('QA Test');
await page.getByLabel('Card Number').fill('4000 0000 0000 0002');
await page.getByLabel('Expiry Date').fill('12/30');
await page.getByLabel('CVV').fill('123');
await page.getByLabel('Billing ZIP').fill('34000');
await page.getByRole('button', { name: /pay with test card/i }).click();
await expect(page.getByText(/declined card/i)).toBeVisible();
});
});Headed Test Playback
Simulated headed-browser flow — no real browser is launched.
Automation-style playback (Playwright-shaped logs). No real browser; no commands run on your machine.
form-payment.spec.ts- Read test-card warning
- Fill test card data
- Submit test payment
- Assert success or decline message