test(ui): add UserButton connected integration test - #9191
test(ui): add UserButton connected integration test#9191alexcarpenter wants to merge 19 commits into
Conversation
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
🦋 Changeset detectedLatest commit: 178fb88 The changes in this PR will be included in the next version bump. This PR includes changesets to release 0 packagesWhen changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
|
Important Review skippedAuto reviews are disabled on base/target branches other than the default branch. Please check the settings in the CodeRabbit UI or the ⚙️ Run configurationConfiguration used: Repository YAML (base), Repository UI (inherited) Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
Comment |
ApprovabilityVerdict: Approved This PR adds integration tests for the AccountButton component with no production code changes. The empty changeset confirms no packages are affected, making this a low-risk test-only addition. You can customize Macroscope's approvability policy. Learn more. |
Dismissing prior approval to re-evaluate 088fc5a
22e6748 to
4f890d8
Compare
9a8dfc6 to
b192bfc
Compare
b192bfc to
cb6a6fd
Compare
@clerk/astro
@clerk/backend
@clerk/chrome-extension
@clerk/clerk-js
@clerk/electron
@clerk/electron-passkeys
@clerk/eslint-plugin
@clerk/expo
@clerk/expo-google-signin
@clerk/expo-passkeys
@clerk/express
@clerk/fastify
@clerk/hono
@clerk/localizations
@clerk/nextjs
@clerk/nuxt
@clerk/react
@clerk/react-router
@clerk/shared
@clerk/tanstack-react-start
@clerk/testing
@clerk/ui
@clerk/upgrade
@clerk/vue
commit: |
API Changes Report
Summary
No API Changes DetectedAll packages have stable APIs with no detected changes. Report generated by Break Check Last ran on |
Render the connected UserButton against stubbed Clerk hooks and drive it through the popover: organization selection, account switching, sign out, accepting invitations and suggestions, single-session mode, navigation actions, busy and loading states, and the paging sentinel.
Every other action — switching account, signing out of one, joining a suggested or invited workspace — now resolves back into an open popover so the result is visible where it happened. The swingset prototypes fake the round trip they make against Clerk, so the spinner and stood-down rows are demonstrable without a running app.
The sizes track the Icon scale (sm 14px, md 16px) so a spinner can stand in for the icon it replaces, and the UserButton's trailing column is now one slot the width of the menu button, so the spinner, the active check, and the menu all sit on the same centre line.
The trigger carried the avatar alone. It now names what is active beside it — the organization and its plan wherever one heads the trigger, the account otherwise — behind `showLabel`, which defaults on. Badge's `neutral` color was unreadable in both schemes: its fill is a 900 and its text token is a text color, not an on-fill one. It now rides the same black/white scrim the button's neutral fill does.
…ccount The trigger and the popup's header now always name the same workspace. `combined` carries both switchers, so `modePriority` picks which one it leads with: the active organization by default, the account with `modePriority="user"`. Both are still listed either way.
…ser fixture The controller now reads hasOrganizations off the user resource, so the mocked user needs the field the real one has.
`setActive` swaps the active organization while its promise is still in flight, so the popup rearranged mid-action: the header renamed itself, the check jumped rows, and Invite came and went as the permission was re-read. The connected component now snapshots the controller when an action starts and renders that until it settles, so the result lands in one step. Two smaller faults fell out of the same interaction: - The spinner waited out a delay window before appearing, and the check raced ahead of it. Every action here is a network round trip, so there is nothing to debounce: `useSpinDelay` takes `delay: 0` and shows the value in the same pass, with `minDuration` still steadying it. - A row going busy swapped its host element from `<button>` to `<div>`, remounting the subtree and dropping the avatar back to its initials for the length of the action. A row that stands down now stays the button it was, disabled, and `Avatar.Image` resolves a browser-cached `src` in a layout effect so neither a remount nor a swap flashes the fallback.
The popover stayed up behind the surface it opened. Managing, inviting, creating an organization, and adding an account now close it on the way out, whether they open a modal or navigate.
The connected test drives the real controller against a mocked Clerk, which is what makes it worth having and also what makes it slow. Cases that only ever asserted what the popover renders now sit in the view test, leaving the connected one to prove the layers compose. Also covers `hidePersonal` reaching the popover through the container.
UserButtonProps picked only modePriority off the root, so the connected component was hard-wired to the combined surface and the orgs/user modes were reachable only by composing UserButtonView directly.
The placeholder takes its corner from the mode, so the connected component has to hand it down before any data lands.
Stacked on #9185. Adds busy/loading UX to the connected UserButton + an end-to-end integration test.
Changes
Busy/loading states (
controller+container)pendingKey. Clicked affordance spins, others disable (blocks double-submit). Popover closes only on success; busy clears on rejection so UI never hangs.void | Promise<unknown>to satisfyno-misused-promises; fire-and-forget navigations void-wrapped.Spin-delay (
useSpinDelayhook + tests)T | nullflag. Fast actions resolve before delay → no spinner flash; any spinner shown held for min duration → no flicker. Re-entry still guarded on immediatependingKey; only visuals delayed.View decomposition (1032 → ~600 lines)
user-button.recipe.ts, data-contract types +userButtonBusyKeys→user-button.types.ts.BusyButtonprimitive replaces 4 hand-wired busy buttons (inline join/accept, hover sign-out, header actions, footer sign-out-all).UserButtonViewProps; deadstatusfield dropped. No behavior change.Spinner Mosaic primitive.
Integration test (14 tests)
Renders real view through real controller against mocked
@clerk/shared/react, drives real popover + rows/actions, asserts Clerk calls + close-on-success.setActive(...)+ closesetActive({session})+ closesignOut(...)+ closeaccept()+revalidate()+ closenavigate(...), popover stays openCovers every
closeOnSuccesscallback + every navigation through real DOM.Not re-tested here (owned elsewhere): a11y/focus-trap (popover primitive suite), data derivation/gating (
controller.test.tsx). Per-row sign-out is hover-revealed (pointer-events:none), so that one usesfireEvent.click(noted inline).Parity gaps (tracked separately, not test gaps): no
hidePersonal, force-org-selection, or trigger pending-counter badge yet.Changeset
Empty — feature ships under #9184 / #9185, no user-facing change here.