@0xsequence/marketplace-sdk 0.5.2 → 0.5.4

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 (184) hide show
  1. package/dist/builder-types-Jl3Ymws8.d.ts +73 -0
  2. package/dist/{chunk-XP3WY5AX.js → chunk-7C7ADZ2H.js} +3 -3
  3. package/dist/{chunk-XP3WY5AX.js.map → chunk-7C7ADZ2H.js.map} +1 -1
  4. package/dist/{chunk-FCF57DZI.js → chunk-7FN62HOP.js} +5 -9
  5. package/dist/chunk-7FN62HOP.js.map +1 -0
  6. package/dist/chunk-DZKPDV63.js +27 -0
  7. package/dist/chunk-DZKPDV63.js.map +1 -0
  8. package/dist/{chunk-ZUEQGPLO.js → chunk-J6F5QOW5.js} +2 -2
  9. package/dist/{chunk-ZUEQGPLO.js.map → chunk-J6F5QOW5.js.map} +1 -1
  10. package/dist/{chunk-I37CRQ4S.js → chunk-JWNONWD6.js} +259 -173
  11. package/dist/chunk-JWNONWD6.js.map +1 -0
  12. package/dist/{chunk-LJAB3S6U.js → chunk-TFRAOS7F.js} +22 -13
  13. package/dist/chunk-TFRAOS7F.js.map +1 -0
  14. package/dist/{chunk-MKGSGTQC.js → chunk-TLNRD4BQ.js} +3 -3
  15. package/dist/{chunk-5NORRVPM.js → chunk-UZIAX32Y.js} +1 -1
  16. package/dist/{chunk-5NORRVPM.js.map → chunk-UZIAX32Y.js.map} +1 -1
  17. package/dist/chunk-WGGZEQHL.js +56 -0
  18. package/dist/chunk-WGGZEQHL.js.map +1 -0
  19. package/dist/{chunk-MWDG7UTB.js → chunk-ZBLU3Q22.js} +1 -1
  20. package/dist/{chunk-MSTTVFVQ.js → chunk-ZGVCOQ4I.js} +383 -283
  21. package/dist/chunk-ZGVCOQ4I.js.map +1 -0
  22. package/dist/{create-config-BXvwUh55.d.ts → create-config-DOUq8Day.d.ts} +2 -2
  23. package/dist/index.css +1 -1
  24. package/dist/index.d.ts +5 -4
  25. package/dist/index.js +10 -6
  26. package/dist/{sdk-config-B32_2bG3.d.ts → marketplace.gen-D0ADxbfH.d.ts} +1 -24
  27. package/dist/react/_internal/api/index.d.ts +3 -2
  28. package/dist/react/_internal/databeat/index.css +82 -0
  29. package/dist/react/_internal/databeat/index.css.map +1 -0
  30. package/dist/react/_internal/databeat/index.d.ts +68 -0
  31. package/dist/react/_internal/databeat/index.js +26 -0
  32. package/dist/react/_internal/databeat/index.js.map +1 -0
  33. package/dist/react/_internal/index.d.ts +6 -5
  34. package/dist/react/_internal/index.js +6 -6
  35. package/dist/react/_internal/wagmi/index.d.ts +4 -4
  36. package/dist/react/_internal/wagmi/index.js +1 -1
  37. package/dist/react/hooks/index.d.ts +367 -22
  38. package/dist/react/hooks/index.js +9 -7
  39. package/dist/react/index.css +1 -1
  40. package/dist/react/index.css.map +1 -1
  41. package/dist/react/index.d.ts +7 -6
  42. package/dist/react/index.js +15 -12
  43. package/dist/react/ssr/index.d.ts +54 -41
  44. package/dist/react/ssr/index.js +5 -9
  45. package/dist/react/ssr/index.js.map +1 -1
  46. package/dist/react/ui/components/collectible-card/index.css +1 -1
  47. package/dist/react/ui/components/collectible-card/index.css.map +1 -1
  48. package/dist/react/ui/components/collectible-card/index.d.ts +4 -3
  49. package/dist/react/ui/components/collectible-card/index.js +9 -8
  50. package/dist/react/ui/components/marketplace-logos/index.js +1 -1
  51. package/dist/react/ui/index.css +1 -1
  52. package/dist/react/ui/index.css.map +1 -1
  53. package/dist/react/ui/index.d.ts +4 -3
  54. package/dist/react/ui/index.js +9 -8
  55. package/dist/react/ui/modals/_internal/components/actionModal/index.d.ts +4 -3
  56. package/dist/react/ui/modals/_internal/components/actionModal/index.js +6 -6
  57. package/dist/react/ui/styles/index.d.ts +1 -1
  58. package/dist/sdk-config-xWkdBdrL.d.ts +24 -0
  59. package/dist/{services-BRBVE0mm.d.ts → services-Dd2MoBTM.d.ts} +2 -1
  60. package/dist/styles/index.css +1 -1
  61. package/dist/styles/index.css.map +1 -1
  62. package/dist/styles/index.d.ts +1 -1
  63. package/dist/styles/index.js +1 -1
  64. package/dist/types/index.d.ts +4 -5
  65. package/dist/types/index.js +9 -5
  66. package/dist/{types-Yto6KrTN.d.ts → types-vOfhbBkR.d.ts} +3 -2
  67. package/dist/utils/index.d.ts +4 -3
  68. package/dist/utils/index.js +4 -4
  69. package/package.json +12 -10
  70. package/src/react/_internal/api/__mocks__/indexer.msw.ts +197 -0
  71. package/src/react/_internal/api/__mocks__/marketplace.msw.ts +140 -1
  72. package/src/react/_internal/api/__mocks__/metadata.msw.ts +162 -0
  73. package/src/react/_internal/databeat/index.ts +63 -0
  74. package/src/react/_internal/databeat/types.ts +70 -0
  75. package/src/react/_internal/test/mocks/publicClient.ts +39 -0
  76. package/src/react/_internal/test/mocks/wagmi.ts +61 -0
  77. package/src/react/_internal/test/mocks/wallet.ts +61 -0
  78. package/src/react/_internal/test/setup.ts +28 -0
  79. package/src/react/_internal/test-utils.tsx +31 -2
  80. package/src/react/_internal/wagmi/__tests__/create-config.test.ts +53 -20
  81. package/src/react/_internal/wagmi/create-config.ts +3 -4
  82. package/src/react/_internal/wagmi/embedded.ts +1 -4
  83. package/src/react/_internal/wagmi/universal.ts +1 -4
  84. package/src/react/_internal/wallet/wallet.ts +1 -0
  85. package/src/react/hooks/__tests__/useAutoSelectFeeOption.test.tsx +314 -0
  86. package/src/react/hooks/__tests__/useBalanceOfCollectible.test.tsx +148 -0
  87. package/src/react/hooks/__tests__/useCancelOrder.test.tsx +410 -0
  88. package/src/react/hooks/__tests__/useCancelTransactionSteps.test.tsx +269 -0
  89. package/src/react/hooks/__tests__/useCollectible.test.tsx +120 -0
  90. package/src/react/hooks/__tests__/useCollection.test.tsx +101 -0
  91. package/src/react/hooks/__tests__/useCollectionBalanceDetails.test.tsx +175 -0
  92. package/src/react/hooks/__tests__/useCollectionDetails.test.tsx +82 -0
  93. package/src/react/hooks/__tests__/useCollectionDetailsPolling.test.tsx +133 -0
  94. package/src/react/hooks/__tests__/useCountListingsForCollectible.test.tsx +108 -0
  95. package/src/react/hooks/__tests__/useCountOfCollectables.test.tsx +129 -0
  96. package/src/react/hooks/__tests__/useCountOffersForCollectible.test.tsx +108 -0
  97. package/src/react/hooks/__tests__/useCurrencies.test.tsx +176 -0
  98. package/src/react/hooks/__tests__/useCurrency.test.tsx +153 -0
  99. package/src/react/hooks/__tests__/useCurrencyBalance.test.tsx +111 -0
  100. package/src/react/hooks/__tests__/useFilters.test.tsx +127 -0
  101. package/src/react/hooks/__tests__/useFloorOrder.test.tsx +101 -0
  102. package/src/react/hooks/__tests__/useGenerateBuyTransaction.test.tsx +173 -0
  103. package/src/react/hooks/__tests__/useGenerateCancelTransaction.test.tsx +207 -0
  104. package/src/react/hooks/__tests__/useGenerateListingTransaction.test.tsx +207 -0
  105. package/src/react/hooks/__tests__/useGenerateOfferTransaction.test.tsx +205 -0
  106. package/src/react/hooks/__tests__/useGenerateSellTransaction.test.tsx +181 -0
  107. package/src/react/hooks/__tests__/useHighestOffer.test.tsx +118 -0
  108. package/src/react/hooks/__tests__/useListBalances.test.tsx +136 -0
  109. package/src/react/hooks/__tests__/useListCollectibleActivities.test.tsx +200 -0
  110. package/src/react/hooks/__tests__/useListCollectibles.test.tsx +232 -0
  111. package/src/react/hooks/__tests__/useListCollectiblesPaginated.test.tsx +217 -0
  112. package/src/react/hooks/__tests__/useListCollectionActivities.test.tsx +235 -0
  113. package/src/react/hooks/__tests__/useListCollections.test.tsx +296 -0
  114. package/src/react/hooks/__tests__/useListListingsForCollectible.test.tsx +140 -0
  115. package/src/react/hooks/__tests__/useListOffersForCollectible.test.tsx +140 -0
  116. package/src/react/hooks/__tests__/useLowestListing.test.tsx +148 -0
  117. package/src/react/hooks/__tests__/useMarketplaceConfig.test.tsx +106 -0
  118. package/src/react/hooks/__tests__/useRoyaltyPercentage.test.tsx +129 -0
  119. package/src/react/hooks/index.ts +1 -1
  120. package/src/react/hooks/options/__mocks__/marketplaceConfig.msw.ts +66 -10
  121. package/src/react/hooks/options/__tests__/marketplaceConfigOptions.test.tsx +2 -11
  122. package/src/react/hooks/options/marketplaceConfigOptions.ts +8 -3
  123. package/src/react/hooks/useAutoSelectFeeOption.tsx +4 -3
  124. package/src/react/hooks/useCancelTransactionSteps.tsx +17 -9
  125. package/src/react/hooks/useCollectionDetailsPolling.tsx +1 -1
  126. package/src/react/hooks/useCurrencies.tsx +29 -28
  127. package/src/react/hooks/useFilters.tsx +75 -2
  128. package/src/react/hooks/useGenerateBuyTransaction.tsx +13 -5
  129. package/src/react/hooks/useListCollectibleActivities.tsx +1 -0
  130. package/src/react/hooks/useListCollectibles.tsx +1 -0
  131. package/src/react/hooks/useListCollectiblesPaginated.tsx +78 -0
  132. package/src/react/hooks/useListCollectionActivities.tsx +1 -0
  133. package/src/react/hooks/useListCollections.tsx +2 -2
  134. package/src/react/ui/components/_internals/custom-select/__tests__/CustomSelect.test.tsx +6 -2
  135. package/src/react/ui/components/collectible-card/CollectibleCard.tsx +1 -1
  136. package/src/react/ui/components/collectible-card/Footer.tsx +9 -5
  137. package/src/react/ui/modals/BuyModal/Modal.tsx +9 -4
  138. package/src/react/ui/modals/BuyModal/__tests__/Modal.test.tsx +0 -1
  139. package/src/react/ui/modals/BuyModal/__tests__/store.test.ts +4 -2
  140. package/src/react/ui/modals/BuyModal/hooks/__tests__/useBuyCollectable.test.tsx +1 -24
  141. package/src/react/ui/modals/BuyModal/hooks/__tests__/useCheckoutOptions.test.tsx +152 -210
  142. package/src/react/ui/modals/BuyModal/hooks/__tests__/useFees.test.tsx +19 -49
  143. package/src/react/ui/modals/BuyModal/hooks/useFees.ts +6 -6
  144. package/src/react/ui/modals/BuyModal/modals/Modal1155.tsx +4 -2
  145. package/src/react/ui/modals/BuyModal/modals/__tests__/Modal1155.test.tsx +161 -52
  146. package/src/react/ui/modals/BuyModal/store.ts +7 -0
  147. package/src/react/ui/modals/CreateListingModal/Modal.tsx +1 -3
  148. package/src/react/ui/modals/CreateListingModal/__tests__/Modal.test.tsx +59 -227
  149. package/src/react/ui/modals/CreateListingModal/hooks/useCreateListing.tsx +2 -1
  150. package/src/react/ui/modals/CreateListingModal/hooks/useTransactionSteps.tsx +47 -7
  151. package/src/react/ui/modals/MakeOfferModal/Modal.tsx +1 -8
  152. package/src/react/ui/modals/MakeOfferModal/__tests__/Modal.test.tsx +41 -118
  153. package/src/react/ui/modals/MakeOfferModal/hooks/useMakeOffer.tsx +2 -1
  154. package/src/react/ui/modals/MakeOfferModal/hooks/useTransactionSteps.tsx +34 -6
  155. package/src/react/ui/modals/SellModal/Modal.tsx +3 -1
  156. package/src/react/ui/modals/SellModal/__tests__/Modal.test.tsx +4 -3
  157. package/src/react/ui/modals/SellModal/hooks/useGetTokenApproval.tsx +33 -31
  158. package/src/react/ui/modals/SellModal/hooks/useSell.tsx +11 -7
  159. package/src/react/ui/modals/SellModal/hooks/useTransactionSteps.tsx +58 -16
  160. package/src/react/ui/modals/SuccessfulPurchaseModal/__tests__/Modal.test.tsx +0 -1
  161. package/src/react/ui/modals/_internal/components/actionModal/ErrorModal.tsx +4 -2
  162. package/src/react/ui/modals/_internal/components/currencyOptionsSelect/__tests__/index.test.tsx +129 -57
  163. package/src/react/ui/modals/_internal/components/currencyOptionsSelect/index.tsx +1 -3
  164. package/src/react/ui/modals/_internal/components/priceInput/__tests__/index.test.tsx +1 -3
  165. package/src/react/ui/modals/_internal/components/transactionDetails/index.tsx +2 -2
  166. package/src/react/ui/modals/_internal/components/transactionStatusModal/__tests__/TransactionStatusModal.test.tsx +8 -8
  167. package/src/react/ui/modals/_internal/components/transactionStatusModal/hooks/useTransactionStatus.ts +1 -0
  168. package/src/types/builder-types.ts +79 -0
  169. package/src/types/index.ts +1 -1
  170. package/src/utils/__tests__/get-public-rpc-client.test.ts +2 -0
  171. package/src/utils/getMarketplaceDetails.ts +2 -2
  172. package/tsconfig.tsbuildinfo +1 -1
  173. package/vitest.config.js +2 -1
  174. package/dist/chunk-FCF57DZI.js.map +0 -1
  175. package/dist/chunk-I37CRQ4S.js.map +0 -1
  176. package/dist/chunk-LJAB3S6U.js.map +0 -1
  177. package/dist/chunk-MSTTVFVQ.js.map +0 -1
  178. package/dist/chunk-RK6KYMZM.js +0 -18
  179. package/dist/chunk-RK6KYMZM.js.map +0 -1
  180. package/dist/marketplace-config-znEu4L0K.d.ts +0 -60
  181. package/src/react/hooks/useCurrencyOptions.tsx +0 -16
  182. package/src/types/marketplace-config.ts +0 -67
  183. /package/dist/{chunk-MKGSGTQC.js.map → chunk-TLNRD4BQ.js.map} +0 -0
  184. /package/dist/{chunk-MWDG7UTB.js.map → chunk-ZBLU3Q22.js.map} +0 -0
@@ -0,0 +1,314 @@
1
+ import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';
2
+ import { useAutoSelectFeeOption } from '../useAutoSelectFeeOption';
3
+ import { renderHook, waitFor } from '../../_internal/test-utils';
4
+ import { zeroAddress } from 'viem';
5
+ import { http, HttpResponse } from 'msw';
6
+ import { server } from '../../_internal/test/setup';
7
+ import {
8
+ mockTokenBalance,
9
+ mockIndexerEndpoint,
10
+ mockIndexerHandler,
11
+ } from '../../_internal/api/__mocks__/indexer.msw';
12
+ import { useAccount } from 'wagmi';
13
+ import { useChain } from '@0xsequence/kit';
14
+ import { mainnet } from 'wagmi/chains';
15
+ import type { FeeOption } from '../../ui/modals/_internal/components/waasFeeOptionsSelect/WaasFeeOptionsSelect';
16
+
17
+ // Mock wagmi hooks
18
+ vi.mock('wagmi', async () => {
19
+ const actual = await vi.importActual('wagmi');
20
+ return {
21
+ ...actual,
22
+ useAccount: vi.fn(),
23
+ };
24
+ });
25
+
26
+ // Mock @0xsequence/kit
27
+ vi.mock('@0xsequence/kit', () => ({
28
+ useChain: vi.fn(),
29
+ }));
30
+
31
+ describe('useAutoSelectFeeOption', () => {
32
+ const mockUserAddress = '0x1234567890123456789012345678901234567890';
33
+ const mockChainId = 1;
34
+
35
+ const mockFeeOptions: FeeOption[] = [
36
+ {
37
+ token: {
38
+ chainId: mockChainId,
39
+ contractAddress: null,
40
+ decimals: 18,
41
+ logoURL: 'https://example.com/eth.png',
42
+ name: 'Ethereum',
43
+ symbol: 'ETH',
44
+ tokenID: null,
45
+ type: 'NATIVE',
46
+ },
47
+ value: '1000000000000000000', // 1 ETH
48
+ gasLimit: 21000,
49
+ to: zeroAddress,
50
+ },
51
+ {
52
+ token: {
53
+ chainId: mockChainId,
54
+ contractAddress: '0x1234567890123456789012345678901234567890',
55
+ decimals: 6,
56
+ logoURL: 'https://example.com/usdc.png',
57
+ name: 'USD Coin',
58
+ symbol: 'USDC',
59
+ tokenID: null,
60
+ type: 'ERC20',
61
+ },
62
+ value: '1000000', // 1 USDC
63
+ gasLimit: 21000,
64
+ to: zeroAddress,
65
+ },
66
+ ];
67
+
68
+ const defaultArgs = {
69
+ pendingFeeOptionConfirmation: {
70
+ id: 'test-id',
71
+ options: mockFeeOptions,
72
+ chainId: mockChainId,
73
+ },
74
+ };
75
+
76
+ beforeEach(() => {
77
+ // Reset handlers before each test
78
+ server.resetHandlers();
79
+
80
+ // Mock useAccount hook with complete wagmi account type
81
+ vi.mocked(useAccount).mockReturnValue({
82
+ address: mockUserAddress as `0x${string}`,
83
+ addresses: [mockUserAddress as `0x${string}`],
84
+ chain: mainnet,
85
+ chainId: mockChainId,
86
+ connector: undefined,
87
+ isConnected: true,
88
+ isConnecting: false,
89
+ isDisconnected: false,
90
+ isReconnecting: true,
91
+ status: 'reconnecting',
92
+ });
93
+
94
+ // Mock useChain hook with required chain properties
95
+ vi.mocked(useChain).mockReturnValue({
96
+ ...mainnet,
97
+ id: mockChainId,
98
+ name: 'Ethereum',
99
+ nativeCurrency: {
100
+ name: 'Ether',
101
+ symbol: 'ETH',
102
+ decimals: 18,
103
+ },
104
+ });
105
+
106
+ // Set up default handler for successful balance check
107
+ server.use(
108
+ mockIndexerHandler('GetTokenBalancesDetails', {
109
+ page: { page: 1, pageSize: 10, more: false },
110
+ balances: [
111
+ {
112
+ ...mockTokenBalance,
113
+ balance: '2000000000000000000', // 2 ETH
114
+ contractAddress: zeroAddress,
115
+ },
116
+ ],
117
+ nativeBalances: [
118
+ {
119
+ balance: '2000000000000000000', // 2 ETH
120
+ blockHash: '0x1234',
121
+ blockNumber: 1234567,
122
+ },
123
+ ],
124
+ }),
125
+ );
126
+ });
127
+
128
+ afterEach(() => {
129
+ vi.clearAllMocks();
130
+ });
131
+
132
+ it('should select the first fee option with sufficient balance', async () => {
133
+ const { result } = renderHook(() => useAutoSelectFeeOption(defaultArgs));
134
+
135
+ // Wait for the hook to complete
136
+ await waitFor(async () => {
137
+ const response = await result.current;
138
+ expect(response.selectedOption).toBe(mockFeeOptions[0]);
139
+ });
140
+
141
+ // Verify final state
142
+ const finalResponse = await result.current;
143
+ expect(finalResponse).toEqual({
144
+ selectedOption: mockFeeOptions[0],
145
+ error: null,
146
+ });
147
+ });
148
+
149
+ it('should return InsufficientBalanceForAnyFeeOption error when user has insufficient balance for all options', async () => {
150
+ // Override handler for insufficient balances
151
+ server.use(
152
+ mockIndexerHandler('GetTokenBalancesDetails', {
153
+ page: { page: 1, pageSize: 10, more: false },
154
+ balances: [
155
+ {
156
+ ...mockTokenBalance,
157
+ balance: '500000000000000000', // 0.5 ETH (less than required 1 ETH)
158
+ contractAddress: zeroAddress,
159
+ },
160
+ ],
161
+ nativeBalances: [
162
+ {
163
+ balance: '500000000000000000', // 0.5 ETH
164
+ blockHash: '0x1234',
165
+ blockNumber: 1234567,
166
+ },
167
+ ],
168
+ }),
169
+ );
170
+
171
+ const { result } = renderHook(() => useAutoSelectFeeOption(defaultArgs));
172
+
173
+ // Wait for the hook to complete
174
+ await waitFor(async () => {
175
+ const response = await result.current;
176
+ expect(response.error).toBe('Insufficient balance for any fee option');
177
+ });
178
+
179
+ // Verify final state
180
+ const finalResponse = await result.current;
181
+ expect(finalResponse).toEqual({
182
+ selectedOption: null,
183
+ error: 'Insufficient balance for any fee option',
184
+ });
185
+ });
186
+
187
+ it('should return UserNotConnected error when wallet is not connected', async () => {
188
+ // Mock useAccount to return no address (user not connected)
189
+ vi.mocked(useAccount).mockReturnValue({
190
+ address: undefined,
191
+ addresses: [],
192
+ chain: mainnet,
193
+ chainId: mockChainId,
194
+ connector: undefined,
195
+ isConnected: false,
196
+ isConnecting: false,
197
+ isDisconnected: false,
198
+ isReconnecting: true,
199
+ status: 'reconnecting',
200
+ });
201
+
202
+ const { result } = renderHook(() => useAutoSelectFeeOption(defaultArgs));
203
+
204
+ // Wait for the hook to complete
205
+ await waitFor(async () => {
206
+ const response = await result.current;
207
+ expect(response.error).toBe('User not connected');
208
+ });
209
+
210
+ // Verify final state
211
+ const finalResponse = await result.current;
212
+ expect(finalResponse).toEqual({
213
+ selectedOption: null,
214
+ error: 'User not connected',
215
+ });
216
+ });
217
+
218
+ it('should select second fee option when user has insufficient balance for first but sufficient for second', async () => {
219
+ // Override handler for mixed balance scenario
220
+ server.use(
221
+ mockIndexerHandler('GetTokenBalancesDetails', {
222
+ page: { page: 1, pageSize: 10, more: false },
223
+ balances: [
224
+ {
225
+ ...mockTokenBalance,
226
+ balance: '500000000000000000', // 0.5 ETH (less than required 1 ETH)
227
+ contractAddress: zeroAddress,
228
+ },
229
+ {
230
+ ...mockTokenBalance,
231
+ balance: '2000000', // 2 USDC (more than required 1 USDC)
232
+ contractAddress: '0x1234567890123456789012345678901234567890',
233
+ },
234
+ ],
235
+ nativeBalances: [
236
+ {
237
+ balance: '500000000000000000', // 0.5 ETH
238
+ blockHash: '0x1234',
239
+ blockNumber: 1234567,
240
+ },
241
+ ],
242
+ }),
243
+ );
244
+
245
+ const { result } = renderHook(() => useAutoSelectFeeOption(defaultArgs));
246
+
247
+ // Wait for the hook to complete
248
+ await waitFor(async () => {
249
+ const response = await result.current;
250
+ expect(response.selectedOption).toBe(mockFeeOptions[1]);
251
+ });
252
+
253
+ // Verify final state
254
+ const finalResponse = await result.current;
255
+ expect(finalResponse).toEqual({
256
+ selectedOption: mockFeeOptions[1],
257
+ error: null,
258
+ });
259
+ });
260
+
261
+ it('should return NoOptionsProvided error when fee options are undefined', async () => {
262
+ const argsWithNoOptions = {
263
+ pendingFeeOptionConfirmation: {
264
+ id: 'test-id',
265
+ options: undefined,
266
+ chainId: mockChainId,
267
+ },
268
+ };
269
+
270
+ const { result } = renderHook(() =>
271
+ useAutoSelectFeeOption(argsWithNoOptions),
272
+ );
273
+
274
+ // Wait for the hook to complete
275
+ await waitFor(async () => {
276
+ const response = await result.current;
277
+ expect(response.error).toBe('No options provided');
278
+ });
279
+
280
+ // Verify final state
281
+ const finalResponse = await result.current;
282
+ expect(finalResponse).toEqual({
283
+ selectedOption: null,
284
+ error: 'No options provided',
285
+ });
286
+ });
287
+
288
+ it('should return FailedToCheckBalances error when balance checking fails', async () => {
289
+ // Override handler to simulate API error
290
+ server.use(
291
+ http.post(mockIndexerEndpoint('GetTokenBalancesDetails'), () => {
292
+ return new HttpResponse(null, {
293
+ status: 500,
294
+ statusText: 'Internal Server Error',
295
+ });
296
+ }),
297
+ );
298
+
299
+ const { result } = renderHook(() => useAutoSelectFeeOption(defaultArgs));
300
+
301
+ // Wait for the hook to complete
302
+ await waitFor(async () => {
303
+ const response = await result.current;
304
+ expect(response.error).toBe('Failed to check balances');
305
+ });
306
+
307
+ // Verify final state
308
+ const finalResponse = await result.current;
309
+ expect(finalResponse).toEqual({
310
+ selectedOption: null,
311
+ error: 'Failed to check balances',
312
+ });
313
+ });
314
+ });
@@ -0,0 +1,148 @@
1
+ import { describe, expect, it, beforeEach, vi } from 'vitest';
2
+ import { renderHook, waitFor } from '../../_internal/test-utils';
3
+ import { useBalanceOfCollectible } from '../useBalanceOfCollectible';
4
+ import {
5
+ mockTokenBalance,
6
+ enableDebug,
7
+ } from '../../_internal/api/__mocks__/indexer.msw';
8
+ import { zeroAddress } from 'viem';
9
+ import { server } from '../../_internal/test/setup';
10
+ import { http, HttpResponse } from 'msw';
11
+ import { mockIndexerEndpoint } from '../../_internal/api/__mocks__/indexer.msw';
12
+
13
+ describe('useBalanceOfCollectible', () => {
14
+ beforeEach(() => {
15
+ vi.clearAllMocks();
16
+ enableDebug();
17
+ });
18
+
19
+ const defaultArgs = {
20
+ collectionAddress: zeroAddress,
21
+ collectableId: '1',
22
+ userAddress: '0x1234567890123456789012345678901234567890' as `0x${string}`,
23
+ chainId: 1,
24
+ };
25
+
26
+ it('should fetch balance successfully', async () => {
27
+ // Override the handler specifically for this test
28
+ server.use(
29
+ http.post(mockIndexerEndpoint('GetTokenBalances'), () => {
30
+ return HttpResponse.json({
31
+ page: { page: 1, pageSize: 10, more: false },
32
+ balances: [mockTokenBalance],
33
+ });
34
+ }),
35
+ );
36
+
37
+ const { result } = renderHook(() => useBalanceOfCollectible(defaultArgs));
38
+
39
+ // Initially loading
40
+ expect(result.current.isLoading).toBe(true);
41
+
42
+ // Wait for the query to complete
43
+ await waitFor(() => {
44
+ expect(result.current.isSuccess).toBe(true);
45
+ });
46
+
47
+ // Check the returned data matches mock
48
+ expect(result.current.data).toEqual(mockTokenBalance);
49
+ });
50
+
51
+ it('should return null when userAddress is undefined', () => {
52
+ const { result } = renderHook(() =>
53
+ useBalanceOfCollectible({
54
+ ...defaultArgs,
55
+ userAddress: undefined,
56
+ }),
57
+ );
58
+
59
+ expect(result.current.data).toBeUndefined();
60
+ expect(result.current.isLoading).toBe(false);
61
+ });
62
+
63
+ it('should respect enabled option in query config', () => {
64
+ const { result } = renderHook(() =>
65
+ useBalanceOfCollectible({
66
+ ...defaultArgs,
67
+ query: {
68
+ enabled: false,
69
+ },
70
+ }),
71
+ );
72
+
73
+ expect(result.current.isLoading).toBe(false);
74
+ expect(result.current.data).toBeUndefined();
75
+ });
76
+
77
+ it('should handle error states', async () => {
78
+ // Override the handler to return an error
79
+ server.use(
80
+ http.post(mockIndexerEndpoint('GetTokenBalances'), () => {
81
+ return HttpResponse.json(
82
+ { error: { message: 'Invalid address format' } },
83
+ { status: 400 },
84
+ );
85
+ }),
86
+ );
87
+
88
+ const invalidArgs = {
89
+ ...defaultArgs,
90
+ collectionAddress: '0xinvalid' as `0x${string}`, // Invalid address format
91
+ };
92
+
93
+ const { result } = renderHook(() => useBalanceOfCollectible(invalidArgs));
94
+
95
+ await waitFor(() => {
96
+ expect(result.current.isError).toBe(true);
97
+ });
98
+ });
99
+
100
+ it('should return correct balance for specific collectible', async () => {
101
+ const specificCollectible = {
102
+ collectionAddress:
103
+ '0x1234567890123456789012345678901234567890' as `0x${string}`,
104
+ collectableId: '42',
105
+ userAddress:
106
+ '0xabcdef1234567890abcdef1234567890abcdef12' as `0x${string}`,
107
+ chainId: 1,
108
+ };
109
+
110
+ const specificBalance = {
111
+ ...mockTokenBalance,
112
+ contractAddress: specificCollectible.collectionAddress,
113
+ accountAddress: specificCollectible.userAddress,
114
+ tokenID: specificCollectible.collectableId,
115
+ balance: '2', // User owns 2 of this collectible
116
+ };
117
+
118
+ server.use(
119
+ http.post(mockIndexerEndpoint('GetTokenBalances'), () => {
120
+ return HttpResponse.json({
121
+ page: { page: 1, pageSize: 10, more: false },
122
+ balances: [specificBalance],
123
+ });
124
+ }),
125
+ );
126
+
127
+ const { result } = renderHook(() =>
128
+ useBalanceOfCollectible(specificCollectible),
129
+ );
130
+
131
+ await waitFor(() => {
132
+ expect(result.current.isSuccess).toBe(true);
133
+ });
134
+
135
+ // Verify the specific collectible balance
136
+ expect(result.current.data).toEqual(specificBalance);
137
+ expect(result.current.data?.balance).toBe('2');
138
+ expect(result.current.data?.contractAddress).toBe(
139
+ specificCollectible.collectionAddress,
140
+ );
141
+ expect(result.current.data?.tokenID).toBe(
142
+ specificCollectible.collectableId,
143
+ );
144
+ expect(result.current.data?.accountAddress).toBe(
145
+ specificCollectible.userAddress,
146
+ );
147
+ });
148
+ });