Implant catalog

Complete catalog

Free Playwright practice. Write a catalog test, then run it again.

Ten implant families across five categories. Prices include the surgery window, the pre-op screening, and the implant license. They do not include the clash you will have with your previous installer, which is on you.

The traps we set

These are live on this page. Each one teaches a specific lesson about brittle test patterns. Point Playwright at any of them.

These are live on this page. Each one teaches a specific lesson about brittle test patterns. Point Playwright at any of them.

Tier 1hostile

DOM Selector Rotation

Don't hardcode brittle locators; use semantic, resilient patterns.

Breaks when: CSS class selectors like .add-to-cart-btn fail because the class is generated procedurally and rotates every page load.

Try: Use getByRole, getByLabel, or text-based selectors — they survive class rotation.

1-1-dom-selector-rotation
Tier 1hostile

Data Mutation on Load

Don't assert on dynamic values; verify conditions, not exact states.

Breaks when: Exact-match assertions on stock status or price pass ~70% of the time and fail ~30% — flaky by design.

Try: Accept both valid states (In stock / Out of stock) or check ranges instead of exact values.

1-2-data-mutation
Tier 2hostile

Decoy / Duplicate Elements

Be specific; verify before interacting; don't trust first match.

Breaks when: click() on nth(0) hits a decoy element that looks identical but is non-functional.

Try: Use filter({ hasText: ... }) or getByRole with accessible name to target the real element.

1-3-decoy-duplicate-elements
Tier 2subtle

Structural Drift Between Pages

Don't assume patterns transfer; each page needs fresh recon.

Breaks when: Selectors that work on /catalog fail on /checkout because class names, nesting, or element order changed.

Try: Use semantic locators that don't depend on DOM structure or versioned class names.

1-4-structural-drift
Tier 3subtle

Email Scenarios

Async delivery and expiry timers break tests that assume instant results.

Breaks when: Emails arrive after a delay, links expire after a few seconds, and some messages route to spam. Tests that check immediately or use stale links fail.

Try: Wait for delivery indicators, poll until expected state appears, and regenerate links before each test pass.

1-5-email-scenarios
Tier 2hostile

Subscription Trap

A button's label and behavior change after the first click. Naive tests click and check once.

Breaks when: The button transitions through confirm, processing, and done phases. A test that clicks and asserts the original label fails on the second click.

Try: Use a state machine in your test: assert the label changes through each expected phase instead of assuming it stays the same.

1-6-subscription-trap
Tier 3hostile

File Upload

Upload progress is async and chunked. Tests that expect instant completion miss intermediate states.

Breaks when: The upload emits start, progress (0-100%), processing, and complete events. A test that waits only for 'done' misses timing-sensitive progress assertions.

Try: Use Playwright's waitForEvent or poll for the complete event instead of relying on static timeouts.

1-7-file-upload
Tier 3subtle

Webhook Callback

Async callbacks with retry logic break tests that fire-and-forget.

Breaks when: Webhooks transition pending → delivered/failed/retrying. A test that doesn't wait for the final delivery state passes when the webhook is still pending and flaky when it retries.

Try: Poll the delivery log until status reaches delivered or the retry budget is exhausted.

1-8-webhook-callback
Tier 2environmental

Rate Limit

Rate-limited endpoints reject rapid requests. Tests that hammer the same route without spacing fail intermittently.

Breaks when: After N requests in a sliding window, subsequent requests return 429. A test that fires concurrent requests without coordination hits the limit.

Try: Stagger requests in your test, or use the reset header to wait for the window to clear before continuing.

1-9-rate-limit
Tier 2environmental

Timeout / Slow Load

Async content with variable delay breaks tests that assume fixed timings.

Breaks when: Content appears after a configurable delay (or random delay). A test with a hardcoded wait may timeout before content loads, or pass on the first run and fail on CI.

Try: Use Playwright's waitForSelector with a generous timeout instead of fixed sleep(). Enable auto-waiting assertions.

1-10-timeout
Tier 3hostile

State Desync

Client state may diverge from server truth. Checking only the rendered DOM misses the real data.

Breaks when: Items show a stale price, wrong stock badge, or outdated count on the client while the server holds correct data. A test that checks only the displayed value catches the desync intermittently.

Try: Cross-reference visible values against hidden data-testid attributes that carry the server ground truth.

1-11-state-desync
Tier 2environmental

Permission Error

Role-based access gates break tests that assume all users are admins.

Breaks when: A test using admin-panel actions gets a permission denied response when the current role is viewer or operator.

Try: Set the role explicitly before testing restricted actions, or test across all roles to confirm the access control works.

1-12-permission-error
Tier 2hostile

Modal Overlay

Modals that appear after a delay or can't be dismissed break naive interaction tests.

Breaks when: A modal appears after N ms. A test that clicks the trigger and immediately looks for modal content finds nothing because the overlay hasn't rendered yet.

Try: Wait for the modal to be visible (waitForSelector or locator.waitFor) before interacting with its contents.

1-13-modal-overlay
Tier 2hostile

Focus Trap

Trapped focus loops inside a dialog. Tests that tab-out or expect focus to leave the dialog fail.

Breaks when: Tabbing past the last focusable element inside a dialog wraps back to the first. A test that presses Tab and expects focus on a page-level element never escapes.

Try: Test that focus cycles correctly inside the trap. Use locator.press('Tab') and assert the active element stays within the dialog.

1-14-focus-trap
Tier 3subtle

Scroll Stealth

Lazy-loaded content below the fold doesn't exist until the user scrolls.

Breaks when: Sections below the viewport are empty divs. A test that scrolls down and immediately checks for content sees nothing because the reveal is tied to scroll position.

Try: Scroll the element into view then wait for its content to render. Use scrollIntoViewIfNeeded or Playwright's locator.scrollIntoViewIfNeeded.

1-15-scroll-stealth
Tier 2subtle

Tab Visibility

Background tab behavior differs from foreground. Tests that assume the tab stays visible miss hidden-tab branches.

Breaks when: When the tab is hidden, polling pauses or throttles. A test that switches tabs (or the system does) and expects continuous updates sees stale data.

Try: Override document.hidden via page.addInitScript for tests that need to simulate background behavior, or test explicitly in both visibility states.

1-16-tab-visibility
Tier 3environmental

Network Jitter

Variable network latency causes test race conditions that are hard to reproduce.

Breaks when: A request-response cycle takes between minDelayMs and maxDelayMs. A test with a fixed timeout succeeds on fast networks and fails on slower CI runners.

Try: Use Playwright's page.route to simulate or record latency, or rely on auto-waiting assertions that give the full timeout budget.

1-17-network-jitter
Tier 3environmental

Clock Skew

Client and server time differences break tests that compare timestamps locally.

Breaks when: Client time is offset from server time by a configurable amount. A test that compares new Date() against a server-returned timestamp sees a mismatch.

Try: Use the server's reported time as the source of truth. Avoid Date.now() in assertions that cross the client-server boundary.

1-18-clock-skew
Tier 4subtle

Memory Leak

Accumulated DOM nodes degrade performance and eventually crash the page under test.

Breaks when: A growing list of LeakItem elements is appended every tick. A test that navigates away and back sees accumulated nodes from the previous visit.

Try: Clear or reset the list between test cases. Use page.evaluate to measure DOM node count before and after each scenario.

1-19-memory-leak

Every page load re-rolls bait IDs on each card. Hardcoding an id in your test guarantees a flaky failure. Use semantic locators.

Ripper Gym. Hostile Playwright practice. The shop is Chrome Clinic.