VALIDATION LAB•ADDRESS FORM
Form Lab
Address Form
Validate shipping/billing address fields including postal code format, numeric phone number, and required country.
Scenario
Address forms drive shipping, tax, and fraud checks. QA needs coverage for optional address line 2, country-dependent validation, postal formats, and phone normalization.
Live widget · interact freely
Manual test checklist
- 1Submit an empty address and confirm required errors
- 2Enter a postal code with symbols and confirm format validation
- 3Enter letters in Phone Number and confirm numeric validation
- 4Leave Country blank and confirm it blocks submit
- 5Fill a complete address and confirm the success state
Expected result
Invalid postal codes, non-numeric phone values, and missing country are blocked; complete address data submits successfully.
Automation challenge
Fill address fields by label, select Country, assert invalid postal and phone errors, then submit a valid address and assert the success toast.
Stable selectors
- Address form
[data-testid="form-address-form"] - Address Line 1
[data-testid="form-address-address-line-1"] - Address Line 2
[data-testid="form-address-address-line-2"] - City
[data-testid="form-address-city"] - State
[data-testid="form-address-state"] - Postal Code
[data-testid="form-address-postal-code"] - Country
[data-testid="form-address-country"] - Phone Number
[data-testid="form-address-phone-number"] - Validation result
[data-testid="form-address-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-address');
await page.locator('[data-testid="form-address-form"]').waitFor();
await page.locator('[data-testid="form-address-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
12345678910111213141516
import { test, expect } from '@playwright/test';
test('address form validates postal code and phone', async ({ page }) => {
await page.goto('https://lab.hakdogan.com/practice/form-address');
await page.getByLabel('Address Line 1').fill('QA Plaza 42');
await page.getByLabel('City').fill('Istanbul');
await page.getByLabel('State').fill('Kadikoy');
await page.getByLabel('Postal Code').fill('ABC!');
await page.getByLabel('Country').selectOption('TR');
await page.getByLabel('Phone Number').fill('phone');
await page.getByRole('button', { name: /save address/i }).click();
await expect(page.getByText(/postal code format/i)).toBeVisible();
await expect(page.getByText(/phone number must be numeric/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-address.spec.ts- Fill address fields
- Select country
- Validate postal and phone rules
- Assert saved address