feat(portal): M10.2 — MSW handlers + ToastHost + InviteButton end-to-end
ci / test (pull_request) Failing after 4m54s
ci / shared (pull_request) Successful in 11s
ci / e2e (pull_request) Has been skipped
ci / image (pull_request) Has been skipped

Closes out the design pass with the missing piece: a real client-side
mock-API pipeline so the write-path CTAs the design shows (invite a
teammate, run a scan, kick off a workflow test, request reactivation)
actually do something visible without a backend.

* `public/mockServiceWorker.js` — generated by `pnpm exec msw init`.
* `src/mocks/handlers.ts` — POST handlers for `/api/team/invites`,
  `/api/scans`, `/api/workflows/:id/test`, `/api/billing/reactivate`.
  Each returns the design's mono status-code header
  (`201 · invite.created`, `202 · scan.queued`, etc.) so the toast
  surface reads identical to the handoff. A `x-bp-tenant-status` hint
  header lets the same handler respond 402 (frozen) or 410 (archived)
  without needing a real session.
* `src/mocks/browser.ts` — thin `setupWorker(...handlers)` wrapper,
  imported lazily so prod bundles don't pull MSW.
* `src/components/portal/MockWorker.tsx` — client component that boots
  the worker only when `window.__BP_MOCK_API__` is true (set by
  `[slug]/layout` when `BP_DEV_FIXTURE` is on the server). Real Auth.js
  builds skip the worker entirely.
* `src/components/portal/ToastHost.tsx` — global bottom-right toast
  queue, mounted in `[slug]/layout`. Emits via a custom event so any
  client component can call `toast({ msg, code })` without prop-drilling.
* `src/components/portal/InviteButton.tsx` — first live write affordance.
  Modal with email + role-segmented buttons, POSTs to `/api/team/invites`
  with the tenant-status hint header, surfaces 201/402/410 differently.
  Wired into the Team page.
* `src/middleware.ts` — added `mockServiceWorker.js` to the matcher
  exclusion list so the host-rewrite doesn't 404 the worker script.

Verified end-to-end via Playwright: SW registers at the root scope,
click Invite member → fill email → Send invitation → MSW intercepts →
toast "Invitation sent · 201 · invite.created" → modal closes.

This closes the last open M10.2 task. Branch is ready to review/merge.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Sharang Parnerkar
2026-06-04 16:11:18 +02:00
parent 26f41a8122
commit 0797f8f99c
10 changed files with 752 additions and 4 deletions
+6 -1
View File
@@ -43,5 +43,10 @@
"tailwindcss": "^4.3.0",
"typescript": "5.7.2",
"vitest": "2.1.8"
},
"msw": {
"workerDirectory": [
"public"
]
}
}
}