Component Lab A · Actions

Button Components

Exercise native button semantics, forms, enabled states, pointer gestures, deterministic delays, DOM replacement, duplicate names, scoped actions, and appearance waits.

PRACTICE FIXTURE — intentionally built for automation practice

Normal, disabled, and icon actions

Native buttons expose role, accessible name, and disabled state without custom attributes.

Choose an available action.

Icon-only button without an accessible name

This deliberate defect should remain discoverable by role but has no accessible name.

Intentional anti-pattern

The defect is intentional and separately tested.

Submit and reset buttons

Use native form events and assert the result message after either action.

Form is ready.

Enabled after a condition

The action becomes enabled only after the confirmation checkbox is checked.

Action is disabled.

Double-click, context click, and long press

Each gesture reports a distinct assertion target. Long press completes after a bounded 650 ms hold.

Waiting for a gesture.

Controlled delayed response

Choose a bounded delay and wait for the final status rather than using a fixed test timeout.

No response requested.

Button replaced after click

The first click replaces the node. The replacement has a new ID and visible label.

Original node is attached.

Duplicate labels in named sections

Both buttons are called Save. Scope the locator to the intended region.

Profile settings

Danger zone

Nothing saved.

Nested-container button

Scope through a named billing region and nested card before selecting the action.

Billing

Billing unchanged.

Delayed-appearance button

A trigger reveals the target after exactly 500 ms and moves focus to it.

Action is hidden.

Passing examples

Start with observable behavior

These snippets match executable tests stored inexamples/playwright-ts/.

Role locator and result
await page.getByRole('button', { name: 'Run smoke test' }).click();
await expect(page.getByRole('status')).toContainText('Smoke test queued');
Scoped duplicate label
const dangerZone = page.getByRole('region', { name: 'Danger zone' });
await dangerZone.getByRole('button', { name: 'Save' }).click();
await expect(page.getByTestId('duplicate-result')).toHaveText('Saved danger section.');
DOM replacement
const original = page.getByRole('button', { name: 'Replace this button' });
await original.click();
await expect(original).not.toBeAttached();
await page.getByRole('button', { name: 'Replacement button' }).click();