VALIDATION LAB•RADIO BUTTONS
Selection
Radio Buttons
Switch between radio options and validate that exactly one option is selected at any time.
Scenario
Pricing pages, plan upgrades, payment method choice — radios drive money. A radio group that allows multiple selections (or none) leaks revenue or breaks trust.
Plan: Starter
Live widget · interact freely
Manual test checklist
- 1Click each option and confirm only one carries the visual selected state
- 2Use ↑ / ↓ arrows to navigate the group via keyboard
- 3Tab into the group — focus should land on the currently selected option
- 4Reload and confirm a default option exists (no empty state)
- 5Submit without changing anything — does the form post the default?
Expected result
Only one option carries the selected affordance; the visible plan summary reflects the chosen tier.
Automation challenge
After checking `radio-pro`, assert `radio-pro` is checked AND `radio-starter` is NOT checked in the same test — proves mutual exclusion, not just a positive click.
Stable selectors
- Plan: Starter
[data-testid="radio-starter"] - Plan: Pro
[data-testid="radio-pro"] - Plan: Enterprise
[data-testid="radio-enterprise"] - Selected plan
[data-testid="radio-selected"]
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.
123
await page.goto('https://lab.hakdogan.com/practice/radio');
await page.locator('#radio-pro').check();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
12345678910
import { test, expect } from '@playwright/test';
test('radio selection is mutually exclusive', async ({ page }) => {
await page.goto('https://lab.hakdogan.com/practice/radio');
await page.getByTestId('radio-pro').check();
await expect(page.getByTestId('radio-pro')).toBeChecked();
await expect(page.getByTestId('radio-starter')).not.toBeChecked();
await expect(page.getByTestId('radio-selected')).toHaveText('Plan: Pro');
});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.
radio.spec.ts- Selecting Pro plan
- Asserting Pro is checked
- Asserting Starter is unchecked