A small, realistic web app built to be tested end to end. Each case is a feature that is hard to test well, with a list of requirements. Write automated tests that check every requirement. Each case hides a detail that makes the obvious test miss a broken requirement.
Bring your own framework: Playwright, Cypress, WebdriverIO, or anything that drives a browser.
Live demo: https://e2e-proving-ground.onrender.com (free tier: if it has been idle, it takes about a minute to wake, and it starts empty after every wake).
Worked solutions: solutions/ has Playwright approaches to 12 cases,
each scored against bugs planted in the app, plus a benchmark of
AI agents writing tests for the same cases. The other cases stay unsolved.
200+ cases is a lot. These twelve show the range:
| Case | Why it is hard to test |
|---|---|
| 1. Two-user realtime chat | Two browsers, a dropped socket, and messages that must arrive once and in order. |
| 3. Optimistic moves | The screen changes before the server answers, and has to change back when it says no. |
| 6. Due dates, time zones, and DST | The bug only shows in some zones, on some dates. |
| 24. Draft | Autosave with retries, and a race you have to make happen. |
| 38. Search | Answers that arrive out of order. |
| 72. Upload | Progress, cancel, and a server that must keep nothing from a broken upload. |
| 95. Local notes | An IndexedDB upgrade while another tab holds the old version open. |
| 104. Concert tickets | A page restored from the back/forward cache, which fires no load. |
| 111. Bus stop | A service worker that has to work offline. |
| 166. Kitchen timer | One alarm, however many tabs are open. |
| 172. Help desk | A strict Content Security Policy that nothing may break. |
| 194. Meeting rooms | Three requests in a row, where each can fail on its own. |
| # | Case | What it is |
|---|---|---|
| 1 | Two-user realtime chat | Open a sandbox, join with a name, and send messages. |
| 2 | Concurrent edit | Two people open the same card on the board and both edit it. |
| 3 | Optimistic moves | Cards move between columns at once, before the server answers. |
| 4 | Export job | Export board as CSV starts a background job with progress. |
| 5 | Feature flag | New cards are created with one of two variants: an inline form or a dialog. |
| 6 | Due dates, time zones, and DST | Cards can have a due date. |
| 7 | A shared environment | Card titles are unique within a sandbox, and the board shows how many cards it has. |
| 8 | Magic-link sign-in | The Account page signs you in with a link sent by email. |
| 9 | A virtualized list | The Activity page lists 10,000 entries, rendering only the rows in view and loading them in pages. |
| 10 | A toast and a page that is never idle | Saving Settings shows "Settings saved" for 2 seconds. |
| 11 | Checkout total | The Shop page sells three products. |
| 12 | Shipping insurance | Checkout offers shipping insurance for 4.99 PLN, with no VAT on it. |
| 13 | Product reviews | Each product has a reviews page, linked from the Shop. |
| 14 | Editing a review | The browser that posted a review can edit it. |
| 15 | Splitting an order | Under your orders, "Split order" opens a page that divides the order total between 2 and 8 people. |
| 16 | The People picker | The split page chooses the number of people with a list built from ARIA roles, not a native select. |
| 17 | Cookie consent | The Deals page asks for cookie consent before it shows deals picked for you. |
| 18 | Gift cards | The Gift cards page sells gift cards. |
| 19 | Notes | The Notes page lists notes you can star, archive, or delete. |
| 20 | Budget | The Budget page keeps a list of expenses and charts them. |
| 21 | Your plan | The Plan page shows your Pro plan, 49.00 PLN a month, with the next payment on 1 December 2026. |
| 22 | Playlist | The Playlist page lists five songs in an order you can change. |
| 23 | Top up | The Top up page adds money to a wallet. |
| 24 | Draft | The Draft page holds one letter that saves itself. |
| 25 | Calendar | The Calendar page connects a calendar from Example Calendar, a separate sign-in service. |
| 26 | Contacts | The Contacts page imports contacts from a CSV file. |
| 27 | Stores | The Stores page finds the three stores nearest to you. |
| 28 | Quote | The Quote page multiplies a unit price by a quantity. |
| 29 | Booking | The Booking page books a room in three steps: Dates, Guests, and Review. |
| 30 | Feed | The Feed page lists posts, newest first. |
| 31 | Checklist | The Checklist page keeps a list of items and keeps working when the connection drops. |
| 32 | Vault | The Vault page keeps notes behind two-step verification with an authenticator app. |
| 33 | Basket | The Basket page keeps a basket in the browser, without the server. |
| 34 | Support | The Support page sends a message to support. |
| 35 | Receipt | The Receipt page shows a shop receipt with an order number and the time it was printed (24-hour clock). |
| 36 | Sign up | The Sign up page creates an account (nothing is stored). |
| 37 | Bio | The Bio page has a small rich-text editor with Bold and Italic buttons (Ctrl+B and Ctrl+I work too) and Save. |
| 38 | Search | The Search page finds products as you type. |
| 39 | Invoices | The Invoices page lists two invoices with a Download PDF link each. |
| 40 | Price filter | The Price filter page shows products between a lowest and a highest price, chosen with a slider that has two handles. |
| 41 | Reminders | The Reminders page reminds you about something in 1, 5, 15 or 60 minutes. |
| 42 | Address | The Address page edits your street, city and postcode. |
| 43 | Feedback | The Feedback page sends a star rating and an optional comment. |
| 44 | Share | The Share page shows an invite link with Copy link and New link buttons. |
| 45 | Updates | The Updates page tells you when a new version of the app has been released while the page was open. |
| 46 | Inbox | The Inbox page lists eight messages with a checkbox each. |
| 47 | Orders | The Orders page shows orders ten at a time, sorted on the server. |
| 48 | Files | The Files page lists five files. |
| 49 | Tasks | The Tasks page is a small to-do list with keyboard shortcuts. |
| 50 | Itinerary | The Itinerary page shows a three-day trip with a Print itinerary button. |
| 51 | Verify phone | The Verify phone page texts a code (nothing is really sent). |
| 52 | Order summary | The Order summary page can be shown in English or Arabic. |
| 53 | Shipping address | The Shipping address page saves a country and a postcode, and a state for the United States. |
| 54 | Gallery | The Gallery page shows 24 photos in two columns. |
| 55 | Holiday request | The Holiday request page picks a first and a last day, on a calendar or in the From and To fields. |
| 56 | Stay signed in | The Stay signed in page signs in [email protected] with the password correct horse. |
| 57 | Podcast | The Podcast page plays a 30-second episode (a quiet tone) with its own controls. |
| 58 | Bakery | The Bakery page has a site header with four links. |
| 59 | Session | The Session page signs you out after 90 seconds without activity. |
| 60 | Team | The Team page shows a Roadmap document and its members. |
| 61 | Meetings | The Meetings page adds a meeting at a date and time, once or every week for 4 weeks. |
| 62 | Directory | The Directory page lists 10,000 customers. |
| 63 | Confirm email | The Confirm email page asks for a 6-digit code, one box per digit. |
| 64 | Messages | The Messages page counts new messages in English or Polish. |
| 65 | Passkeys | The Passkeys page creates passkeys for ann and signs in with them. |
| 66 | Delivery | The Delivery page asks you to sign for a parcel. |
| 67 | Import | The Import page imports 100 customers and shows the progress as it happens. |
| 68 | Packing list | The Packing list page edits a list of things to pack. |
| 69 | Help centre | The Help centre opens articles without reloading the page. |
| 70 | Order review | The Order review page lists 12 items under a header that stays at the top, with a pay bar that stays at the bottom. |
| 71 | Sales report | The Sales report page adds up 20,000,000 sales by region. |
| 72 | Upload | The Upload page sends a file of up to 20 MB to the server. |
| 73 | Support ticket | The Support ticket page takes a description and pasted screenshots. |
| 74 | Timesheet | The Timesheet page is a grid of hours per day and project. |
| 75 | Shop reviews | The Shop reviews page shows a reviews widget in a sandboxed frame. |
| 76 | Country | The Country page is a list of 30 countries you can pick from with the keyboard. |
| 77 | Appearance | The Appearance page lets you pick a theme and how much motion you see. |
| 78 | Statement | The Statement page lists a month of transactions and downloads them as a CSV file. |
| 79 | Plans | The Plans page compares three plans, each with an info button that shows a tooltip. |
| 80 | Price alerts | The Price alerts page sends a browser notification when a product gets cheaper. |
| 81 | Live score | The Live score page follows a match and stops asking the server while the tab is hidden. |
| 82 | Mobile inbox | The Mobile inbox page deletes a message when you swipe it to the left, with an undo. |
| 83 | Change password | The Change password page changes the account password and works with password managers. |
| 84 | Flash sale | The Flash sale page counts down to the end of a sale by the shop's clock. |
| 85 | Class list | The Class list page sorts and searches 15 pupils with Polish names. |
| 86 | Newsletter | The Newsletter page marks an article as read once it has been on screen for 2 seconds. |
| 87 | Post editor | The Post editor page writes and publishes a blog post in a panel that scrolls. |
| 88 | Announcements | The Announcements page shows three banners you can dismiss. |
| 89 | Voice note | The Voice note page records a voice note with the microphone and saves it. |
| 90 | Price list | The Price list page checks for new prices and downloads the list only when it changed. |
| 91 | Contributors | The Contributors page shows names on small cards, cutting the ones that do not fit. |
| 92 | Product details | The Product details page shows four tabs of details about a hand grinder. |
| 93 | Files tree | The Files tree page shows folders and files in a tree you can open and close. |
| 94 | Promotions | The Promotions page shows a carousel of four offers that changes every 5 seconds. |
| 95 | Local notes | The Local notes page keeps notes in the browser's database and updates it safely across tabs. |
| 96 | Letter | The Letter page is a text box with its own Undo and Redo that work a word at a time. |
| 97 | Recipe | The Recipe page shares a recipe with the device's share sheet, or copies its link. |
| 98 | Photos | The Photos page shows five photos in a viewer that can go full screen. |
| 99 | Delivery details | The Delivery details page is a form that reflows on narrow screens and with large text. |
| 100 | Hotels | The Hotels page filters a hotel list in a sheet that covers the whole window. |
| 101 | Lamps | The Lamps page shows product cards with Save and Compare buttons for mouse, keyboard and touch. |
| 102 | Mailing list | The Mailing list page embeds a sign-up form that a separate script wires up after the page loads. |
| 103 | Trip tags | The Trip tags page turns typed text into tags, also when the text comes from an input method. |
| 104 | Concert tickets | The Concert tickets page sells tickets and must be up to date when the user returns with Back. |
| 105 | Privacy settings | The Privacy settings page has a pop-up hint for each option and a confirmation after saving. |
| 106 | Train ticket | The Train ticket page sells a ticket with optional extras over three steps. |
| 107 | Pancakes | The Pancakes page scales a recipe by servings and works out how many servings your flour makes. |
| 108 | Photo album | The Photo album page uploads a whole folder of photos, keeping its subfolders. |
| 109 | Floor plan | The Floor plan page zooms a plan with a pinch, Ctrl and the mouse wheel, or buttons. |
| 110 | Reading list | The Reading list page keeps the user signed in with a session stored in IndexedDB. |
| 111 | Bus stop | The Bus stop page links to a departures board that keeps working offline. |
| 112 | Workspace | The Workspace page opens on Setup or on the Dashboard, depending on the workspace's settings. |
| 113 | Saved searches | The Saved searches page lists saved searches and shows an empty state when there are none. |
| 114 | Groceries | The Groceries page adds products to a basket and announces each change to screen readers. |
| 115 | Event feedback | The Event feedback page has a form whose star rating is a custom element. |
| 116 | Shop dashboard | The Shop dashboard page has an orders widget that switches layout with its own width. |
| 117 | Highlights | The Highlights page lets the reader save selected text from an article. |
| 118 | Sell your bike | The Sell your bike page explains, to every user, why Publish is not available yet. |
| 119 | Expense claims | The Expense claims page submits claims after you sign in, and lets you sign in again without losing a claim when the session ends. |
| 120 | Flats | The Flats page lists flats to rent as cards that open the flat, with Save and Compare on each card. |
| 121 | Parking permit | The Parking permit page takes payment through card fields in an embedded frame. |
| 122 | Shared drive | The Shared drive page lists files with a custom right-click menu: Open, Duplicate and Delete. |
| 123 | Village hall | The Village hall page lists questions whose answers open and close, and can still be found while closed. |
| 124 | Assistant | The Assistant page has three conversations; answers arrive word by word, also while you read another conversation. |
| 125 | Comments | The Comments page has a comment box that grows with its text, up to six lines. |
| 126 | Alert settings | The Alert settings page has three on/off switches and a choice of summary email. |
| 127 | Choir sign-up | The Choir sign-up page shows its form step by step on narrow screens and all at once on wide ones. |
| 128 | Shared photos | The Shared photos page opens a photo on a tap and starts selecting photos when one is pressed and held. |
| 129 | Mail reader | The Mail reader page shows a message list and a message side by side, divided by a bar you can drag. |
| 130 | Receipts | The Receipts page attaches receipt files dragged from the computer onto it, or chosen with a button. |
| 131 | Guestbook | The Guestbook is a plain HTML page with a form, served by the server and usable without JavaScript. |
| 132 | Concert poster | The Concert poster page sizes the poster's headline so it fits on one line at any width. |
| 133 | Field notes | The Field notes page keeps notes in the browser's storage as you type. |
| 134 | Club activity | The Club activity page lists what happened in the club, with times such as "3 minutes ago". |
| 135 | Notice board | The Notice board page lists office notices and counts the ones you have not read yet. |
| 136 | Prints | The Prints page connects your CloudPix photo account through a pop-up window. |
| 137 | Study group | The Study group page is a group chat that shows who is typing. |
| 138 | Billing details | The Billing details page saves who invoices are made out to: a private person or a company. |
| 139 | Flight search | The Flight search page finds flights, and copes when the search is slow. |
| 140 | Bank transfer | The Bank transfer page sends money to an account number that is formatted as you type. |
| 141 | Library card | The Library card page takes a date of birth typed by hand and works out your age. |
| 142 | Village fête | The Village fête page links to a reply form that the server builds and a script improves. |
| 143 | Rooms | The Rooms page shows a guest house's three rooms with photos sized for each screen. |
| 144 | Radio favourites | The Radio favourites page lets you like songs, and keeps the saved likes in step with the screen. |
| 145 | Shift handover | The Shift handover page sends a note for the next shift, where @ mentions people. |
| 146 | Ticket contact | The Ticket contact page asks where to send tickets, and works with the browser's autofill. |
| 147 | Handbook | The Handbook page has a menu of sections that open and close, usable with a keyboard and a screen reader. |
| 148 | Barber | The Barber page books a haircut and holds the chosen time for 5 minutes. |
| 149 | Running order | The Running order page lists 30 acts of a village show, in an order you change by dragging. |
| 150 | Site photos | The Site photos page lists folders and photos in a table you sort by name, size or date. |
| 151 | Staff | The Staff page opens an edit dialog that loads a person's details while you move around it. |
| 152 | Support answers | The Support answers page filters help articles as you type and highlights the matches. |
| 153 | Tile order | The Tile order page builds an order that belongs to one browser tab and survives a reload. |
| 154 | Shoe size | The Shoe size page picks a size from a custom list that opens over its button. |
| 155 | Saved cards | The Saved cards page asks before removing a card, in a question that fades out. |
| 156 | Stock take | The Stock take page is a grid of counts you can fill by pasting cells from a spreadsheet. |
| 157 | Cookbook | The Cookbook page opens dialogs over a long list that must stay put behind them. |
| 158 | Trail map | The Trail map page opens from a service worker's saved copy and must update to a new version cleanly. |
| 159 | Phrasebook | The Phrasebook page adds phrases with Enter, including ones typed with an input method (IME). |
| 160 | Replies | The Replies page keeps an unsent reply per conversation in the browser, up to the last letter typed. |
| 161 | Payslips | On the Payslips site, the browser's Back and Forward buttons must never show payslips to someone who signed out. |
| 162 | Newsroom | The Newsroom page pages through stories with Load more, without repeats or gaps, and keeps your place when you come back from a story. |
| 163 | Members | The Members area sends you to the page you asked for after signing in, but never off the site. |
| 164 | Prime counter | The Prime counter page runs a count of several seconds that must not freeze the page, and can be cancelled or replaced. |
| 165 | Pay by bank | The Pay by bank page sends you to a bank on another site, which sends you back with the result. |
| 166 | Kitchen timer | The Kitchen timer is shared by all open tabs of the page and must ring exactly once when it ends. |
| 167 | Transcript | The Transcript page has a link for every line, and each link must land on its line, under the page's sticky header. |
| 168 | Team chat | The Team chat keeps you at the newest message as messages and photos arrive, unless you scrolled up to read. |
| 169 | Cinema | The Cinema page reserves seats, and its buttons must work from the moment they appear, on any connection. |
| 170 | Parts search | A search box that waits as long as the server asks after 429 Too Many Requests. |
| 171 | Staff guide | A contents bar that marks the section you are reading and jumps to a section on click. |
| 172 | Help desk | A page under a strict Content-Security-Policy with a chat whose code loads on the first click. |
| 173 | Video upload | An upload in 1 MB parts that carries on where the server stopped, after a lost connection or a reload. |
| 174 | Chat history | A conversation that loads older messages above when you scroll up, without moving what you read. |
| 175 | Close account | A page that closes the account, shown in this app's own preview frame but never in another site's. |
| 176 | Shipments | Parcels with long tracking numbers that must stay exact from the server to the screen and back. |
| 177 | Metronome | A metronome with page-wide keys that keeps working the same however often you leave and come back. |
| 178 | Loyalty points | Points read and spent through a partner API on another origin, straight from the browser. |
| 179 | Café dashboard | Three tiles that fail one at a time: a broken tile says so, reports it, and leaves the others working. |
| 180 | Printer status | A status that checks less and less often while the printer cannot be reached, and normally again once it can. |
| 181 | Holiday homes | Cards that load a home's details as soon as the pointer or keyboard reaches them, counting a view only when it is opened. |
| 182 | Profile photo | A photo turned and cut to a 256 × 256 square in the browser, then sent as a PNG. |
| 183 | Travel article | An article whose photos and newsletter box arrive after the text, without moving it. |
| 184 | Paper boat | A 12-second video with captions in English or Polish and a transcript that follows it. |
| 185 | Quick invoice | An invoice form with many buttons, where Enter saves and no other button ever does. |
| 186 | Library catalogue | A search kept in the page's address, so it survives a reload, a shared link and Back, whatever the text. |
| 187 | Team overview | Three panels loaded at once with a short-lived token that is renewed once, quietly, when it runs out. |
| 188 | Region packs | Map downloads with a progress bar that follows the bytes as they arrive, and a Cancel button. |
| 189 | Gym membership | Renewal dates for a membership that starts late in the month, in any time zone. |
| 190 | Courier pickup | A two-column booking form where the keyboard has to move in the order a person reads. |
| 191 | Recipe box | A list and an editor side by side, with answers kept in a cache that has to forget the right things. |
| 192 | Travel wallet | Balances in złoty, yen and Bahraini dinar, which have 2, 0 and 3 decimal places. |
| 193 | Weather | A weather widget that asks the server once per change and once every ten minutes, and no more. |
| 194 | Meeting rooms | Booking a room in three steps (book, send the invite, refresh the list) where a later step can fail on its own. |
| 195 | Shopping list | A list where a new item can be ticked or removed before the server has given it an id. |
| 196 | Class timetable | A month grid whose first weekday and weekend follow the visitor's language and region. |
| 197 | Guest invites | A box for many email addresses at once, where real but unusual addresses must get through. |
| 198 | Shared files | A list of shared file names, some of which use direction marks to hide what they are. |
| 199 | Exhibition | Paintings that open in a dialog with its own address, where Back closes the dialog instead of leaving. |
| 200 | Appointment reminders | An SMS reminder box that counts characters and messages the way phone networks do. |
| 201 | Parcel lockers | Choosing a parcel locker from a list sorted by distance, where full lockers cannot be chosen. |
| 202 | Ferry tickets | Ferry fares for adults and children with a family discount and a passenger limit. |
docker compose up --buildOpen http://localhost:3000 to browse the cases by topic, then start a sandbox. A sandbox is a private copy of the app; open its URL in a second window to be the second user.
Test hooks reset, seed and break a sandbox from a test. API lists the endpoints the pages use.
Node 24 or newer runs TypeScript directly; CI uses the newest Node release. Fastify serves the API, the WebSocket, and the React build from one process; data lives in an in-memory SQLite database, so a restart is a full reset. The client is React 19 with Vite and TanStack Query.
npm ci
npm run dev:server # API on :3000 with test hooks
npm run dev:web # Vite on :5173, proxies /api and /__test__
npm run typecheck
npm run test:unit
npm run build && npm run test:smoke # opens every page in Chromium; axe scan of the shellMIT. Made by bartech-lab.
