Practice
Web Automation Practice Playground
Real apps aren't just login forms. Practise resilient locators and automation patterns against dynamic IDs, filterable tables, modals, delayed toasts, and file uploads. Pick a framework and each module shows a working solution snippet.
Dynamic login form
BeginnerStable label and data-testid, but a regenerating element id — practise resilient locators.
Challenge: Sign in with valid credentials and assert the success message.
Skills: label/role locators, avoiding dynamic IDs, assertions
await page.getByLabel('Email address').fill('qa@example.com');
await page.getByLabel('Password').fill('Password123!');
await page.getByTestId('pg-submit').click();
await expect(page.getByText('Signed in successfully.')).toBeVisible();Search & filter table
IntermediateSearch, status filter, and an empty state — locate rows by content, not index.
| Test | Status |
|---|---|
| Login API | Passing |
| Checkout flow | Failing |
| Search results | Passing |
| Profile update | Skipped |
| Password reset | Failing |
Challenge: Filter to Failing tests and assert the row count.
Skills: locating by text, filtering, asserting collections
await page.getByTestId('pg-status').selectOption('Failing');
await expect(page.locator('[data-testid="pg-table-body"] tr')).toHaveCount(2);Modal dialog
IntermediateOpen/close, backdrop and Esc dismissal — locate by role and test keyboard behaviour.
Challenge: Open the dialog, confirm it's visible, and close it with Esc.
Skills: role locators, keyboard events, visibility assertions
await page.getByTestId('pg-open-modal').click();
await expect(page.getByRole('dialog')).toBeVisible();
await page.keyboard.press('Escape');
await expect(page.getByRole('dialog')).toBeHidden();Toast & loader
IntermediateA delayed toast with a disabled button while saving — practise auto-waiting, not fixed sleeps.
Challenge: Click Save and wait for the success toast (no fixed waits).
Skills: auto-waiting, transient states, disabled assertions
await page.getByTestId('pg-save').click();
await expect(page.getByTestId('pg-save')).toBeDisabled();
await expect(page.getByTestId('pg-toast')).toBeVisible();File upload
AdvancedA labelled file input with type validation — automate uploads and the invalid-type path.
Challenge: Upload a valid file and assert the confirmation.
Skills: file inputs, validation paths, assertions
await page.getByTestId('pg-file').setInputFiles('avatar.png');
await expect(page.getByTestId('pg-file-ok')).toBeVisible();Keep going