I had a 530-line component that was never rendered. Not once. Unit tests didn't catch it. Type checks didn't catch it. The build passed clean. A browser agent caught it in 4 seconds because it couldn't find the goddamn gear icon.
530 passing tests on February 6. Every one green. The TemplateManagerSheet was completely invisible to users.
... I should probably explain.
agent-browser is a CLI that gives an AI agent a real Chrome window. Open a page. Take a snapshot of the DOM. Find elements by text. Click things. Fill forms. Screenshot. That's it. It's not Cypress. Not Playwright. Not a test framework. It's an AI that looks at your running app and tries to use it like a human would.
agent-browser open http://localhost:5173/finance/budget
agent-browser snapshot -i
agent-browser find text 'MANAGE_TEMPLATES' click
agent-browser screenshot .claude/verification/budget-template-manager.png
I started using it January 18 to test the Finance Nexus. 20 new components. Responsive layouts across three viewports. I needed to know if the thing actually worked at 375px wide, 768px on a tablet, and 1440px on desktop. Not what I thought it was doing... what it was actually doing.
5 screenshots that session. Desktop, mobile assets, mobile liabilities, tablet assets, tablet liabilities. Each one showed the real rendered output.
But yeah... the real story is what happened on February 6.
I'm implementing category types for the Finance module. Expense vs. allocation. The feature needs the Template Manager to toggle a category's type. Standard stuff. I tell the browser agent to test the workflow. Open the budget page. Find the gear icon. Click it. Toggle a category type.
Round 2 report comes back: "Could not find gear icon on the budget page."
I check the code. TemplateManagerSheet.tsx exists. 530 lines. Fully built. Category sections, inline forms, optimistic updates, entitlement gating. The whole damn thing. Complete UI with zero users because it was never wired into the page.
... I'd built the component January 13 during a 12-commit sprint. Moved on to the next feature. Never came back to mount it. The type system was happy because nothing referenced it incorrectly. The build was happy because dead code compiles fine. I was happy because I don't know... I thought I finished it? EGO alert... apparently "building it" and "shipping it" are two different things. Who knew.
The fix was embarrassing. useState for sheet visibility. A Settings icon button in the budget header. The actual <TemplateManagerSheet> rendered with its required props. Plus a loader update for the data it needed. Maybe 20 minutes of work to wire in something I'd spent hours building.
That February 6 session ran 3 rounds of browser testing against the category type feature.
Round 1 -- migration not pushed. The agent tried to load bill presets. Only the HOME category appeared. All category_type tests blocked. Bug: supabase db push hadn't been run. The agent found the gap between my local database and production. No unit test would've caught that. Round 2 -- Template Manager not wired. Found the 530-line orphan. Preset loading was also broken because Round 1 had partially loaded data. HOME existed from the failed first run, but nothing else came through. Round 3 -- both fixes deployed. Tests 1 through 6 passed. Tests 8, 14, 15 passed. Core feature verified end-to-end.
Three rounds. Each one surfaced a different category of bug. Database state. Component mounting. Data recovery from partial failures. All of them invisible to npm run test.
Regardless... this became the standard workflow. Build the feature. Write the unit tests. Then point the browser agent at it and see what actually happens when a user tries to use the thing.
January 31 -- manual testing across desktop and mobile viewports for launch readiness. 10 screenshots verifying shadow rendering, dialog behavior, responsive layouts. February 1 -- full sovereignty audit E2E testing. 37 screenshots. Anonymous flow, session storage round-trips, trial activation, mobile viewport audit at iPhone SE width. Found that the login redirect dropped users at / instead of /assessment after saving audit results. Not a bug the test suite would surface. The logic was correct. The UX was wrong. February 7 -- template profile system verification. 11 screenshots. Pro user profile switching, free tier limit banners, Domdhi preset backfill, mobile Template Manager at 375px. Found that ensureDomdhiProfile returned early on empty profiles because the migration created the row but never populated categories. The profile existed. It was just hollow.
50+ screenshots across these sessions. Each one a snapshot of what the user actually sees. Not what the test mocks say they see.
I don't know... I feel like I should push back on myself here. Unit tests aren't the problem. The finance calculator has 66 tests covering allocation separation. The sovereignty calculator has 51 tests covering gate boundaries. I trust those numbers. They verify logic. Given these inputs, produce these outputs. Essential.
But unit tests don't open a browser. They don't click buttons. They don't try to find a gear icon that doesn't exist. They test the engine, not the dashboard. And I was speedrunning features fast enough that I literally built an entire component and forgot to mount it. That's the kind of shit that only surfaces when something tries to use the app the way a human would.
"Could not find gear icon" is more useful than any assertion I could've written. It's the experience of every user who would've tried to manage their templates and found nothing.
Either way... the workflow is dead simple. Build the feature. Write your unit tests. Get the build passing. Start your dev server. Tell the agent to open the page and try the user workflow. Read the report. Fix what's broken. Run the agent again.
The viewport testing is where it really compounds. I test at 375px, 768px, and 1440px. Three screenshots per page state. CSS you wrote at 1440px does unexpected things at 375px. You'll see it in the screenshot before your users see it in production.
The agent isn't a replacement for unit tests. It's a replacement for the manual QA you're not doing. The "let me resize the browser and click through every page" session that takes an hour and gets skipped when you're grinding through features at 6x velocity. Especially when your 800-line file size rule means you're shipping small pieces fast and need something to verify they actually compose into a working page.
| Session | Screenshots | Bugs Found |
|---|---|---|
| Jan 18 - Finance Nexus | 5 | Responsive layout issues at tablet width |
| Jan 31 - Launch readiness | 10 | Shadow rendering verified, no fixes needed |
| Feb 1 - Sovereignty Audit | 37 | Login redirect UX, empty profile backfill |
| Feb 6 - Category Types | 3 rounds | 530-line orphan, migration gap, partial data |
| Feb 7 - Template Profiles | 11 | Empty Domdhi profile, mobile Template Manager |
530 unit tests said the code was correct. The browser agent said users couldn't find the button.
Both were right. That's the whole point.