thirdweb 5.75.0-nightly-ec84ed37d6db8281d3afb12bc47a20ccc5fe9713-20241207000341 → 5.76.0-nightly-8234dbae8fcf73ca83bbda31d929aa57ca521a53-20241208000407

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (126) hide show
  1. package/dist/cjs/exports/react.js.map +1 -1
  2. package/dist/cjs/exports/utils.js +5 -1
  3. package/dist/cjs/exports/utils.js.map +1 -1
  4. package/dist/cjs/pay/convert/cryptoToFiat.js.map +1 -1
  5. package/dist/cjs/pay/convert/fiatToCrypto.js +1 -1
  6. package/dist/cjs/pay/convert/fiatToCrypto.js.map +1 -1
  7. package/dist/cjs/pay/convert/type.js +4 -0
  8. package/dist/cjs/pay/convert/type.js.map +1 -0
  9. package/dist/cjs/react/web/ui/ConnectWallet/Details.js +56 -16
  10. package/dist/cjs/react/web/ui/ConnectWallet/Details.js.map +1 -1
  11. package/dist/cjs/react/web/ui/ConnectWallet/screens/ReceiveFunds.js +1 -1
  12. package/dist/cjs/react/web/ui/ConnectWallet/screens/ReceiveFunds.js.map +1 -1
  13. package/dist/cjs/react/web/ui/ConnectWallet/screens/SendFunds.js +3 -2
  14. package/dist/cjs/react/web/ui/ConnectWallet/screens/SendFunds.js.map +1 -1
  15. package/dist/cjs/react/web/ui/components/CopyIcon.js +1 -1
  16. package/dist/cjs/react/web/ui/components/CopyIcon.js.map +1 -1
  17. package/dist/cjs/react/web/ui/components/Skeleton.js +1 -1
  18. package/dist/cjs/react/web/ui/components/Skeleton.js.map +1 -1
  19. package/dist/cjs/react/web/ui/prebuilt/Account/balance.js +114 -26
  20. package/dist/cjs/react/web/ui/prebuilt/Account/balance.js.map +1 -1
  21. package/dist/cjs/react/web/ui/prebuilt/Account/provider.js +3 -0
  22. package/dist/cjs/react/web/ui/prebuilt/Account/provider.js.map +1 -1
  23. package/dist/cjs/utils/formatNumber.js +7 -1
  24. package/dist/cjs/utils/formatNumber.js.map +1 -1
  25. package/dist/cjs/utils/shortenLargeNumber.js +47 -0
  26. package/dist/cjs/utils/shortenLargeNumber.js.map +1 -0
  27. package/dist/cjs/version.js +1 -1
  28. package/dist/cjs/wallets/manager/index.js +35 -24
  29. package/dist/cjs/wallets/manager/index.js.map +1 -1
  30. package/dist/esm/exports/react.js.map +1 -1
  31. package/dist/esm/exports/utils.js +2 -0
  32. package/dist/esm/exports/utils.js.map +1 -1
  33. package/dist/esm/pay/convert/cryptoToFiat.js.map +1 -1
  34. package/dist/esm/pay/convert/fiatToCrypto.js +1 -1
  35. package/dist/esm/pay/convert/fiatToCrypto.js.map +1 -1
  36. package/dist/esm/pay/convert/type.js +3 -0
  37. package/dist/esm/pay/convert/type.js.map +1 -0
  38. package/dist/esm/react/web/ui/ConnectWallet/Details.js +57 -23
  39. package/dist/esm/react/web/ui/ConnectWallet/Details.js.map +1 -1
  40. package/dist/esm/react/web/ui/ConnectWallet/screens/ReceiveFunds.js +1 -1
  41. package/dist/esm/react/web/ui/ConnectWallet/screens/ReceiveFunds.js.map +1 -1
  42. package/dist/esm/react/web/ui/ConnectWallet/screens/SendFunds.js +3 -3
  43. package/dist/esm/react/web/ui/ConnectWallet/screens/SendFunds.js.map +1 -1
  44. package/dist/esm/react/web/ui/components/CopyIcon.js +1 -1
  45. package/dist/esm/react/web/ui/components/CopyIcon.js.map +1 -1
  46. package/dist/esm/react/web/ui/components/Skeleton.js +1 -1
  47. package/dist/esm/react/web/ui/components/Skeleton.js.map +1 -1
  48. package/dist/esm/react/web/ui/prebuilt/Account/balance.js +113 -28
  49. package/dist/esm/react/web/ui/prebuilt/Account/balance.js.map +1 -1
  50. package/dist/esm/react/web/ui/prebuilt/Account/provider.js +3 -0
  51. package/dist/esm/react/web/ui/prebuilt/Account/provider.js.map +1 -1
  52. package/dist/esm/utils/formatNumber.js +7 -1
  53. package/dist/esm/utils/formatNumber.js.map +1 -1
  54. package/dist/esm/utils/shortenLargeNumber.js +44 -0
  55. package/dist/esm/utils/shortenLargeNumber.js.map +1 -0
  56. package/dist/esm/version.js +1 -1
  57. package/dist/esm/wallets/manager/index.js +33 -24
  58. package/dist/esm/wallets/manager/index.js.map +1 -1
  59. package/dist/types/exports/react.d.ts +1 -1
  60. package/dist/types/exports/react.d.ts.map +1 -1
  61. package/dist/types/exports/utils.d.ts +2 -0
  62. package/dist/types/exports/utils.d.ts.map +1 -1
  63. package/dist/types/pay/convert/cryptoToFiat.d.ts +2 -1
  64. package/dist/types/pay/convert/cryptoToFiat.d.ts.map +1 -1
  65. package/dist/types/pay/convert/fiatToCrypto.d.ts +2 -1
  66. package/dist/types/pay/convert/fiatToCrypto.d.ts.map +1 -1
  67. package/dist/types/pay/convert/type.d.ts +7 -0
  68. package/dist/types/pay/convert/type.d.ts.map +1 -0
  69. package/dist/types/react/core/hooks/connection/ConnectButtonProps.d.ts +11 -0
  70. package/dist/types/react/core/hooks/connection/ConnectButtonProps.d.ts.map +1 -1
  71. package/dist/types/react/web/ui/ConnectWallet/Details.d.ts +60 -0
  72. package/dist/types/react/web/ui/ConnectWallet/Details.d.ts.map +1 -1
  73. package/dist/types/react/web/ui/ConnectWallet/screens/ReceiveFunds.d.ts.map +1 -1
  74. package/dist/types/react/web/ui/ConnectWallet/screens/SendFunds.d.ts +15 -0
  75. package/dist/types/react/web/ui/ConnectWallet/screens/SendFunds.d.ts.map +1 -1
  76. package/dist/types/react/web/ui/components/CopyIcon.d.ts.map +1 -1
  77. package/dist/types/react/web/ui/components/Skeleton.d.ts +1 -0
  78. package/dist/types/react/web/ui/components/Skeleton.d.ts.map +1 -1
  79. package/dist/types/react/web/ui/prebuilt/Account/balance.d.ts +58 -9
  80. package/dist/types/react/web/ui/prebuilt/Account/balance.d.ts.map +1 -1
  81. package/dist/types/react/web/ui/prebuilt/Account/provider.d.ts.map +1 -1
  82. package/dist/types/utils/formatNumber.d.ts +7 -1
  83. package/dist/types/utils/formatNumber.d.ts.map +1 -1
  84. package/dist/types/utils/shortenLargeNumber.d.ts +16 -0
  85. package/dist/types/utils/shortenLargeNumber.d.ts.map +1 -0
  86. package/dist/types/version.d.ts +1 -1
  87. package/dist/types/wallets/manager/index.d.ts +4 -0
  88. package/dist/types/wallets/manager/index.d.ts.map +1 -1
  89. package/dist/types/wallets/wallet-connect/types.d.ts +1 -1
  90. package/dist/types/wallets/wallet-connect/types.d.ts.map +1 -1
  91. package/dist/types/wallets/wallet-types.d.ts +1 -1
  92. package/package.json +7 -6
  93. package/src/exports/react.ts +1 -0
  94. package/src/exports/utils.ts +3 -0
  95. package/src/pay/convert/cryptoToFiat.test.ts +21 -1
  96. package/src/pay/convert/cryptoToFiat.ts +2 -1
  97. package/src/pay/convert/fiatToCrypto.test.ts +21 -1
  98. package/src/pay/convert/fiatToCrypto.ts +3 -2
  99. package/src/pay/convert/type.ts +5 -0
  100. package/src/react/core/hooks/connection/ConnectButtonProps.ts +13 -0
  101. package/src/react/web/ui/ConnectWallet/ConnectButton.test.tsx +15 -0
  102. package/src/react/web/ui/ConnectWallet/Details.test.tsx +587 -0
  103. package/src/react/web/ui/ConnectWallet/Details.tsx +174 -67
  104. package/src/react/web/ui/ConnectWallet/screens/PrivateKey.test.tsx +54 -0
  105. package/src/react/web/ui/ConnectWallet/screens/ReceiveFunds.test.tsx +37 -0
  106. package/src/react/web/ui/ConnectWallet/screens/ReceiveFunds.tsx +6 -1
  107. package/src/react/web/ui/ConnectWallet/screens/SendFunds.test.tsx +67 -0
  108. package/src/react/web/ui/ConnectWallet/screens/SendFunds.tsx +3 -2
  109. package/src/react/web/ui/ConnectWallet/screens/StartScreen.test.tsx +71 -0
  110. package/src/react/web/ui/ConnectWallet/screens/formatTokenBalance.test.ts +60 -0
  111. package/src/react/web/ui/ConnectWallet/screens/nativeToken.test.ts +42 -0
  112. package/src/react/web/ui/components/CopyIcon.tsx +5 -1
  113. package/src/react/web/ui/components/Skeleton.tsx +2 -0
  114. package/src/react/web/ui/prebuilt/Account/balance.test.tsx +167 -36
  115. package/src/react/web/ui/prebuilt/Account/balance.tsx +168 -28
  116. package/src/react/web/ui/prebuilt/Account/provider.test.tsx +16 -0
  117. package/src/react/web/ui/prebuilt/Account/provider.tsx +5 -0
  118. package/src/utils/formatNumber.ts +7 -1
  119. package/src/utils/shortenLargeNumber.test.ts +30 -0
  120. package/src/utils/shortenLargeNumber.ts +48 -0
  121. package/src/version.ts +1 -1
  122. package/src/wallets/manager/connection-manager.test.ts +290 -3
  123. package/src/wallets/manager/index.ts +45 -32
  124. package/src/wallets/wallet-connect/receiver/receiver.test.ts +1 -1
  125. package/src/wallets/wallet-connect/types.ts +1 -1
  126. package/src/wallets/wallet-types.ts +1 -1
@@ -3,6 +3,7 @@ import type { Chain } from "../../../../chains/types.js";
3
3
  import type { ThirdwebClient } from "../../../../client/client.js";
4
4
  import type { BuyWithCryptoStatus } from "../../../../pay/buyWithCrypto/getStatus.js";
5
5
  import type { BuyWithFiatStatus } from "../../../../pay/buyWithFiat/getStatus.js";
6
+ import type { SupportedFiatCurrency } from "../../../../pay/convert/type.js";
6
7
  import type { FiatProvider } from "../../../../pay/utils/commonTypes.js";
7
8
  import type { AssetTabs } from "../../../../react/web/ui/ConnectWallet/screens/ViewAssets.js";
8
9
  import type { PreparedTransaction } from "../../../../transaction/prepare-transaction.js";
@@ -320,6 +321,12 @@ export type ConnectButton_detailsModalOptions = {
320
321
  * Note: If an empty array is passed, the [View Funds] button will be hidden
321
322
  */
322
323
  assetTabs?: AssetTabs[];
324
+
325
+ /**
326
+ * Show the token balance's value in fiat.
327
+ * Note: Not all tokens are resolvable to a fiat value. In that case, nothing will be shown.
328
+ */
329
+ showBalanceInFiat?: SupportedFiatCurrency;
323
330
  };
324
331
 
325
332
  /**
@@ -377,6 +384,12 @@ export type ConnectButton_detailsButtonOptions = {
377
384
  * Use custom avatar URL for the connected wallet image in the `ConnectButton` details button, overriding ENS avatar or Blobbie icon.
378
385
  */
379
386
  connectedAccountAvatarUrl?: string;
387
+
388
+ /**
389
+ * Show the token balance's value in fiat.
390
+ * Note: Not all tokens are resolvable to a fiat value. In that case, nothing will be shown.
391
+ */
392
+ showBalanceInFiat?: SupportedFiatCurrency;
380
393
  };
381
394
 
382
395
  /**
@@ -50,4 +50,19 @@ describe("ConnectButton", () => {
50
50
  );
51
51
  expect(screen.getByText("Sign In")).toBeInTheDocument();
52
52
  });
53
+
54
+ it("should render with fiat balance props", () => {
55
+ render(
56
+ <ConnectButton
57
+ client={TEST_CLIENT}
58
+ detailsButton={{
59
+ showBalanceInFiat: "USD",
60
+ }}
61
+ detailsModal={{
62
+ showBalanceInFiat: "USD",
63
+ }}
64
+ />,
65
+ );
66
+ expect(screen.getByText("Connect Wallet")).toBeInTheDocument();
67
+ });
53
68
  });
@@ -0,0 +1,587 @@
1
+ import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
2
+ import type { FC } from "react";
3
+ import { beforeEach, describe, expect, it, vi } from "vitest";
4
+ import { VITALIK_WALLET } from "~test/addresses.js";
5
+ import {
6
+ fireEvent,
7
+ render,
8
+ renderHook,
9
+ screen,
10
+ waitFor,
11
+ } from "~test/react-render.js";
12
+ import { TEST_CLIENT } from "~test/test-clients.js";
13
+ import { base } from "../../../../chains/chain-definitions/base.js";
14
+ import { ethereum } from "../../../../chains/chain-definitions/ethereum.js";
15
+ import { useActiveAccount } from "../../../../react/core/hooks/wallets/useActiveAccount.js";
16
+ import { useActiveWalletChain } from "../../../../react/core/hooks/wallets/useActiveWalletChain.js";
17
+ import { ThirdwebProvider } from "../../providers/thirdweb-provider.js";
18
+ import { AccountProvider } from "../prebuilt/Account/provider.js";
19
+ import {
20
+ ConnectedToSmartWallet,
21
+ ConnectedWalletDetails,
22
+ DetailsModal,
23
+ InAppWalletUserInfo,
24
+ SwitchNetworkButton,
25
+ detailsBtn_formatFiatBalanceForButton,
26
+ detailsBtn_formatTokenBalanceForButton,
27
+ useWalletDetailsModal,
28
+ } from "./Details.js";
29
+ import en from "./locale/en.js";
30
+ import { getConnectLocale } from "./locale/getConnectLocale.js";
31
+
32
+ /**
33
+ * Tests for the Details button and Details Modal (parts of the ConnectButton component)
34
+ */
35
+ const queryClient = new QueryClient();
36
+ const client = TEST_CLIENT;
37
+ vi.mock("../../../core/hooks/wallets/useActiveAccount.js", () => ({
38
+ useActiveAccount: vi.fn(),
39
+ }));
40
+
41
+ const mockDetailsModalOptions = {};
42
+ const mockSupportedTokens = {};
43
+ const mockSupportedNFTs = {};
44
+ // biome-ignore lint/suspicious/noExplicitAny: Mock
45
+ const mockChains: any[] = [];
46
+ const mockDisplayBalanceToken = {};
47
+ const mockConnectOptions = {};
48
+ // biome-ignore lint/suspicious/noExplicitAny: Mock
49
+ const mockAssetTabs: any[] = [];
50
+ const mockOnDisconnect = vi.fn();
51
+
52
+ describe("Details button", () => {
53
+ it("should render (when a wallet is connected)", () => {
54
+ const { container } = render(
55
+ <QueryClientProvider client={queryClient}>
56
+ <AccountProvider address={VITALIK_WALLET} client={client}>
57
+ <ConnectedWalletDetails
58
+ theme={"dark"}
59
+ detailsButton={undefined}
60
+ detailsModal={undefined}
61
+ supportedTokens={undefined}
62
+ supportedNFTs={undefined}
63
+ onDisconnect={() => {}}
64
+ chains={[]}
65
+ switchButton={undefined}
66
+ client={client}
67
+ connectLocale={en}
68
+ connectOptions={undefined}
69
+ />
70
+ </AccountProvider>
71
+ </QueryClientProvider>,
72
+ );
73
+
74
+ const elements = container.getElementsByClassName("tw-connected-wallet");
75
+ expect(!!elements.length).toBe(true);
76
+ });
77
+
78
+ it("should render with showBalanceInFiat", () => {
79
+ const { container } = render(
80
+ <QueryClientProvider client={queryClient}>
81
+ <AccountProvider address={VITALIK_WALLET} client={client}>
82
+ <ConnectedWalletDetails
83
+ theme={"dark"}
84
+ detailsButton={{
85
+ showBalanceInFiat: "USD",
86
+ }}
87
+ detailsModal={undefined}
88
+ supportedTokens={undefined}
89
+ supportedNFTs={undefined}
90
+ onDisconnect={() => {}}
91
+ chains={[]}
92
+ switchButton={undefined}
93
+ client={client}
94
+ connectLocale={en}
95
+ connectOptions={undefined}
96
+ />
97
+ </AccountProvider>
98
+ </QueryClientProvider>,
99
+ );
100
+
101
+ const elements = container.getElementsByClassName("tw-connected-wallet");
102
+ expect(!!elements.length).toBe(true);
103
+ });
104
+
105
+ it("should render with custom UI from the `render` prop", () => {
106
+ const { container } = render(
107
+ <QueryClientProvider client={queryClient}>
108
+ <AccountProvider address={VITALIK_WALLET} client={client}>
109
+ <ConnectedWalletDetails
110
+ theme={"dark"}
111
+ detailsButton={{
112
+ render: () => <p className="thirdweb_tw" />,
113
+ }}
114
+ detailsModal={undefined}
115
+ supportedTokens={undefined}
116
+ supportedNFTs={undefined}
117
+ onDisconnect={() => {}}
118
+ chains={[]}
119
+ switchButton={undefined}
120
+ client={client}
121
+ connectLocale={en}
122
+ connectOptions={undefined}
123
+ />
124
+ </AccountProvider>
125
+ </QueryClientProvider>,
126
+ );
127
+
128
+ const element = container.querySelector("p.thirdweb_tw");
129
+ expect(element).not.toBe(null);
130
+ });
131
+
132
+ it("should render style properly", () => {
133
+ const { container } = render(
134
+ <QueryClientProvider client={queryClient}>
135
+ <AccountProvider address={VITALIK_WALLET} client={client}>
136
+ <ConnectedWalletDetails
137
+ theme={"dark"}
138
+ detailsButton={{
139
+ style: {
140
+ color: "red",
141
+ width: "4444px",
142
+ },
143
+ }}
144
+ detailsModal={undefined}
145
+ supportedTokens={undefined}
146
+ supportedNFTs={undefined}
147
+ onDisconnect={() => {}}
148
+ chains={[]}
149
+ switchButton={undefined}
150
+ client={client}
151
+ connectLocale={en}
152
+ connectOptions={undefined}
153
+ />
154
+ </AccountProvider>
155
+ </QueryClientProvider>,
156
+ );
157
+ const element = container.querySelector(
158
+ '[data-test="connected-wallet-details"]',
159
+ );
160
+ if (!element) {
161
+ throw new Error("Details button not rendered properly");
162
+ }
163
+ const styles = window.getComputedStyle(element);
164
+ expect(styles.color).toBe("red");
165
+ expect(styles.width).toBe("4444px");
166
+ });
167
+
168
+ it("should render the Balance section", () => {
169
+ const { container } = render(
170
+ <QueryClientProvider client={queryClient}>
171
+ <AccountProvider address={VITALIK_WALLET} client={client}>
172
+ <ConnectedWalletDetails
173
+ theme={"dark"}
174
+ detailsButton={undefined}
175
+ detailsModal={undefined}
176
+ supportedTokens={undefined}
177
+ supportedNFTs={undefined}
178
+ onDisconnect={() => {}}
179
+ chains={[]}
180
+ switchButton={undefined}
181
+ client={client}
182
+ connectLocale={en}
183
+ connectOptions={undefined}
184
+ />
185
+ </AccountProvider>
186
+ </QueryClientProvider>,
187
+ );
188
+
189
+ const elements = container.getElementsByClassName(
190
+ "tw-connected-wallet__balance",
191
+ );
192
+ expect(!!elements.length).toBe(true);
193
+ });
194
+
195
+ it("should render the Address section if detailsButton.connectedAccountName is not passed", () => {
196
+ const { container } = render(
197
+ <QueryClientProvider client={queryClient}>
198
+ <AccountProvider address={VITALIK_WALLET} client={client}>
199
+ <ConnectedWalletDetails
200
+ theme={"dark"}
201
+ detailsButton={undefined}
202
+ detailsModal={undefined}
203
+ supportedTokens={undefined}
204
+ supportedNFTs={undefined}
205
+ onDisconnect={() => {}}
206
+ chains={[]}
207
+ switchButton={undefined}
208
+ client={client}
209
+ connectLocale={en}
210
+ connectOptions={undefined}
211
+ />
212
+ </AccountProvider>
213
+ </QueryClientProvider>,
214
+ );
215
+
216
+ const elements = container.getElementsByClassName(
217
+ "tw-connected-wallet__address",
218
+ );
219
+ expect(!!elements.length).toBe(true);
220
+ });
221
+
222
+ it("should NOT render the Address section if detailsButton.connectedAccountName is passed", () => {
223
+ const { container } = render(
224
+ <QueryClientProvider client={queryClient}>
225
+ <AccountProvider address={VITALIK_WALLET} client={client}>
226
+ <ConnectedWalletDetails
227
+ theme={"dark"}
228
+ detailsButton={{
229
+ connectedAccountName: "test name",
230
+ }}
231
+ detailsModal={undefined}
232
+ supportedTokens={undefined}
233
+ supportedNFTs={undefined}
234
+ onDisconnect={() => {}}
235
+ chains={[]}
236
+ switchButton={undefined}
237
+ client={client}
238
+ connectLocale={en}
239
+ connectOptions={undefined}
240
+ />
241
+ </AccountProvider>
242
+ </QueryClientProvider>,
243
+ );
244
+
245
+ const elements = container.getElementsByClassName(
246
+ "tw-connected-wallet__address",
247
+ );
248
+ expect(elements.length).toBe(1);
249
+ expect(elements[0]?.innerHTML).toBe("test name");
250
+ });
251
+
252
+ it("should render a custom img if detailsButton?.connectedAccountAvatarUrl is passed", () => {
253
+ const { container } = render(
254
+ <QueryClientProvider client={queryClient}>
255
+ <AccountProvider address={VITALIK_WALLET} client={client}>
256
+ <ConnectedWalletDetails
257
+ theme={"dark"}
258
+ detailsButton={{
259
+ connectedAccountAvatarUrl: "https://thirdweb.com/cat.png",
260
+ }}
261
+ detailsModal={undefined}
262
+ supportedTokens={undefined}
263
+ supportedNFTs={undefined}
264
+ onDisconnect={() => {}}
265
+ chains={[]}
266
+ switchButton={undefined}
267
+ client={client}
268
+ connectLocale={en}
269
+ connectOptions={undefined}
270
+ />
271
+ </AccountProvider>
272
+ </QueryClientProvider>,
273
+ );
274
+
275
+ const elements = container.getElementsByTagName("img");
276
+ expect(elements.length).toBe(1);
277
+ expect(elements[0]?.src).toBe("https://thirdweb.com/cat.png");
278
+ });
279
+
280
+ it("should render AccountAvatar if no custom image is passed", () => {
281
+ const { container } = render(
282
+ <QueryClientProvider client={queryClient}>
283
+ <AccountProvider address={VITALIK_WALLET} client={client}>
284
+ <ConnectedWalletDetails
285
+ theme={"dark"}
286
+ detailsButton={{
287
+ connectedAccountName: "test name",
288
+ }}
289
+ detailsModal={undefined}
290
+ supportedTokens={undefined}
291
+ supportedNFTs={undefined}
292
+ onDisconnect={() => {}}
293
+ chains={[]}
294
+ switchButton={undefined}
295
+ client={client}
296
+ connectLocale={en}
297
+ connectOptions={undefined}
298
+ />
299
+ </AccountProvider>
300
+ </QueryClientProvider>,
301
+ );
302
+
303
+ const elements = container.getElementsByClassName(
304
+ "tw-connected-wallet__account_avatar",
305
+ );
306
+ expect(elements.length).toBe(1);
307
+ });
308
+
309
+ it("should render the SwitchNetworkButton if chain is mismatched", () => {
310
+ vi.mock(
311
+ "../../../../react/core/hooks/wallets/useActiveWalletChain.js",
312
+ () => ({
313
+ useActiveWalletChain: vi.fn(),
314
+ }),
315
+ );
316
+ vi.mocked(useActiveWalletChain).mockReturnValue(base);
317
+ const { container } = render(
318
+ <QueryClientProvider client={queryClient}>
319
+ <AccountProvider address={VITALIK_WALLET} client={client}>
320
+ <ConnectedWalletDetails
321
+ theme={"dark"}
322
+ detailsButton={{
323
+ connectedAccountName: "test name",
324
+ }}
325
+ detailsModal={undefined}
326
+ supportedTokens={undefined}
327
+ supportedNFTs={undefined}
328
+ onDisconnect={() => {}}
329
+ chains={[]}
330
+ switchButton={{
331
+ style: {
332
+ color: "red",
333
+ },
334
+ className: "thirdwebSwitchBtn",
335
+ label: "switchbtn",
336
+ }}
337
+ client={client}
338
+ connectLocale={en}
339
+ connectOptions={undefined}
340
+ chain={ethereum}
341
+ />
342
+ </AccountProvider>
343
+ </QueryClientProvider>,
344
+ );
345
+ const element = container.querySelector(
346
+ "button.tw-connect-wallet--switch-network",
347
+ );
348
+ expect(element).not.toBe(null);
349
+ const element2 = container.querySelector("button.thirdwebSwitchBtn");
350
+ expect(element2).not.toBe(null);
351
+ expect(element && element.innerHTML === "switchbtn").toBe(true);
352
+ vi.resetAllMocks();
353
+ });
354
+
355
+ it("should render the fiat value properly", () => {
356
+ expect(
357
+ detailsBtn_formatFiatBalanceForButton({ balance: 12.9231, symbol: "$" }),
358
+ ).toBe(" ($13)");
359
+ });
360
+
361
+ it("should render the token balance properly", () => {
362
+ expect(
363
+ detailsBtn_formatTokenBalanceForButton({
364
+ balance: 12.923111,
365
+ symbol: "ETH",
366
+ }),
367
+ ).toBe("12.9231 ETH");
368
+ });
369
+ });
370
+
371
+ const thirdwebWrapper: FC = ({ children }: React.PropsWithChildren) => (
372
+ <ThirdwebProvider>{children}</ThirdwebProvider>
373
+ );
374
+
375
+ /**
376
+ * useWalletDetailsModal
377
+ */
378
+ describe("useWalletDetailsModal", () => {
379
+ beforeEach(() => {
380
+ vi.clearAllMocks();
381
+ });
382
+
383
+ it("should return an object with an open function", () => {
384
+ const { result } = renderHook(() => useWalletDetailsModal(), {
385
+ wrapper: thirdwebWrapper,
386
+ });
387
+ expect(result.current).toHaveProperty("open");
388
+ expect(typeof result.current.open).toBe("function");
389
+ });
390
+
391
+ it("should throw an error when opening modal without a connected wallet", () => {
392
+ const { result } = renderHook(() => useWalletDetailsModal(), {
393
+ wrapper: thirdwebWrapper,
394
+ });
395
+
396
+ expect(() =>
397
+ result.current.open({
398
+ client,
399
+ }),
400
+ ).toThrow("Wallet is not connected.");
401
+ });
402
+ });
403
+
404
+ /**
405
+ * SwitchNetworkButton
406
+ */
407
+ describe("SwitchNetworkButton", () => {
408
+ it("should render a default button", () => {
409
+ const { container } = render(
410
+ <SwitchNetworkButton targetChain={ethereum} connectLocale={en} />,
411
+ );
412
+ const element = container.querySelector(
413
+ "button.tw-connect-wallet--switch-network",
414
+ );
415
+ expect(element).not.toBe(null);
416
+ });
417
+
418
+ it("should apply the style properly", () => {
419
+ const { container } = render(
420
+ <SwitchNetworkButton
421
+ targetChain={ethereum}
422
+ connectLocale={en}
423
+ style={{ color: "red", width: "4444px" }}
424
+ />,
425
+ );
426
+ const element = container.querySelector(
427
+ "button.tw-connect-wallet--switch-network",
428
+ );
429
+ if (!element) {
430
+ throw new Error("Failed to render SwitchNetworkButton");
431
+ }
432
+ const styles = window.getComputedStyle(element);
433
+ expect(styles.color).toBe("red");
434
+ expect(styles.width).toBe("4444px");
435
+ });
436
+
437
+ it("should apply the className properly", () => {
438
+ const { container } = render(
439
+ <SwitchNetworkButton
440
+ targetChain={ethereum}
441
+ connectLocale={en}
442
+ className="thirdwebRocks"
443
+ />,
444
+ );
445
+ const element = container.querySelector("button.thirdwebRocks");
446
+ expect(element).not.toBe(null);
447
+ });
448
+
449
+ it("should render button's text with locale.switchNetwork by default", () => {
450
+ const { container } = render(
451
+ <SwitchNetworkButton targetChain={ethereum} connectLocale={en} />,
452
+ );
453
+ const element = container.querySelector(
454
+ "button.tw-connect-wallet--switch-network",
455
+ );
456
+ if (!element) {
457
+ throw new Error("Failed to render SwitchNetworkButton");
458
+ }
459
+ expect(element.innerHTML).toBe(en.switchNetwork);
460
+ });
461
+
462
+ it("should render `switchNetworkBtnTitle` properly", () => {
463
+ const { container } = render(
464
+ <SwitchNetworkButton
465
+ targetChain={ethereum}
466
+ connectLocale={en}
467
+ switchNetworkBtnTitle="cat"
468
+ />,
469
+ );
470
+ const element = container.querySelector(
471
+ "button.tw-connect-wallet--switch-network",
472
+ );
473
+ if (!element) {
474
+ throw new Error("Failed to render SwitchNetworkButton");
475
+ }
476
+ expect(element.innerHTML).toBe("cat");
477
+ });
478
+ });
479
+
480
+ describe("ConnectedToSmartWallet", () => {
481
+ it("should render nothing since no active wallet exists in default test env", () => {
482
+ const { container } = render(
483
+ <ThirdwebProvider>
484
+ <ConnectedToSmartWallet client={client} connectLocale={en} />
485
+ </ThirdwebProvider>,
486
+ );
487
+ // no smart wallet exists in this env so this component should render null
488
+ const element = container.querySelector("span");
489
+ expect(element).toBe(null);
490
+ });
491
+ });
492
+
493
+ describe("InAppWalletUserInfo", () => {
494
+ it("should render a Skeleton since no active wallet exists in default test env", () => {
495
+ const { container } = render(
496
+ <ThirdwebProvider>
497
+ <InAppWalletUserInfo client={client} locale={en} />
498
+ </ThirdwebProvider>,
499
+ );
500
+ // no smart wallet exists in this env so this component should render null
501
+ const element = container.querySelector(
502
+ "div.InAppWalletUserInfo__skeleton",
503
+ );
504
+ expect(element).not.toBe(null);
505
+ });
506
+ });
507
+
508
+ describe("Details Modal", () => {
509
+ beforeEach(() => {
510
+ // Mock the animate method
511
+ HTMLDivElement.prototype.animate = vi.fn().mockReturnValue({
512
+ onfinish: vi.fn(),
513
+ });
514
+ });
515
+
516
+ it("should close the modal when activeAccount is falsy", async () => {
517
+ const closeModalMock = vi.fn();
518
+ const locale = await getConnectLocale("en_US");
519
+
520
+ vi.mocked(useActiveAccount).mockReturnValue(undefined);
521
+
522
+ render(
523
+ <DetailsModal
524
+ client={TEST_CLIENT}
525
+ locale={locale}
526
+ detailsModal={mockDetailsModalOptions}
527
+ theme="light"
528
+ supportedTokens={mockSupportedTokens}
529
+ supportedNFTs={mockSupportedNFTs}
530
+ closeModal={closeModalMock}
531
+ onDisconnect={mockOnDisconnect}
532
+ chains={mockChains}
533
+ displayBalanceToken={mockDisplayBalanceToken}
534
+ connectOptions={mockConnectOptions}
535
+ assetTabs={mockAssetTabs}
536
+ />,
537
+ );
538
+
539
+ await waitFor(() => {
540
+ expect(closeModalMock).toHaveBeenCalled();
541
+ });
542
+ });
543
+
544
+ it("should render the DetailsModal with default props", async () => {
545
+ const closeModalMock = vi.fn();
546
+ const locale = await getConnectLocale("en_US");
547
+
548
+ render(
549
+ <DetailsModal
550
+ client={TEST_CLIENT}
551
+ locale={locale}
552
+ theme="light"
553
+ closeModal={closeModalMock}
554
+ onDisconnect={mockOnDisconnect}
555
+ chains={mockChains}
556
+ connectOptions={mockConnectOptions}
557
+ />,
558
+ );
559
+
560
+ // Add assertions to check if the modal is rendered correctly
561
+ expect(screen.getByText("Connect Modal")).toBeInTheDocument();
562
+ });
563
+
564
+ it("should call closeModal when the close button is clicked", async () => {
565
+ const closeModalMock = vi.fn();
566
+ const locale = await getConnectLocale("en_US");
567
+
568
+ render(
569
+ <DetailsModal
570
+ client={TEST_CLIENT}
571
+ locale={locale}
572
+ theme="light"
573
+ closeModal={closeModalMock}
574
+ onDisconnect={mockOnDisconnect}
575
+ chains={mockChains}
576
+ connectOptions={mockConnectOptions}
577
+ />,
578
+ );
579
+
580
+ // Simulate clicking the close button
581
+ fireEvent.click(screen.getByRole("button", { name: /close/i }));
582
+
583
+ await waitFor(() => {
584
+ expect(closeModalMock).toHaveBeenCalled();
585
+ });
586
+ });
587
+ });