Practice automation on real-world UI patterns
Twenty self-contained modules with forms, tables, waits, dialogs, frames, shadow DOM, drag and drop, file transfers and dummy REST endpoints. Every element exposes stable ids and data-testid attributes so you can focus on writing good tests.
GET|POST|PATCH|DELETE https://klauders.com/automate-the-internet?api=<endpoint>
Open the API reference →
Login & session
Authenticate against a dummy endpoint. Covers success, invalid credentials, locked account and empty-field validation.
POST ?api=auth/loginPOST ?api=auth/logoutRegistration & validation
Client-side and server-side validation, inline field errors, a password strength meter and a conflict response for a duplicate email.
POST ?api=registerForm controls
Checkboxes, radios, single and multi selects, slider, toggle switch, color and time inputs, plus disabled and read-only fields. The JSON panel reflects the current state.
Users data table
Server-side search, filters, sorting and pagination. Row actions update status or delete a user after a confirmation modal. User #1 cannot be deleted (403).
GET ?api=usersPATCH ?api=users&id=DELETE ?api=users&id=| Actions |
|---|
Dynamic content & waits
Elements that load after a random delay, get added or removed, change their id on every click, or become enabled asynchronously. Avoid fixed sleeps.
A. Delayed rendering (1.5–4s)
Hello World!
B. Add / remove elements
C. Dynamic id (use a stable locator)
current id:D. Enable / disable asynchronously
E. Remove / restore a checkbox
F. Disappearing element (one link is missing on random loads)
Async job & polling
Start a report export that returns 202 Accepted, then poll the job status until it completes (~6s). Ideal for testing polling, progress bars and timeouts.
POST ?api=jobsGET ?api=jobs&id=Native browser dialogs
JavaScript alert, confirm and prompt. Practice switching to the alert, accepting, dismissing and sending text.
Result: —
Modals, toasts & cookie banner
An accessible modal with focus handling and Escape to close, auto-dismissing toast notifications, and a cookie banner that appears on first visit and can block clicks.
Modal result: —
iFrames & new windows
Switch into an iframe to fill a form that posts a message back to the parent page. Open a link in a new tab and a popup window to practice window handles.
Message from iframe: —
Shadow DOM
A web component with an open shadow root. Its inner input and button are not reachable with normal CSS selectors; pierce the shadow boundary.
Light DOM mirror: —
Drag & drop board
An HTML5 drag-and-drop kanban. Move test cases between columns and assert the counters and order. Selenium may need a JavaScript workaround for native HTML5 drag events.
To do0
In progress0
Done0
Hover, tooltips & context menu
Captions revealed on hover, a tooltip on hover or focus, a nested hover menu and a custom right-click context menu.
Last action: —
Tabs & accordion
ARIA tabs with arrow-key navigation and an accordion with expandable panels. Assert visibility and aria-expanded / aria-selected states.
- checkout › applies coupon (timeout)
- login › locked user message
- table › sorts by date
- upload › rejects large file
Autocomplete search
A debounced combobox that queries the API as you type. Select with the mouse or with arrow keys and Enter; Escape closes the list.
GET ?api=search&q=Selected: —
No results
Cart & checkout flow
An end-to-end purchase journey: load products, add to cart, change quantities, apply a coupon and place the order. Includes an out-of-stock item and stock limit errors.
GET ?api=productsGET ?api=coupon&code=POST ?api=ordersLoading products…
Coupons: QA10 (10%), KLAUDERS20 (20%), EXPIRED (410 Gone), anything else (404).
File upload & download
Upload through a file input or drag-and-drop zone (max 2 MB, multipart/form-data) and download CSV or JSON exports served with Content-Disposition headers.
POST ?api=uploadGET ?api=export&format=Keyboard events
Send key presses and modifier combinations. The page reports the last key and keeps a short log. Press Ctrl/⌘ + K anywhere to focus the field.
You entered: —
Infinite scroll
A scrollable activity feed that fetches the next page when you reach the bottom, until the end of the feed (60 items).
GET ?api=feed&page=Loaded items: 0
API status console
Trigger specific HTTP status codes, slow responses, a flaky endpoint (40% 503) and a client-side timeout. Use it to test error states, retries and request interception.
GET ?api=status&code=GET ?api=slow&delay=GET ?api=flaky// Click a button to send a request
Network log
Every request made by this page is listed here with method, endpoint, status and duration, which helps you compare what the UI did with what your test intercepted.
| Method | Endpoint | Status | Time |
|---|
API reference
Every dummy endpoint can be called directly from RestAssured, Postman, Playwright APIRequestContext, Cypress cy.request or curl. All of them share one base URL; the endpoint goes in the api query parameter.
https://klauders.com/automate-the-internet
- JSON responses include Content-Type: application/json, Cache-Control: no-store and an X-Request-Id header that matches the requestId field in the body.
- Every response is delayed a random 150–650 ms on purpose (except slow and export), so keep time assertions loose.
- Errors share one shape: {"error", "message", "requestId"}. A wrong HTTP method returns 405 with an Allow header, and an unknown api value returns 404 unknown_endpoint.
- Nothing is stored. PATCH and DELETE answer as if they worked, but a later GET returns the original data. No endpoint requires the login token.
Authentication & registration
| Method | Endpoint & query params | Request body | Response example | Status codes |
|---|---|---|---|---|
| POST |
https://klauders.com/automate-the-internet?api=auth/login
Valid user: qa.engineer / Klauders#2026. Username locked.user returns 423; empty fields return 422. |
{
"username": "qa.engineer",
"password": "Klauders#2026"
}
|
{
"token": "eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJxYS5lbmdpbmVlciJ9.4f1c9a2b7d3e8a10",
"expiresIn": 3600,
"user": {
"id": 7,
"username": "qa.engineer",
"name": "QA Engineer",
"role": "QA Engineer"
},
"requestId": "req_3f9a1c2b7d4e"
} |
200OK
401invalid_credentials
422validation_error
423account_locked
|
| POST |
https://klauders.com/automate-the-internet?api=auth/logout
Always returns 200. There is no real session to close. |
No body | {
"message": "Session closed.",
"requestId": "req_3f9a1c2b7d4e"
} |
200OK
|
| POST |
https://klauders.com/automate-the-internet?api=register
Password needs 8+ characters, one uppercase letter and one number. plan: starter | team | enterprise. taken@example.com returns 409; 422 includes an errors object per field. |
{
"fullName": "Ana Garcia",
"email": "ana@example.com",
"password": "Secret123",
"country": "MX",
"plan": "team",
"terms": true
}
|
{
"message": "Account created.",
"userId": 4821,
"email": "ana@example.com",
"plan": "team",
"requestId": "req_3f9a1c2b7d4e"
} |
201Created
409email_taken
422validation_error
|
Users
| Method | Endpoint & query params | Request body | Response example | Status codes |
|---|---|---|---|---|
| GET |
https://klauders.com/automate-the-internet?api=users&page=1&perPage=8
48 users in total. Filters combine with AND. The response includes a meta object for pagination. |
No body | {
"data": [
{
"id": 1,
"name": "Jorge Ramirez",
"email": "jorge.ramirez1@example.com",
"role": "Admin",
"status": "active",
"createdAt": "2025-01-07"
}
],
"meta": {
"page": 1,
"perPage": 8,
"total": 48,
"totalPages": 6,
"sort": "id",
"order": "asc"
},
"requestId": "req_3f9a1c2b7d4e"
} |
200OK
|
| GET |
https://klauders.com/automate-the-internet?api=users&id=2
Returns one user inside data. |
No body | {
"data": {
"id": 2,
"name": "Ana Diaz",
"email": "ana.diaz2@example.com",
"role": "QA Engineer",
"status": "inactive",
"createdAt": "2025-01-13"
},
"requestId": "req_3f9a1c2b7d4e"
} |
200OK
404not_found
|
| PATCH |
https://klauders.com/automate-the-internet?api=users&id=2
status must be active, inactive or pending; any other value returns 422. |
{
"status": "active"
}
|
{
"data": {
"id": 2,
"name": "Ana Diaz",
"email": "ana.diaz2@example.com",
"role": "QA Engineer",
"status": "active",
"createdAt": "2025-01-13"
},
"requestId": "req_3f9a1c2b7d4e"
} |
200OK
404not_found
422validation_error
|
| DELETE |
https://klauders.com/automate-the-internet?api=users&id=2
User 1 is the primary admin and returns 403. |
No body | {
"deleted": true,
"id": 2,
"requestId": "req_3f9a1c2b7d4e"
} |
200OK
403forbidden
404not_found
|
Feed & search
| Method | Endpoint & query params | Request body | Response example | Status codes |
|---|---|---|---|---|
| GET |
https://klauders.com/automate-the-internet?api=feed&page=1
60 items in 6 pages. Page 7 and later return an empty data array with hasMore: false. |
No body | {
"data": [
{
"id": 1,
"author": "Ana Rivera",
"text": "fixed a flaky test",
"minutesAgo": 7
}
],
"meta": {
"page": 1,
"hasMore": true
},
"requestId": "req_3f9a1c2b7d4e"
} |
200OK
|
| GET |
https://klauders.com/automate-the-internet?api=search&q=sel
Returns up to 8 matching tool names. An empty q returns an empty list. |
No body | {
"query": "sel",
"data": [
"Selenium WebDriver",
"Selenium Grid"
],
"requestId": "req_3f9a1c2b7d4e"
} |
200OK
|
Shop
| Method | Endpoint & query params | Request body | Response example | Status codes |
|---|---|---|---|---|
| GET |
https://klauders.com/automate-the-internet?api=products
6 products, KL-001 to KL-006. KL-005 has stock 0. |
No body | {
"data": [
{
"sku": "KL-001",
"name": "Selenium Grid Hours (10h)",
"category": "Infrastructure",
"price": 49.0,
"stock": 25
}
],
"requestId": "req_3f9a1c2b7d4e"
} |
200OK
|
| GET |
https://klauders.com/automate-the-internet?api=coupon&code=QA10
The code is case-insensitive. EXPIRED returns 410; an unknown code returns 404. |
No body | {
"code": "QA10",
"type": "percent",
"value": 10,
"expired": false,
"requestId": "req_3f9a1c2b7d4e"
} |
200OK
404invalid_coupon
410coupon_expired
|
| POST |
https://klauders.com/automate-the-internet?api=orders
An empty items array returns 422 empty_cart. An unknown SKU or qty < 1 returns 400. qty above stock returns 409. |
{
"items": [
{
"sku": "KL-001",
"qty": 2
}
],
"customer": {
"name": "Ana Garcia",
"email": "ana@example.com"
},
"coupon": "QA10",
"paymentMethod": "card"
}
|
{
"orderId": "KL-9F3A1C2B",
"status": "confirmed",
"subtotal": 98.0,
"discount": 9.8,
"total": 88.2,
"paymentMethod": "card",
"requestId": "req_3f9a1c2b7d4e"
} |
201Created
400invalid_item
409insufficient_stock
422empty_cart / validation_error
|
Jobs, files & export
| Method | Endpoint & query params | Request body | Response example | Status codes |
|---|---|---|---|---|
| POST |
https://klauders.com/automate-the-internet?api=jobs
Returns 202 Accepted with the job id to poll. |
No body | {
"id": "job_1759850000000",
"status": "queued",
"progress": 0,
"requestId": "req_3f9a1c2b7d4e"
} |
202Accepted
|
| GET |
https://klauders.com/automate-the-internet?api=jobs&id=job_1759850000000
status moves from queued to running to completed in about 6.6 s; progress goes 0–100. downloadUrl appears only when completed. |
No body | {
"id": "job_1759850000000",
"status": "completed",
"progress": 100,
"downloadUrl": "automate-the-internet.php?api=export&format=csv",
"requestId": "req_3f9a1c2b7d4e"
} |
200OK
404not_found
|
| POST |
https://klauders.com/automate-the-internet?api=upload
Send the file in a multipart field named file. Files over 2 MB return 413. The file is not stored; only its metadata is returned. |
Content-Type: multipart/form-data file: <binary, max 2 MB> |
{
"fileName": "report.pdf",
"size": 48213,
"mimeType": "application/pdf",
"sha1": "2fd4e1c67a2d28fced849ee1bb76e7391b93eb12",
"requestId": "req_3f9a1c2b7d4e"
} |
201Created
400no_file
413file_too_large
|
| GET |
https://klauders.com/automate-the-internet?api=export&format=csv
Returns a file download (CSV or JSON) with a Content-Disposition header instead of the usual JSON envelope. |
No body | Content-Disposition: attachment; filename="users-export.csv" id,name,email,role,status,createdAt 1,"Jorge Ramirez",jorge.ramirez1@example.com,Admin,active,2025-01-07 … |
200OK
|
Errors & timing
| Method | Endpoint & query params | Request body | Response example | Status codes |
|---|---|---|---|---|
| GET |
https://klauders.com/automate-the-internet?api=status&code=404
Accepts any HTTP method. 204 has no body; 429 adds a Retry-After: 30 header. |
No body | {
"status": 404,
"message": "Not Found",
"requestId": "req_3f9a1c2b7d4e"
} |
2xx–5xxrequested code
400unsupported_code
|
| GET |
https://klauders.com/automate-the-internet?api=slow&delay=3
Accepts any HTTP method. Use it to test client timeouts. |
No body | {
"message": "Responded after 3s.",
"delay": 3,
"requestId": "req_3f9a1c2b7d4e"
} |
200OK
|
| GET |
https://klauders.com/automate-the-internet?api=flaky
Accepts any HTTP method. Returns 503 about 40% of the time; use it to test retries. |
No body | {
"message": "Success this time.",
"requestId": "req_3f9a1c2b7d4e"
} |
200OK
503service_unavailable
|
Example with RestAssured (Java)
RestAssured.baseURI = "https://klauders.com/automate-the-internet";
String token =
given()
.contentType(ContentType.JSON)
.queryParam("api", "auth/login")
.body("{\"username\":\"qa.engineer\",\"password\":\"Klauders#2026\"}")
.when()
.post()
.then()
.statusCode(200)
.header("X-Request-Id", startsWith("req_"))
.body("user.username", equalTo("qa.engineer"))
.extract().path("token");
given()
.queryParam("api", "users")
.queryParam("role", "Admin")
.queryParam("perPage", 5)
.when()
.get()
.then()
.statusCode(200)
.body("meta.perPage", equalTo(5))
.body("data.role", everyItem(equalTo("Admin")));
Need a test automation framework that scales?
Klauders designs maintainable UI and API automation with Selenium, Cypress and Playwright, integrated into your CI pipeline.
Talk to our QA team