@0xsequence/marketplace-sdk 0.4.8 → 0.5.0

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 (116) hide show
  1. package/dist/{chunk-2OJB35FS.js → chunk-5NORRVPM.js} +5 -5
  2. package/dist/{chunk-2OJB35FS.js.map → chunk-5NORRVPM.js.map} +1 -1
  3. package/dist/{chunk-ATDCYXXV.js → chunk-6YHHCGGY.js} +2 -2
  4. package/dist/{chunk-WRMJ5FZM.js → chunk-HV2X2VZN.js} +874 -194
  5. package/dist/chunk-HV2X2VZN.js.map +1 -0
  6. package/dist/{chunk-AQT3BQ67.js → chunk-J2XJZ6SJ.js} +12 -5
  7. package/dist/chunk-J2XJZ6SJ.js.map +1 -0
  8. package/dist/{chunk-JEOUQFT3.js → chunk-LJAB3S6U.js} +4 -3
  9. package/dist/chunk-LJAB3S6U.js.map +1 -0
  10. package/dist/{chunk-7WCZP6FN.js → chunk-OUVFTA63.js} +649 -386
  11. package/dist/chunk-OUVFTA63.js.map +1 -0
  12. package/dist/{chunk-XXML5K3X.js → chunk-QTJF5GDQ.js} +2 -2
  13. package/dist/{chunk-LF44FCG5.js → chunk-TQWM4ER6.js} +2 -2
  14. package/dist/{chunk-LF44FCG5.js.map → chunk-TQWM4ER6.js.map} +1 -1
  15. package/dist/{chunk-6R4G7J6Q.js → chunk-WSCUPAGR.js} +33 -5
  16. package/dist/chunk-WSCUPAGR.js.map +1 -0
  17. package/dist/{create-config-D5WqfUft.d.ts → create-config-BXvwUh55.d.ts} +2 -2
  18. package/dist/index.css +31 -17
  19. package/dist/index.d.ts +3 -3
  20. package/dist/index.js +1 -1
  21. package/dist/{marketplace-config-C_fDWzz0.d.ts → marketplace-config-znEu4L0K.d.ts} +1 -1
  22. package/dist/{marketplace.gen-B8S8fflj.d.ts → marketplace.gen-CCJ-URn2.d.ts} +16 -4
  23. package/dist/react/_internal/api/index.d.ts +3 -2
  24. package/dist/react/_internal/api/index.js +3 -1
  25. package/dist/react/_internal/index.d.ts +5 -5
  26. package/dist/react/_internal/index.js +3 -1
  27. package/dist/react/_internal/wagmi/index.d.ts +3 -3
  28. package/dist/react/hooks/index.d.ts +249 -74
  29. package/dist/react/hooks/index.js +18 -5
  30. package/dist/react/index.css +37 -17
  31. package/dist/react/index.css.map +1 -1
  32. package/dist/react/index.d.ts +6 -6
  33. package/dist/react/index.js +22 -9
  34. package/dist/react/ssr/index.js +4 -0
  35. package/dist/react/ssr/index.js.map +1 -1
  36. package/dist/react/ui/components/collectible-card/index.css +37 -17
  37. package/dist/react/ui/components/collectible-card/index.css.map +1 -1
  38. package/dist/react/ui/components/collectible-card/index.d.ts +27 -4
  39. package/dist/react/ui/components/collectible-card/index.js +8 -9
  40. package/dist/react/ui/icons/index.js +3 -3
  41. package/dist/react/ui/index.css +37 -17
  42. package/dist/react/ui/index.css.map +1 -1
  43. package/dist/react/ui/index.d.ts +3 -3
  44. package/dist/react/ui/index.js +8 -9
  45. package/dist/react/ui/modals/_internal/components/actionModal/index.d.ts +3 -3
  46. package/dist/react/ui/modals/_internal/components/actionModal/index.js +5 -5
  47. package/dist/{sdk-config-BXVH8PS2.d.ts → sdk-config-B32_2bG3.d.ts} +29 -7
  48. package/dist/{services-CdXAIjt1.d.ts → services-BRBVE0mm.d.ts} +1 -1
  49. package/dist/styles/index.css +31 -17
  50. package/dist/styles/index.css.map +1 -1
  51. package/dist/styles/index.d.ts +2 -2
  52. package/dist/styles/index.js +2 -2
  53. package/dist/types/index.d.ts +3 -3
  54. package/dist/types/index.js +1 -1
  55. package/dist/{types-eX4P9xju.d.ts → types-Yto6KrTN.d.ts} +2 -2
  56. package/dist/utils/index.d.ts +3 -3
  57. package/dist/utils/index.js +1 -1
  58. package/package.json +16 -16
  59. package/src/react/_internal/api/__mocks__/marketplace.msw.ts +4 -0
  60. package/src/react/_internal/api/marketplace.gen.ts +45 -7
  61. package/src/react/_internal/api/query-keys.ts +4 -0
  62. package/src/react/_internal/wallet/useWallet.ts +30 -46
  63. package/src/react/_internal/wallet/wallet.ts +52 -6
  64. package/src/react/hooks/index.ts +4 -0
  65. package/src/react/hooks/options/__mocks__/marketplaceConfig.msw.ts +10 -1
  66. package/src/react/hooks/useAutoSelectFeeOption.tsx +104 -0
  67. package/src/react/hooks/useCancelOrder.tsx +57 -1
  68. package/src/react/hooks/useCollectionBalanceDetails.tsx +87 -0
  69. package/src/react/hooks/useCollectionDetails.tsx +35 -0
  70. package/src/react/hooks/useCollectionDetailsPolling.tsx +60 -0
  71. package/src/react/ui/components/_internals/action-button/ActionButton.tsx +36 -118
  72. package/src/react/ui/components/_internals/action-button/components/ActionButtonBody.tsx +52 -0
  73. package/src/react/ui/components/_internals/action-button/components/NonOwnerActions.tsx +72 -0
  74. package/src/react/ui/components/_internals/action-button/components/OwnerActions.tsx +81 -0
  75. package/src/react/ui/components/_internals/action-button/hooks/useActionButtonLogic.ts +93 -0
  76. package/src/react/ui/components/_internals/action-button/store.ts +47 -0
  77. package/src/react/ui/components/_internals/action-button/styles.css.ts +8 -0
  78. package/src/react/ui/components/collectible-card/CollectibleCard.tsx +35 -18
  79. package/src/react/ui/components/collectible-card/Footer.tsx +5 -8
  80. package/src/react/ui/components/collectible-card/styles.css.ts +44 -31
  81. package/src/react/ui/icons/CartIcon.tsx +46 -0
  82. package/src/react/ui/modals/BuyModal/Modal.tsx +0 -2
  83. package/src/react/ui/modals/BuyModal/__tests__/Modal.test.tsx +253 -0
  84. package/src/react/ui/modals/BuyModal/__tests__/store.test.ts +100 -0
  85. package/src/react/ui/modals/BuyModal/hooks/__tests__/useBuyCollectable.test.tsx +402 -0
  86. package/src/react/ui/modals/BuyModal/hooks/__tests__/useCheckoutOptions.test.tsx +267 -0
  87. package/src/react/ui/modals/BuyModal/hooks/__tests__/useFees.test.tsx +166 -0
  88. package/src/react/ui/modals/BuyModal/hooks/__tests__/useLoadData.test.tsx +209 -0
  89. package/src/react/ui/modals/BuyModal/hooks/useBuyCollectable.ts +7 -4
  90. package/src/react/ui/modals/BuyModal/hooks/useCheckoutOptions.ts +19 -17
  91. package/src/react/ui/modals/BuyModal/hooks/useLoadData.ts +9 -7
  92. package/src/react/ui/modals/BuyModal/modals/Modal1155.tsx +36 -18
  93. package/src/react/ui/modals/BuyModal/modals/__tests__/CheckoutModal.test.tsx +162 -0
  94. package/src/react/ui/modals/BuyModal/modals/__tests__/Modal1155.test.tsx +243 -0
  95. package/src/react/ui/modals/BuyModal/store.ts +11 -10
  96. package/src/react/ui/modals/CreateListingModal/Modal.tsx +26 -3
  97. package/src/react/ui/modals/CreateListingModal/__tests__/Modal.test.tsx +141 -29
  98. package/src/react/ui/modals/TransferModal/_views/enterWalletAddress/useHandleTransfer.tsx +5 -1
  99. package/src/react/ui/modals/_internal/components/actionModal/ActionModal.tsx +20 -11
  100. package/src/react/ui/modals/_internal/components/currencyOptionsSelect/__tests__/index.test.tsx +13 -58
  101. package/src/react/ui/modals/_internal/components/priceInput/__tests__/index.test.tsx +2 -0
  102. package/src/react/ui/modals/_internal/components/transactionStatusModal/__tests__/TransactionStatusModal.test.tsx +18 -19
  103. package/src/react/ui/modals/_internal/components/transactionStatusModal/__tests__/utils.test.ts +2 -0
  104. package/src/react/ui/modals/_internal/components/transactionStatusModal/hooks/useTransactionStatus.ts +62 -0
  105. package/src/react/ui/modals/_internal/components/transactionStatusModal/index.tsx +53 -100
  106. package/src/react/ui/modals/_internal/components/transactionStatusModal/store.ts +2 -10
  107. package/tsconfig.tsbuildinfo +1 -1
  108. package/dist/chunk-6R4G7J6Q.js.map +0 -1
  109. package/dist/chunk-7WCZP6FN.js.map +0 -1
  110. package/dist/chunk-AQT3BQ67.js.map +0 -1
  111. package/dist/chunk-FWN2MCLI.js +0 -425
  112. package/dist/chunk-FWN2MCLI.js.map +0 -1
  113. package/dist/chunk-JEOUQFT3.js.map +0 -1
  114. package/dist/chunk-WRMJ5FZM.js.map +0 -1
  115. /package/dist/{chunk-ATDCYXXV.js.map → chunk-6YHHCGGY.js.map} +0 -0
  116. /package/dist/{chunk-XXML5K3X.js.map → chunk-QTJF5GDQ.js.map} +0 -0
@@ -0,0 +1,100 @@
1
+ import { describe, it, expect, beforeEach } from 'vitest';
2
+ import { buyModal$, initialState } from '../store';
3
+ import type { Order } from '../../../../_internal';
4
+
5
+ describe('BuyModal Store', () => {
6
+ beforeEach(() => {
7
+ buyModal$.set(initialState);
8
+ });
9
+
10
+ it('should initialize with correct default state', () => {
11
+ expect(buyModal$.isOpen.get()).toBe(false);
12
+ expect(buyModal$.state.get()).toEqual({
13
+ order: undefined as unknown as Order,
14
+ quantity: '1',
15
+ invalidQuantity: false,
16
+ checkoutModalIsLoading: false,
17
+ checkoutModalLoaded: false,
18
+ });
19
+ expect(buyModal$.callbacks.get()).toBeUndefined();
20
+ });
21
+
22
+ it('should handle open action correctly', () => {
23
+ const mockOrder: Order = {
24
+ quantityAvailableFormatted: '10',
25
+ } as Order;
26
+
27
+ const mockCallbacks = {
28
+ onSuccess: () => {},
29
+ onError: () => {},
30
+ };
31
+
32
+ buyModal$.open({
33
+ order: mockOrder,
34
+ chainId: '1',
35
+ collectionAddress: '0x123',
36
+ tokenId: '123',
37
+ callbacks: mockCallbacks,
38
+ });
39
+
40
+ expect(buyModal$.isOpen.get()).toBe(true);
41
+ expect(buyModal$.state.get()).toEqual({
42
+ order: mockOrder,
43
+ quantity: '10',
44
+ invalidQuantity: false,
45
+ checkoutModalIsLoading: false,
46
+ checkoutModalLoaded: false,
47
+ });
48
+ expect(buyModal$.callbacks.get()).toBe(mockCallbacks);
49
+ });
50
+
51
+ it('should handle close action correctly', () => {
52
+ const mockOrder: Order = {
53
+ quantityAvailableFormatted: '10',
54
+ } as Order;
55
+
56
+ buyModal$.open({
57
+ order: mockOrder,
58
+ chainId: '1',
59
+ collectionAddress: '0x123',
60
+ tokenId: '123',
61
+ callbacks: {
62
+ onSuccess: () => {},
63
+ onError: () => {},
64
+ },
65
+ });
66
+
67
+ expect(buyModal$.isOpen.get()).toBe(true);
68
+
69
+ buyModal$.close();
70
+
71
+ expect(buyModal$.isOpen.get()).toBe(false);
72
+ expect(buyModal$.state.get().quantity).toBe('1');
73
+ expect(buyModal$.state.get().invalidQuantity).toBe(false);
74
+ expect(buyModal$.state.get().checkoutModalIsLoading).toBe(false);
75
+ expect(buyModal$.state.get().checkoutModalLoaded).toBe(false);
76
+ expect(buyModal$.callbacks.get()).toBeUndefined();
77
+ expect(buyModal$.state.order.get()).toBeUndefined();
78
+ expect(
79
+ buyModal$.state.order.collectionContractAddress.get(),
80
+ ).toBeUndefined();
81
+ expect(buyModal$.state.order.tokenId.get()).toBeUndefined();
82
+ expect(buyModal$.state.order.chainId.get()).toBeUndefined();
83
+ expect(
84
+ buyModal$.state.order.quantityAvailableFormatted.get(),
85
+ ).toBeUndefined();
86
+ });
87
+
88
+ it('should update loading states correctly', () => {
89
+ buyModal$.state.checkoutModalIsLoading.set(true);
90
+ expect(buyModal$.state.checkoutModalIsLoading.get()).toBe(true);
91
+
92
+ buyModal$.state.checkoutModalLoaded.set(true);
93
+ expect(buyModal$.state.checkoutModalLoaded.get()).toBe(true);
94
+
95
+ buyModal$.state.checkoutModalIsLoading.set(false);
96
+ buyModal$.state.checkoutModalLoaded.set(false);
97
+ expect(buyModal$.state.checkoutModalIsLoading.get()).toBe(false);
98
+ expect(buyModal$.state.checkoutModalLoaded.get()).toBe(false);
99
+ });
100
+ });
@@ -0,0 +1,402 @@
1
+ import { renderHook } from '@testing-library/react';
2
+ import { describe, it, expect, vi, beforeEach } from 'vitest';
3
+ import { useBuyCollectable } from '../useBuyCollectable';
4
+ import { useWallet } from '../../../../../_internal/wallet/useWallet';
5
+ import { useSelectPaymentModal } from '@0xsequence/kit-checkout';
6
+ import { useConfig } from '../../../../../hooks';
7
+ import { useFees } from '../useFees';
8
+ import {
9
+ MarketplaceKind,
10
+ TransactionCrypto,
11
+ WalletKind,
12
+ getMarketplaceClient,
13
+ collectableKeys,
14
+ } from '../../../../../_internal';
15
+
16
+ // Mock dependencies
17
+ vi.mock('@0xsequence/kit-checkout', () => ({
18
+ useSelectPaymentModal: vi.fn(),
19
+ }));
20
+
21
+ vi.mock('../../../../../_internal/wallet/useWallet', () => ({
22
+ useWallet: vi.fn(),
23
+ }));
24
+
25
+ vi.mock('../../../../../hooks', () => ({
26
+ useConfig: vi.fn(),
27
+ }));
28
+
29
+ vi.mock('../useFees', () => ({
30
+ useFees: vi.fn(),
31
+ }));
32
+
33
+ // Mock the buyModal$ store
34
+ const mockClose = vi.fn();
35
+ vi.mock('../store', () => ({
36
+ buyModal$: {
37
+ close: mockClose,
38
+ },
39
+ }));
40
+
41
+ // Mock react-query
42
+ const mockInvalidateQueries = vi.fn();
43
+ vi.mock('@tanstack/react-query', async () => {
44
+ const actual = await vi.importActual('@tanstack/react-query');
45
+ return {
46
+ ...actual,
47
+ getQueryClient: () => ({
48
+ invalidateQueries: mockInvalidateQueries,
49
+ }),
50
+ };
51
+ });
52
+
53
+ vi.mock('../../../../../_internal', async () => {
54
+ const actual = (await vi.importActual('../../../../../_internal')) as Record<
55
+ string,
56
+ unknown
57
+ >;
58
+ return {
59
+ ...actual,
60
+ getMarketplaceClient: vi.fn(() => ({
61
+ generateBuyTransaction: vi.fn().mockResolvedValue({
62
+ steps: [
63
+ {
64
+ type: 'transaction',
65
+ value: '1000000000000000000',
66
+ to: '0x123',
67
+ data: '0x456',
68
+ },
69
+ ],
70
+ }),
71
+ })),
72
+ collectableKeys: {
73
+ listings: ['listings'],
74
+ listingsCount: ['listingsCount'],
75
+ lists: ['lists'],
76
+ userBalances: ['userBalances'],
77
+ },
78
+ balanceQueries: {
79
+ all: ['balances'],
80
+ },
81
+ getQueryClient: () => ({
82
+ invalidateQueries: mockInvalidateQueries,
83
+ }),
84
+ };
85
+ });
86
+
87
+ describe('useBuyCollectable', () => {
88
+ const defaultProps = {
89
+ chainId: '1',
90
+ collectionAddress: '0x123',
91
+ tokenId: '1',
92
+ priceCurrencyAddress: '0x0',
93
+ setCheckoutModalIsLoading: vi.fn(),
94
+ setCheckoutModalLoaded: vi.fn(),
95
+ };
96
+
97
+ beforeEach(() => {
98
+ vi.clearAllMocks();
99
+
100
+ // Setup default mock implementations
101
+ (
102
+ useSelectPaymentModal as unknown as ReturnType<typeof vi.fn>
103
+ ).mockReturnValue({
104
+ openSelectPaymentModal: vi.fn(),
105
+ });
106
+
107
+ (useConfig as unknown as ReturnType<typeof vi.fn>).mockReturnValue({
108
+ projectAccessKey: 'test-key',
109
+ projectId: 'test-id',
110
+ });
111
+
112
+ (useFees as unknown as ReturnType<typeof vi.fn>).mockReturnValue({
113
+ amount: '250',
114
+ receiver: '0x123',
115
+ });
116
+ });
117
+
118
+ it('should return loading state initially', () => {
119
+ // Mock useWallet to return loading state
120
+ (useWallet as unknown as ReturnType<typeof vi.fn>).mockReturnValue({
121
+ wallet: null,
122
+ isLoading: true,
123
+ isError: false,
124
+ });
125
+
126
+ const { result } = renderHook(() => useBuyCollectable(defaultProps));
127
+
128
+ expect(result.current).toEqual({
129
+ status: 'loading',
130
+ buy: null,
131
+ isLoading: true,
132
+ isError: false,
133
+ });
134
+ });
135
+
136
+ it('should return error state when wallet is not available', () => {
137
+ // Mock useWallet to return error state
138
+ (useWallet as unknown as ReturnType<typeof vi.fn>).mockReturnValue({
139
+ wallet: null,
140
+ isLoading: false,
141
+ isError: true,
142
+ });
143
+
144
+ const { result } = renderHook(() => useBuyCollectable(defaultProps));
145
+
146
+ expect(result.current).toEqual({
147
+ status: 'error',
148
+ buy: null,
149
+ isLoading: false,
150
+ isError: true,
151
+ });
152
+
153
+ // Also test when wallet is undefined but no error
154
+ (useWallet as unknown as ReturnType<typeof vi.fn>).mockReturnValue({
155
+ wallet: undefined,
156
+ isLoading: false,
157
+ isError: false,
158
+ });
159
+
160
+ const { result: result2 } = renderHook(() =>
161
+ useBuyCollectable(defaultProps),
162
+ );
163
+
164
+ expect(result2.current).toEqual({
165
+ status: 'error',
166
+ buy: null,
167
+ isLoading: false,
168
+ isError: true,
169
+ });
170
+ });
171
+
172
+ it('should call buy function with correct parameters', async () => {
173
+ // Mock useWallet to return a valid wallet
174
+ (useWallet as unknown as ReturnType<typeof vi.fn>).mockReturnValue({
175
+ wallet: {
176
+ kind: WalletKind.sequence,
177
+ address: async () => '0x123',
178
+ chainId: '1',
179
+ },
180
+ isLoading: false,
181
+ isError: false,
182
+ });
183
+
184
+ const openSelectPaymentModalMock = vi.fn();
185
+ (
186
+ useSelectPaymentModal as unknown as ReturnType<typeof vi.fn>
187
+ ).mockReturnValue({
188
+ openSelectPaymentModal: openSelectPaymentModalMock,
189
+ });
190
+
191
+ const generateBuyTransactionMock = vi.fn().mockResolvedValue({
192
+ steps: [
193
+ {
194
+ type: 'transaction',
195
+ value: '1000000000000000000',
196
+ to: '0x123',
197
+ data: '0x456',
198
+ },
199
+ ],
200
+ });
201
+
202
+ const marketplaceClientMock = {
203
+ generateBuyTransaction: generateBuyTransactionMock,
204
+ };
205
+
206
+ (
207
+ getMarketplaceClient as unknown as ReturnType<typeof vi.fn>
208
+ ).mockReturnValue(marketplaceClientMock);
209
+
210
+ const { result } = renderHook(() => useBuyCollectable(defaultProps));
211
+
212
+ if (result.current.status === 'ready') {
213
+ await result.current.buy({
214
+ orderId: '1',
215
+ quantity: '1',
216
+ collectableDecimals: 18,
217
+ marketplace: MarketplaceKind.sequence_marketplace_v2,
218
+ checkoutOptions: {
219
+ swap: [],
220
+ nftCheckout: [],
221
+ onRamp: [],
222
+ crypto: TransactionCrypto.all,
223
+ },
224
+ });
225
+ }
226
+
227
+ expect(generateBuyTransactionMock).toHaveBeenCalledWith({
228
+ collectionAddress: defaultProps.collectionAddress,
229
+ buyer: '0x123',
230
+ marketplace: MarketplaceKind.sequence_marketplace_v2,
231
+ ordersData: [
232
+ {
233
+ orderId: '1',
234
+ quantity: '1',
235
+ },
236
+ ],
237
+ additionalFees: [
238
+ {
239
+ amount: '250',
240
+ receiver: '0x123',
241
+ },
242
+ ],
243
+ walletType: WalletKind.unknown,
244
+ });
245
+
246
+ expect(openSelectPaymentModalMock).toHaveBeenCalledWith({
247
+ chain: defaultProps.chainId,
248
+ collectibles: [
249
+ {
250
+ tokenId: defaultProps.tokenId,
251
+ quantity: '1',
252
+ decimals: 18,
253
+ },
254
+ ],
255
+ currencyAddress: defaultProps.priceCurrencyAddress,
256
+ price: '1000000000000000000',
257
+ targetContractAddress: '0x123',
258
+ txData: '0x456',
259
+ collectionAddress: defaultProps.collectionAddress,
260
+ recipientAddress: '0x123',
261
+ enableMainCurrencyPayment: true,
262
+ enableSwapPayments: true,
263
+ creditCardProviders: [],
264
+ onSuccess: expect.any(Function),
265
+ onError: undefined,
266
+ onClose: expect.any(Function),
267
+ });
268
+
269
+ expect(defaultProps.setCheckoutModalIsLoading).toHaveBeenCalledWith(true);
270
+ expect(defaultProps.setCheckoutModalLoaded).toHaveBeenCalledWith(true);
271
+ });
272
+
273
+ it('should handle success callback and invalidate queries', async () => {
274
+ (useWallet as unknown as ReturnType<typeof vi.fn>).mockReturnValue({
275
+ wallet: {
276
+ kind: WalletKind.sequence,
277
+ address: async () => '0x123',
278
+ chainId: '1',
279
+ },
280
+ isLoading: false,
281
+ isError: false,
282
+ });
283
+
284
+ const openSelectPaymentModalMock = vi.fn();
285
+ (
286
+ useSelectPaymentModal as unknown as ReturnType<typeof vi.fn>
287
+ ).mockReturnValue({
288
+ openSelectPaymentModal: openSelectPaymentModalMock,
289
+ });
290
+
291
+ const generateBuyTransactionMock = vi.fn().mockResolvedValue({
292
+ steps: [
293
+ {
294
+ type: 'transaction',
295
+ value: '1000000000000000000',
296
+ to: '0x123',
297
+ data: '0x456',
298
+ },
299
+ ],
300
+ });
301
+
302
+ const marketplaceClientMock = {
303
+ generateBuyTransaction: generateBuyTransactionMock,
304
+ };
305
+
306
+ (
307
+ getMarketplaceClient as unknown as ReturnType<typeof vi.fn>
308
+ ).mockReturnValue(marketplaceClientMock);
309
+
310
+ const onSuccessMock = vi.fn();
311
+ const props = {
312
+ ...defaultProps,
313
+ callbacks: {
314
+ onSuccess: onSuccessMock,
315
+ },
316
+ };
317
+
318
+ const { result } = renderHook(() => useBuyCollectable(props));
319
+
320
+ if (result.current.status === 'ready') {
321
+ await result.current.buy({
322
+ orderId: '1',
323
+ quantity: '1',
324
+ collectableDecimals: 18,
325
+ marketplace: MarketplaceKind.sequence_marketplace_v2,
326
+ checkoutOptions: {
327
+ swap: [],
328
+ nftCheckout: [],
329
+ onRamp: [],
330
+ crypto: TransactionCrypto.all,
331
+ },
332
+ });
333
+ }
334
+
335
+ const onSuccessCallback =
336
+ openSelectPaymentModalMock.mock.calls[0][0].onSuccess;
337
+
338
+ const txHash = '0x789';
339
+ await onSuccessCallback(txHash);
340
+
341
+ expect(mockInvalidateQueries).toHaveBeenCalledWith({
342
+ queryKey: collectableKeys.listings,
343
+ });
344
+ expect(mockInvalidateQueries).toHaveBeenCalledWith({
345
+ queryKey: collectableKeys.listingsCount,
346
+ });
347
+
348
+ expect(onSuccessMock).toHaveBeenCalledWith({ hash: txHash });
349
+ });
350
+
351
+ it('should handle error callback', async () => {
352
+ // Mock useWallet to return a valid wallet
353
+ (useWallet as unknown as ReturnType<typeof vi.fn>).mockReturnValue({
354
+ wallet: {
355
+ kind: WalletKind.sequence,
356
+ address: async () => '0x123',
357
+ chainId: '1',
358
+ },
359
+ isLoading: false,
360
+ isError: false,
361
+ });
362
+
363
+ const openSelectPaymentModalMock = vi.fn();
364
+ (
365
+ useSelectPaymentModal as unknown as ReturnType<typeof vi.fn>
366
+ ).mockReturnValue({
367
+ openSelectPaymentModal: openSelectPaymentModalMock,
368
+ });
369
+
370
+ const onErrorMock = vi.fn();
371
+ const props = {
372
+ ...defaultProps,
373
+ callbacks: {
374
+ onError: onErrorMock,
375
+ },
376
+ };
377
+
378
+ const { result } = renderHook(() => useBuyCollectable(props));
379
+
380
+ if (result.current.status === 'ready') {
381
+ await result.current.buy({
382
+ orderId: '1',
383
+ quantity: '1',
384
+ collectableDecimals: 18,
385
+ marketplace: MarketplaceKind.sequence_marketplace_v2,
386
+ checkoutOptions: {
387
+ swap: [],
388
+ nftCheckout: [],
389
+ onRamp: [],
390
+ crypto: TransactionCrypto.all,
391
+ },
392
+ });
393
+ }
394
+
395
+ const onErrorCallback = openSelectPaymentModalMock.mock.calls[0][0].onError;
396
+
397
+ const error = new Error('Transaction failed');
398
+ onErrorCallback(error);
399
+
400
+ expect(onErrorMock).toHaveBeenCalledWith(error);
401
+ });
402
+ });