Catalog
All 24 drills
Search by title, or combine difficulty/category/locator/action filters. Prefer a pre-filtered link instead? Browse by category or difficulty directly. Looking for something that combines several skills into one flow? Try a Scenario.
Async City Search
A debounced combobox fetches suggestions as you type, built with real `role="combobox"`/`aria-expanded` semantics — practice ARIA-role locators and waiting for async results.
Auto-Dismissing Toast
A success toast appears and vanishes after ~2.5s — a pure hardcoded `sleep()` will race it.
Custom (Div-Based) Dropdown
A JS-built dropdown with no native `<select>` — clicking opens a listbox you must locate by role, not tag.
Custom Date Range Picker
A calendar widget spanning two months — select a start and end date across a month boundary.
Delayed Element
A button fetches `/api/delay` and reveals a result after a fixed delay — practice explicit waits instead of `sleep()`.
Duplicate Classes
Five buttons share one class and no unique attribute — practice `nth-of-type` and structural CSS.
Flaky Retry Button
This action fails at random about 40% of the time — your automation needs real retry logic, not a lucky run.
Keyboard-Only Form
Complete the entire form using Tab/Shift+Tab/Enter/Space only — no clicks allowed. Focus order matters.
Live SSE Ticker
A Server-Sent Events stream pushes a new row every couple of seconds — assert on content that only exists briefly.
Login
A mock login form with a fixed test user — practice a real form-submit-and-redirect flow.
Logout
Clears the session cookie and redirects — confirm the dashboard becomes unreachable again afterward.
Multi-Select Listbox
A native multi-select — practice ctrl/cmd-click and reading back the full selected set.
Native JS Confirm
A button triggers `window.confirm()` — accept or dismiss it and assert the result on the page.
Nested iframes
An iframe inside an iframe inside an iframe — the target button is three context switches deep.
No Unique Attributes
An element with no id, no class, no data-testid — only its text and position identify it.
Open Shadow Root Form
A `<custom-input>` web component renders its markup inside an open shadow root — `querySelector` on the document alone will not find it.
Protected Dashboard
Only reachable while logged in — visit it signed-out and you get redirected back to login.
Regenerating IDs
Every page load, the server mints a fresh random id/class — a hardcoded locator breaks on the very next run.
Right-Click Context Menu
A custom context menu appears only on right-click (contextmenu event) — practice dispatching non-primary-button clicks.
Single File Upload
Upload one file and see its name/size/type echoed back from the server — practice `input[type=file]` automation.
Single iframe
A form lives inside one iframe — you must switch context before you can interact with it.
Sortable List (Native HTML5 DnD)
Reorder a list using the native HTML5 drag-and-drop API — notoriously flaky to automate without dispatching real drag events.
Sortable, Filterable, Paginated Grid
A data grid with column sorting, a text filter, and pagination — locate a specific row after the sort order and page have changed.
Unique ID
A button with a stable, unique `id` — the friendliest locator there is.