ByeBuy.ai
BUILD YOUR ESCAPE ROUTE · ✦ CURSOR · HOST IT · ◫ SUPABASE · CONNECT IT · ↯ RELAY · BUILD YOUR ESCAPE ROUTE · ✦ CURSOR · HOST IT · ◫ SUPABASE · CONNECT IT · ↯ RELAY ·
CURRICULUM
← BYEBUY NOTES

September 12, 2026

INTEGRATION AND BROWSER TESTS: CHECK THE SEAMS USERS ACTUALLY CROSS

Integration and Browser Tests: Check the Seams Users Actually Cross

Focused tests from Lesson 50.2 tell you a rule is correct in isolation. But users never experience a rule in isolation. They cross seams: browser to route, route to authorization, authorization to database policy. That is where the expensive failures live, and only seam-crossing tests can catch them.

The seam principle

Each piece of Research Desk can be reasonable on its own while the combination is broken:

  • The frontend hides the Edit button for non-owners. Reasonable.
  • The policy function denies non-owners in a unit test. Correct.
  • The API route loads the record by ID but forgets to call the policy function. Broken — and neither of the first two checks notices.

That is the seam principle: most expensive failures occur where individually reasonable pieces meet. A frontend check plus a database check does not prove the ownership rule survives the API route between them. You have to exercise the route, the authorization logic, and the database policy together.

Two test types do that:

  • An integration test verifies components and services work together across a meaningful boundary — route plus authorization plus database policy — using a safe test database. No real browser, but real wiring.
  • An end-to-end (browser) test drives a real browser through a user journey: sign in, search, save, see the saved state, sign out, confirm access is gone. It proves the whole path a person walks. The current standard tooling for this is described in the Playwright documentation.

What each one looks like

An integration test for "save to watchlist" might read:

Given a test database with users A and B and an empty watchlist,
when User A POSTs { ticker: "AAPL" } with User A's session,
then the response is success and the row is owned by User A;
when User B GETs User A's item ID with User B's session,
then the response is denied (403/404 by design) and the row is unchanged.

Note the two identities. A test with one user proves the happy path; a test with two users proves the boundary. Lesson 50.4's horror story — the mocked authorization that always returned true — passes every single-identity test and fails the moment a second identity appears.

A browser journey for the same slice is longer and closer to a person:

Setup: test account + seeded brief for AAPL + clean watchlist.
1. Sign in as the test user.
2. Search "AAPL" → brief with linked sources appears.
3. Click Save → "Saved" confirmation appears.
4. Reload the watchlist page → AAPL is still there (persisted, not just optimistic UI).
5. Sign out → visiting the watchlist URL shows a sign-in prompt, and the save API without a session is denied.
Assert at every step; screenshot the confirmation and the denied state.

Step 4 is the one AI demos skip: persistence across reload proves the write actually happened. Step 5 proves the denial real users depend on.

Environment discipline: never punch production

Browser and integration tests touch real wiring, so they need real discipline:

  • Never point destructive tests at production. A cleanup step that deletes "test data" will one day match real data. Run seam tests against a test or preview environment with its own database.
  • Use recognizable test accounts and data. test-owner@example.com, tickers like TEST-AAPL, seeded watchlists clearly labeled. Anyone reading a row should know it is a prop, not a customer.
  • Explicit environment variables. The test setup names its target (TEST_DATABASE_URL, preview URL) out loud. If the variable is missing, the test refuses to run rather than guessing.
  • Cleanup and seeds. Each run seeds what it needs and removes what it created — or runs in a transaction that rolls back. A test that passes only when run in a lucky order is a future all-nighter.
  • Data handling. Seeded fixtures stay modest and synthetic. No copying real user rows into a test database to make setup easier.

This is also where Part XI's authorization lessons pay off: your test database should enforce the same row-level policies as production. Testing against a wide-open test database proves nothing about the policies that protect real users.

Screenshots complement — they do not replace

Every browser test can capture screenshots, and it should. But know what each artifact proves:

  • Automated browser assertions prove navigation, state changes, and denials repeatably: the saved row appears after reload, the signed-out request is denied. Machines check these.
  • Screenshots let a human judge visual quality, layout, confusing copy, and broken states on desktop and mobile. Humans check these.
  • Neither proves every production condition: live provider quotas, real email delivery, production permission configuration, performance under load. Say so in the plan.

So attach the screenshot to the test report — the saved confirmation, the denied state — and still require the assertion. An image nobody asserts on is a souvenir; an assertion nobody looks at is a rumor. You want both.

Exercise: one critical journey, one unauthorized journey

On a live task card for the watchlist slice, define two cases:

Journey 1 — critical path. Sign in → search → save → reload-persist → sign out → denied. State the setup (test account, seeded brief), each action, each assertion, the test data, and the cleanup.

Journey 2 — unauthorized. User A saves AAPL; User B, signed in, requests User A's item directly by ID (URL or API call, not the hidden button). Assert denial and an unchanged record. This is the test that would have caught the one-line permission disaster.

For each, add one line: "needs manual verification of ___" (visual polish, error copy tone, mobile layout, keyboard flow). Automation proves the rule held; a person confirms it felt right.

Finish line: two browser/integration test cases tied to the task card and its risk level, each with setup, actions, assertions, test data, cleanup, and a named manual check.

Verify fast: run Journey 2 against a route with the ownership check deliberately removed. It must fail loudly. Common failure: it passes — usually because the test used the same identity twice, hit the wrong environment, or asserted on the button's visibility instead of the server's denial.

Check your understanding

1. State the seam principle in one sentence. 2. What is the difference between an integration test and a browser (end-to-end) test? 3. Why must the unauthorized journey use two identities and assert on the server response, not the hidden button? 4. Name two environment-discipline rules and what goes wrong without each.

Next

You know what to prove and at which layer. The remaining question is leverage: AI can write all of this — the plan, the tests, the fixtures — very fast. Lesson 50.4 shows how to use that speed without letting the same AI grade its own homework.

ARTICLE DISCUSSION

JOIN THE
CONVERSATION.

0 COMMENTS

BYEBUY ACCOUNT ACCESS

Sign in

Use your account to save routes and make the catalogue yours.

Enter your email and we’ll send a secure sign-in link and code.

NEW ROUTES ADDED WEEKLY · 9,235 CATALOGUE ENTRIES · BUILD · DEPLOY · QUERY · STACK · SAY BYE TO BUY · NEW ROUTES ADDED WEEKLY · 9,235 CATALOGUE ENTRIES · BUILD · DEPLOY · QUERY · STACK · SAY BYE TO BUY ·