diff --git a/.changeset/web3-wallet-add-hooks-crash.md b/.changeset/web3-wallet-add-hooks-crash.md new file mode 100644 index 00000000000..89750b6198c --- /dev/null +++ b/.changeset/web3-wallet-add-hooks-crash.md @@ -0,0 +1,5 @@ +--- +'@clerk/ui': patch +--- + +Fix `` crashing with "Rendered fewer hooks than expected" after connecting the last available Web3 wallet. diff --git a/packages/ui/src/components/UserProfile/Web3Form.tsx b/packages/ui/src/components/UserProfile/Web3Form.tsx index 39cb0e54f0a..95b18d82444 100644 --- a/packages/ui/src/components/UserProfile/Web3Form.tsx +++ b/packages/ui/src/components/UserProfile/Web3Form.tsx @@ -25,15 +25,14 @@ export const AddWeb3WalletActionMenu = () => { const unconnectedStrategies = enabledStrategies.filter(strategy => { return !connectedStrategies.includes(strategy) && strategyToDisplayData[strategy]; }); + const createWeb3Wallet = useReverification((identifier: string) => + user?.createWeb3Wallet({ web3Wallet: identifier }), + ); if (unconnectedStrategies.length === 0) { return null; } - const createWeb3Wallet = useReverification((identifier: string) => - user?.createWeb3Wallet({ web3Wallet: identifier }), - ); - // If the user selects `web3_solana_signature` as their strategy, // we need to obtain the wallet name to use when connecting and signing the message during the auth flow // diff --git a/packages/ui/src/components/UserProfile/__tests__/Web3Section.test.tsx b/packages/ui/src/components/UserProfile/__tests__/Web3Section.test.tsx index e972492ea2f..d77f735ca7b 100644 --- a/packages/ui/src/components/UserProfile/__tests__/Web3Section.test.tsx +++ b/packages/ui/src/components/UserProfile/__tests__/Web3Section.test.tsx @@ -178,4 +178,30 @@ describe('Web3Section', () => { }); }); }); + + // Regression: connecting the last unconnected strategy used to crash the whole + // UserProfile with "Rendered fewer hooks than expected", because the action menu + // returned early before calling `useReverification`. + it('keeps rendering after the last enabled wallet strategy gets connected', async () => { + // GIVEN MetaMask is the only enabled web3 strategy and the user has not connected it + const withMetamaskEnabled = createFixtures.config(f => { + f.withWeb3Wallet(); + f.withUser({ email_addresses: ['test@clerk.com'] }); + }); + const { wrapper, fixtures } = await createFixtures(withMetamaskEnabled); + const { getByRole, getByText, queryByRole, rerender } = render(, { wrapper }); + getByRole('button', { name: /Connect wallet/i }); + + // WHEN the user resource updates with a verified MetaMask wallet, as it does after attemptVerification + const { fixtures: connected } = await createFixtures(withMetamaskWallet); + (fixtures.clerk as any).__internal_lastEmittedResources = { + ...(fixtures.clerk as any).__internal_lastEmittedResources, + user: connected.clerk.user, + }; + rerender(); + + // THEN the wallet is listed and the connect menu is gone + getByText(/0x1234...5678/); + expect(queryByRole('button', { name: /Connect wallet/i })).toBeNull(); + }); });