@0xsequence/marketplace-sdk 0.4.7 → 0.4.9
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.
- package/dist/{chunk-6R4G7J6Q.js → chunk-7HWJ4DUX.js} +29 -5
- package/dist/chunk-7HWJ4DUX.js.map +1 -0
- package/dist/{chunk-5UCKYAMR.js → chunk-BJLOO4NP.js} +647 -376
- package/dist/chunk-BJLOO4NP.js.map +1 -0
- package/dist/{chunk-2OJB35FS.js → chunk-BMWCIHCB.js} +5 -5
- package/dist/{chunk-2OJB35FS.js.map → chunk-BMWCIHCB.js.map} +1 -1
- package/dist/{chunk-R7GVMKMM.js → chunk-CUA4SGWT.js} +540 -18
- package/dist/chunk-CUA4SGWT.js.map +1 -0
- package/dist/{chunk-ZEH4JI2U.js → chunk-FCF57DZI.js} +7 -2
- package/dist/chunk-FCF57DZI.js.map +1 -0
- package/dist/{chunk-JEOUQFT3.js → chunk-TFCSNRD5.js} +4 -3
- package/dist/chunk-TFCSNRD5.js.map +1 -0
- package/dist/{chunk-AQT3BQ67.js → chunk-Y3KINNAU.js} +12 -5
- package/dist/chunk-Y3KINNAU.js.map +1 -0
- package/dist/{create-config-D5WqfUft.d.ts → create-config-CgYQDyMD.d.ts} +2 -2
- package/dist/index.css +31 -17
- package/dist/index.d.ts +3 -3
- package/dist/index.js +3 -3
- package/dist/{marketplace-config-C_fDWzz0.d.ts → marketplace-config-BP5-XnFG.d.ts} +1 -1
- package/dist/{marketplace.gen-B8S8fflj.d.ts → marketplace.gen-BzmWLP9L.d.ts} +14 -4
- package/dist/react/_internal/api/index.d.ts +2 -2
- package/dist/react/_internal/api/index.js +3 -1
- package/dist/react/_internal/index.d.ts +5 -5
- package/dist/react/_internal/index.js +4 -2
- package/dist/react/_internal/wagmi/index.d.ts +3 -3
- package/dist/react/_internal/wagmi/index.js +1 -1
- package/dist/react/hooks/index.d.ts +46 -5
- package/dist/react/hooks/index.js +12 -5
- package/dist/react/index.css +37 -17
- package/dist/react/index.css.map +1 -1
- package/dist/react/index.d.ts +6 -6
- package/dist/react/index.js +15 -8
- package/dist/react/ssr/index.js +6 -1
- package/dist/react/ssr/index.js.map +1 -1
- package/dist/react/ui/components/collectible-card/index.css +37 -17
- package/dist/react/ui/components/collectible-card/index.css.map +1 -1
- package/dist/react/ui/components/collectible-card/index.d.ts +27 -4
- package/dist/react/ui/components/collectible-card/index.js +7 -8
- package/dist/react/ui/index.css +37 -17
- package/dist/react/ui/index.css.map +1 -1
- package/dist/react/ui/index.d.ts +3 -3
- package/dist/react/ui/index.js +7 -8
- package/dist/react/ui/modals/_internal/components/actionModal/index.d.ts +3 -3
- package/dist/react/ui/modals/_internal/components/actionModal/index.js +5 -5
- package/dist/{sdk-config-BXVH8PS2.d.ts → sdk-config-LbbmA85k.d.ts} +27 -7
- package/dist/{services-CdXAIjt1.d.ts → services-DW26ougH.d.ts} +1 -1
- package/dist/styles/index.css +31 -17
- package/dist/styles/index.css.map +1 -1
- package/dist/styles/index.d.ts +2 -2
- package/dist/styles/index.js +1 -1
- package/dist/types/index.d.ts +3 -3
- package/dist/types/index.js +2 -2
- package/dist/{types-eX4P9xju.d.ts → types-DhTZWw1U.d.ts} +2 -2
- package/dist/utils/index.d.ts +3 -3
- package/dist/utils/index.js +3 -3
- package/package.json +3 -2
- package/src/react/__tests__/provider.test.tsx +75 -0
- package/src/react/_internal/api/__mocks__/marketplace.msw.ts +4 -0
- package/src/react/_internal/api/marketplace.gen.ts +42 -7
- package/src/react/_internal/wagmi/__tests__/create-config.test.ts +196 -0
- package/src/react/_internal/wagmi/create-config.ts +9 -1
- package/src/react/_internal/wallet/useWallet.ts +30 -46
- package/src/react/_internal/wallet/wallet.ts +52 -6
- package/src/react/hooks/index.ts +2 -0
- package/src/react/hooks/options/__mocks__/marketplaceConfig.msw.ts +10 -1
- package/src/react/hooks/useCollectionDetails.tsx +35 -0
- package/src/react/hooks/useCollectionDetailsPolling.tsx +60 -0
- package/src/react/provider.tsx +5 -0
- package/src/react/ui/components/_internals/action-button/ActionButton.tsx +36 -118
- package/src/react/ui/components/_internals/action-button/components/ActionButtonBody.tsx +52 -0
- package/src/react/ui/components/_internals/action-button/components/NonOwnerActions.tsx +72 -0
- package/src/react/ui/components/_internals/action-button/components/OwnerActions.tsx +81 -0
- package/src/react/ui/components/_internals/action-button/hooks/useActionButtonLogic.ts +93 -0
- package/src/react/ui/components/_internals/action-button/store.ts +47 -0
- package/src/react/ui/components/_internals/action-button/styles.css.ts +8 -0
- package/src/react/ui/components/collectible-card/CollectibleCard.tsx +34 -14
- package/src/react/ui/components/collectible-card/Footer.tsx +9 -9
- package/src/react/ui/components/collectible-card/styles.css.ts +44 -31
- package/src/react/ui/icons/CartIcon.tsx +46 -0
- package/src/react/ui/modals/BuyModal/Modal.tsx +11 -4
- package/src/react/ui/modals/BuyModal/__tests__/Modal.test.tsx +253 -0
- package/src/react/ui/modals/BuyModal/__tests__/store.test.ts +100 -0
- package/src/react/ui/modals/BuyModal/hooks/__tests__/useBuyCollectable.test.tsx +402 -0
- package/src/react/ui/modals/BuyModal/hooks/__tests__/useCheckoutOptions.test.tsx +267 -0
- package/src/react/ui/modals/BuyModal/hooks/__tests__/useFees.test.tsx +166 -0
- package/src/react/ui/modals/BuyModal/hooks/__tests__/useLoadData.test.tsx +209 -0
- package/src/react/ui/modals/BuyModal/hooks/useCheckoutOptions.ts +19 -17
- package/src/react/ui/modals/BuyModal/hooks/useLoadData.ts +9 -7
- package/src/react/ui/modals/BuyModal/modals/CheckoutModal.tsx +7 -0
- package/src/react/ui/modals/BuyModal/modals/Modal1155.tsx +36 -18
- package/src/react/ui/modals/BuyModal/modals/__tests__/CheckoutModal.test.tsx +162 -0
- package/src/react/ui/modals/BuyModal/modals/__tests__/Modal1155.test.tsx +243 -0
- package/src/react/ui/modals/BuyModal/store.ts +11 -10
- package/src/react/ui/modals/CreateListingModal/Modal.tsx +26 -3
- package/src/react/ui/modals/CreateListingModal/__tests__/Modal.test.tsx +141 -29
- package/src/react/ui/modals/SuccessfulPurchaseModal/__tests__/Modal.test.tsx +145 -0
- package/src/react/ui/modals/_internal/components/actionModal/ActionModal.tsx +20 -11
- package/src/react/ui/modals/_internal/components/currencyOptionsSelect/__tests__/index.test.tsx +13 -58
- package/src/react/ui/modals/_internal/components/priceInput/__tests__/index.test.tsx +2 -0
- package/src/react/ui/modals/_internal/components/transactionStatusModal/__tests__/TransactionStatusModal.test.tsx +18 -19
- package/src/react/ui/modals/_internal/components/transactionStatusModal/__tests__/utils.test.ts +2 -0
- package/src/react/ui/modals/_internal/components/transactionStatusModal/hooks/useTransactionStatus.ts +62 -0
- package/src/react/ui/modals/_internal/components/transactionStatusModal/index.tsx +53 -100
- package/src/react/ui/modals/_internal/components/transactionStatusModal/store.ts +2 -10
- package/src/utils/_internal/error/config.ts +16 -0
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/chunk-5UCKYAMR.js.map +0 -1
- package/dist/chunk-6R4G7J6Q.js.map +0 -1
- package/dist/chunk-AQT3BQ67.js.map +0 -1
- package/dist/chunk-FWN2MCLI.js +0 -425
- package/dist/chunk-FWN2MCLI.js.map +0 -1
- package/dist/chunk-JEOUQFT3.js.map +0 -1
- package/dist/chunk-R7GVMKMM.js.map +0 -1
- package/dist/chunk-ZEH4JI2U.js.map +0 -1
|
@@ -13,6 +13,8 @@ import {
|
|
|
13
13
|
useCollectible,
|
|
14
14
|
useCollection,
|
|
15
15
|
useBalanceOfCollectible,
|
|
16
|
+
useCurrencies,
|
|
17
|
+
useCurrencyOptions,
|
|
16
18
|
} from '../../../../hooks';
|
|
17
19
|
import { useCreateListing } from '../hooks/useCreateListing';
|
|
18
20
|
import { useWallet } from '../../../../_internal/wallet/useWallet';
|
|
@@ -27,6 +29,11 @@ vi.mock('../../../../hooks', () => ({
|
|
|
27
29
|
isLoading: false,
|
|
28
30
|
isError: false,
|
|
29
31
|
}),
|
|
32
|
+
useCurrencyOptions: vi.fn().mockReturnValue({
|
|
33
|
+
data: ['0x123'],
|
|
34
|
+
isLoading: false,
|
|
35
|
+
isError: false,
|
|
36
|
+
}),
|
|
30
37
|
useMarketplaceConfig: vi.fn().mockReturnValue({
|
|
31
38
|
data: {
|
|
32
39
|
collections: [
|
|
@@ -107,39 +114,29 @@ describe('CreateListingModal', () => {
|
|
|
107
114
|
expect(screen.queryByText('List item for sale')).toBeNull();
|
|
108
115
|
});
|
|
109
116
|
|
|
110
|
-
it('should render
|
|
117
|
+
it('should render main form when data is loaded', () => {
|
|
118
|
+
// Mock successful states for all required hooks
|
|
111
119
|
(useCollectible as any).mockReturnValue({
|
|
112
|
-
|
|
120
|
+
data: { decimals: 18, name: 'Test NFT' },
|
|
121
|
+
isLoading: false,
|
|
122
|
+
isError: false,
|
|
113
123
|
});
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
collectibleId: '1',
|
|
124
|
+
(useCollection as any).mockReturnValue({
|
|
125
|
+
data: { type: 'ERC721', name: 'Test Collection' },
|
|
126
|
+
isLoading: false,
|
|
127
|
+
isError: false,
|
|
119
128
|
});
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
});
|
|
125
|
-
|
|
126
|
-
it('should render error state', () => {
|
|
127
|
-
(useCollectible as any).mockReturnValue({
|
|
128
|
-
isError: true,
|
|
129
|
+
(useCurrencyOptions as any).mockReturnValue({
|
|
130
|
+
data: ['0x123'],
|
|
131
|
+
isLoading: false,
|
|
132
|
+
isError: false,
|
|
129
133
|
});
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
collectibleId: '1',
|
|
134
|
+
(useCurrencies as any).mockReturnValue({
|
|
135
|
+
data: [{ address: '0x123', symbol: 'TEST', decimals: 18 }],
|
|
136
|
+
isLoading: false,
|
|
137
|
+
isError: false,
|
|
135
138
|
});
|
|
136
139
|
|
|
137
|
-
render(<CreateListingModal />);
|
|
138
|
-
const errorModal = screen.getByTestId('error-modal');
|
|
139
|
-
expect(errorModal).toBeVisible();
|
|
140
|
-
});
|
|
141
|
-
|
|
142
|
-
it('should render main form when data is loaded', () => {
|
|
143
140
|
createListingModal$.open({
|
|
144
141
|
collectionAddress: '0x123',
|
|
145
142
|
chainId: '1',
|
|
@@ -148,6 +145,9 @@ describe('CreateListingModal', () => {
|
|
|
148
145
|
|
|
149
146
|
render(<CreateListingModal />);
|
|
150
147
|
|
|
148
|
+
// Check for the modal title using a more specific selector
|
|
149
|
+
expect(screen.getByRole('dialog')).toBeInTheDocument();
|
|
150
|
+
// Check for the collection name in the token preview
|
|
151
151
|
expect(screen.getByText('Test Collection')).toBeInTheDocument();
|
|
152
152
|
});
|
|
153
153
|
|
|
@@ -183,6 +183,28 @@ describe('CreateListingModal', () => {
|
|
|
183
183
|
});
|
|
184
184
|
|
|
185
185
|
it('should update state based on price input', async () => {
|
|
186
|
+
// Mock successful states for all required hooks
|
|
187
|
+
(useCollectible as any).mockReturnValue({
|
|
188
|
+
data: { decimals: 18, name: 'Test NFT' },
|
|
189
|
+
isLoading: false,
|
|
190
|
+
isError: false,
|
|
191
|
+
});
|
|
192
|
+
(useCollection as any).mockReturnValue({
|
|
193
|
+
data: { type: 'ERC721', name: 'Test Collection' },
|
|
194
|
+
isLoading: false,
|
|
195
|
+
isError: false,
|
|
196
|
+
});
|
|
197
|
+
(useCurrencyOptions as any).mockReturnValue({
|
|
198
|
+
data: ['0x123'],
|
|
199
|
+
isLoading: false,
|
|
200
|
+
isError: false,
|
|
201
|
+
});
|
|
202
|
+
(useCurrencies as any).mockReturnValue({
|
|
203
|
+
data: [{ address: '0x123', symbol: 'TEST', decimals: 18 }],
|
|
204
|
+
isLoading: false,
|
|
205
|
+
isError: false,
|
|
206
|
+
});
|
|
207
|
+
|
|
186
208
|
createListingModal$.open({
|
|
187
209
|
collectionAddress: '0x123',
|
|
188
210
|
chainId: '1',
|
|
@@ -194,8 +216,8 @@ describe('CreateListingModal', () => {
|
|
|
194
216
|
// Initial price should be 0
|
|
195
217
|
expect(createListingModal$.listingPrice.amountRaw.get()).toBe('0');
|
|
196
218
|
|
|
197
|
-
// Find and interact with price input
|
|
198
|
-
const priceInput = screen.getByRole('textbox', { name:
|
|
219
|
+
// Find and interact with price input using id
|
|
220
|
+
const priceInput = screen.getByRole('textbox', { name: /enter price/i });
|
|
199
221
|
expect(priceInput).toBeInTheDocument();
|
|
200
222
|
|
|
201
223
|
fireEvent.change(priceInput, { target: { value: '1.5' } });
|
|
@@ -205,4 +227,94 @@ describe('CreateListingModal', () => {
|
|
|
205
227
|
expect(createListingModal$.listingPrice.amountRaw.get()).not.toBe('0');
|
|
206
228
|
});
|
|
207
229
|
});
|
|
230
|
+
|
|
231
|
+
it('should show loading modal when data is being fetched', () => {
|
|
232
|
+
// Mock loading states for all required hooks
|
|
233
|
+
(useCollectible as any).mockReturnValue({
|
|
234
|
+
isLoading: true,
|
|
235
|
+
isError: false,
|
|
236
|
+
});
|
|
237
|
+
(useCollection as any).mockReturnValue({
|
|
238
|
+
isLoading: true,
|
|
239
|
+
isError: false,
|
|
240
|
+
});
|
|
241
|
+
(useCurrencyOptions as any).mockReturnValue({
|
|
242
|
+
isLoading: true,
|
|
243
|
+
isError: false,
|
|
244
|
+
});
|
|
245
|
+
|
|
246
|
+
createListingModal$.open({
|
|
247
|
+
collectionAddress: '0x123',
|
|
248
|
+
chainId: '1',
|
|
249
|
+
collectibleId: '1',
|
|
250
|
+
});
|
|
251
|
+
|
|
252
|
+
render(<CreateListingModal />);
|
|
253
|
+
|
|
254
|
+
expect(screen.getByTestId('loading-modal')).toBeInTheDocument();
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('should show error modal when there is an error fetching data', () => {
|
|
258
|
+
// Mock error states for required hooks
|
|
259
|
+
(useCollectible as any).mockReturnValue({
|
|
260
|
+
isLoading: false,
|
|
261
|
+
isError: true,
|
|
262
|
+
});
|
|
263
|
+
(useCollection as any).mockReturnValue({
|
|
264
|
+
isLoading: false,
|
|
265
|
+
isError: false,
|
|
266
|
+
});
|
|
267
|
+
(useCurrencyOptions as any).mockReturnValue({
|
|
268
|
+
isLoading: false,
|
|
269
|
+
isError: false,
|
|
270
|
+
});
|
|
271
|
+
|
|
272
|
+
createListingModal$.open({
|
|
273
|
+
collectionAddress: '0x123',
|
|
274
|
+
chainId: '1',
|
|
275
|
+
collectibleId: '1',
|
|
276
|
+
});
|
|
277
|
+
|
|
278
|
+
render(<CreateListingModal />);
|
|
279
|
+
|
|
280
|
+
expect(screen.getByText('Error loading item details')).toBeInTheDocument();
|
|
281
|
+
});
|
|
282
|
+
|
|
283
|
+
it('should show no ERC20 configured modal when currencies array is empty', () => {
|
|
284
|
+
// Reset all hooks to success state
|
|
285
|
+
(useCollectible as any).mockReturnValue({
|
|
286
|
+
data: { decimals: 18, name: 'Test NFT' },
|
|
287
|
+
isLoading: false,
|
|
288
|
+
isError: false,
|
|
289
|
+
});
|
|
290
|
+
(useCollection as any).mockReturnValue({
|
|
291
|
+
data: { type: 'ERC721', name: 'Test Collection' },
|
|
292
|
+
isLoading: false,
|
|
293
|
+
isError: false,
|
|
294
|
+
});
|
|
295
|
+
(useCurrencyOptions as any).mockReturnValue({
|
|
296
|
+
data: [],
|
|
297
|
+
isLoading: false,
|
|
298
|
+
isError: false,
|
|
299
|
+
});
|
|
300
|
+
(useCurrencies as any).mockReturnValue({
|
|
301
|
+
data: [],
|
|
302
|
+
isLoading: false,
|
|
303
|
+
isError: false,
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
createListingModal$.open({
|
|
307
|
+
collectionAddress: '0x123',
|
|
308
|
+
chainId: '1',
|
|
309
|
+
collectibleId: '1',
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
render(<CreateListingModal />);
|
|
313
|
+
|
|
314
|
+
expect(
|
|
315
|
+
screen.getByText(
|
|
316
|
+
'No currencies are configured for the marketplace, contact the marketplace owners',
|
|
317
|
+
),
|
|
318
|
+
).toBeInTheDocument();
|
|
319
|
+
});
|
|
208
320
|
});
|
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import '@testing-library/jest-dom/vitest';
|
|
2
|
+
import { render, screen, cleanup } from '../../../../_internal/test-utils';
|
|
3
|
+
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
4
|
+
import SuccessfulPurchaseModal, { useSuccessfulPurchaseModal } from '..';
|
|
5
|
+
import { successfulPurchaseModal$ } from '../_store';
|
|
6
|
+
import type { ModalCallbacks } from '../../_internal/types';
|
|
7
|
+
|
|
8
|
+
describe('SuccessfulPurchaseModal', () => {
|
|
9
|
+
beforeEach(() => {
|
|
10
|
+
cleanup();
|
|
11
|
+
vi.clearAllMocks();
|
|
12
|
+
});
|
|
13
|
+
|
|
14
|
+
it('should not render when modal is closed', () => {
|
|
15
|
+
render(<SuccessfulPurchaseModal />);
|
|
16
|
+
expect(screen.queryByText('Successful purchase!')).toBeNull();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('should render with purchase details when opened', () => {
|
|
20
|
+
const mockPurchaseData = {
|
|
21
|
+
collectibles: [
|
|
22
|
+
{
|
|
23
|
+
tokenId: '1',
|
|
24
|
+
name: 'Test NFT',
|
|
25
|
+
image: 'https://test.com/image.png',
|
|
26
|
+
attributes: [],
|
|
27
|
+
},
|
|
28
|
+
],
|
|
29
|
+
totalPrice: '1.5 ETH',
|
|
30
|
+
explorerUrl: 'https://etherscan.io/tx/123',
|
|
31
|
+
explorerName: 'Etherscan',
|
|
32
|
+
};
|
|
33
|
+
|
|
34
|
+
successfulPurchaseModal$.open(mockPurchaseData);
|
|
35
|
+
render(<SuccessfulPurchaseModal />);
|
|
36
|
+
|
|
37
|
+
expect(screen.getByText('Successful purchase!')).toBeInTheDocument();
|
|
38
|
+
expect(screen.getByText('1.5 ETH')).toBeInTheDocument();
|
|
39
|
+
expect(screen.getByText('1')).toBeInTheDocument(); // Number of items
|
|
40
|
+
expect(screen.getByText('View on Etherscan')).toBeInTheDocument();
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('should render CTA button when ctaOptions are provided', () => {
|
|
44
|
+
const mockPurchaseData = {
|
|
45
|
+
collectibles: [
|
|
46
|
+
{
|
|
47
|
+
tokenId: '1',
|
|
48
|
+
name: 'Test NFT',
|
|
49
|
+
image: 'https://test.com/image.png',
|
|
50
|
+
attributes: [],
|
|
51
|
+
},
|
|
52
|
+
],
|
|
53
|
+
totalPrice: '1.5 ETH',
|
|
54
|
+
explorerUrl: 'https://etherscan.io/tx/123',
|
|
55
|
+
explorerName: 'Etherscan',
|
|
56
|
+
ctaOptions: {
|
|
57
|
+
ctaLabel: 'View Collection',
|
|
58
|
+
ctaOnClick: vi.fn(),
|
|
59
|
+
},
|
|
60
|
+
};
|
|
61
|
+
|
|
62
|
+
successfulPurchaseModal$.open(mockPurchaseData);
|
|
63
|
+
render(<SuccessfulPurchaseModal />);
|
|
64
|
+
|
|
65
|
+
expect(screen.getByText('View Collection')).toBeInTheDocument();
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
it('should handle multiple collectibles correctly', () => {
|
|
69
|
+
const mockPurchaseData = {
|
|
70
|
+
collectibles: Array(5)
|
|
71
|
+
.fill(null)
|
|
72
|
+
.map((_, index) => ({
|
|
73
|
+
tokenId: String(index + 1),
|
|
74
|
+
name: `Test NFT ${index + 1}`,
|
|
75
|
+
image: `https://test.com/image${index + 1}.png`,
|
|
76
|
+
attributes: [],
|
|
77
|
+
})),
|
|
78
|
+
totalPrice: '5.0 ETH',
|
|
79
|
+
explorerUrl: 'https://etherscan.io/tx/123',
|
|
80
|
+
explorerName: 'Etherscan',
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
successfulPurchaseModal$.open(mockPurchaseData);
|
|
84
|
+
render(<SuccessfulPurchaseModal />);
|
|
85
|
+
|
|
86
|
+
expect(screen.getByText('5 TOTAL')).toBeInTheDocument();
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should close modal when close button is clicked', () => {
|
|
90
|
+
const mockPurchaseData = {
|
|
91
|
+
collectibles: [
|
|
92
|
+
{
|
|
93
|
+
tokenId: '1',
|
|
94
|
+
name: 'Test NFT',
|
|
95
|
+
image: 'https://test.com/image.png',
|
|
96
|
+
attributes: [],
|
|
97
|
+
},
|
|
98
|
+
],
|
|
99
|
+
totalPrice: '1.5 ETH',
|
|
100
|
+
explorerUrl: 'https://etherscan.io/tx/123',
|
|
101
|
+
explorerName: 'Etherscan',
|
|
102
|
+
};
|
|
103
|
+
|
|
104
|
+
successfulPurchaseModal$.open(mockPurchaseData);
|
|
105
|
+
render(<SuccessfulPurchaseModal />);
|
|
106
|
+
|
|
107
|
+
const closeButton = screen.getByLabelText('Close modal');
|
|
108
|
+
closeButton.click();
|
|
109
|
+
|
|
110
|
+
expect(successfulPurchaseModal$.isOpen.get()).toBe(false);
|
|
111
|
+
});
|
|
112
|
+
|
|
113
|
+
describe('useSuccessfulPurchaseModal', () => {
|
|
114
|
+
it('should provide show and close functions', () => {
|
|
115
|
+
const modal = useSuccessfulPurchaseModal();
|
|
116
|
+
|
|
117
|
+
expect(modal.show).toBeDefined();
|
|
118
|
+
expect(modal.close).toBeDefined();
|
|
119
|
+
});
|
|
120
|
+
|
|
121
|
+
it('should pass callbacks to modal state', () => {
|
|
122
|
+
const callbacks = {
|
|
123
|
+
onSuccess: vi.fn(),
|
|
124
|
+
} satisfies ModalCallbacks;
|
|
125
|
+
|
|
126
|
+
const modal = useSuccessfulPurchaseModal(callbacks);
|
|
127
|
+
const mockPurchaseData = {
|
|
128
|
+
collectibles: [
|
|
129
|
+
{
|
|
130
|
+
tokenId: '1',
|
|
131
|
+
name: 'Test NFT',
|
|
132
|
+
image: 'https://test.com/image.png',
|
|
133
|
+
attributes: [],
|
|
134
|
+
},
|
|
135
|
+
],
|
|
136
|
+
totalPrice: '1.5 ETH',
|
|
137
|
+
explorerUrl: 'https://etherscan.io/tx/123',
|
|
138
|
+
explorerName: 'Etherscan',
|
|
139
|
+
};
|
|
140
|
+
|
|
141
|
+
modal.show(mockPurchaseData);
|
|
142
|
+
expect(successfulPurchaseModal$.callbacks.get()).toBe(callbacks);
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
});
|
|
@@ -12,7 +12,14 @@ import {
|
|
|
12
12
|
Text,
|
|
13
13
|
} from '@0xsequence/design-system';
|
|
14
14
|
import { observer } from '@legendapp/state/react';
|
|
15
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
Close,
|
|
17
|
+
Content,
|
|
18
|
+
Overlay,
|
|
19
|
+
Portal,
|
|
20
|
+
Root,
|
|
21
|
+
Title,
|
|
22
|
+
} from '@radix-ui/react-dialog';
|
|
16
23
|
import { getProviderEl } from '../../../../../_internal';
|
|
17
24
|
import {
|
|
18
25
|
closeButton,
|
|
@@ -77,16 +84,18 @@ export const ActionModal = observer(
|
|
|
77
84
|
gap="4"
|
|
78
85
|
position={'relative'}
|
|
79
86
|
>
|
|
80
|
-
<
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
87
|
+
<Title asChild>
|
|
88
|
+
<Text
|
|
89
|
+
fontSize="medium"
|
|
90
|
+
fontWeight="bold"
|
|
91
|
+
textAlign="center"
|
|
92
|
+
width="full"
|
|
93
|
+
color="text100"
|
|
94
|
+
fontFamily="body"
|
|
95
|
+
>
|
|
96
|
+
{title}
|
|
97
|
+
</Text>
|
|
98
|
+
</Title>
|
|
90
99
|
|
|
91
100
|
{children}
|
|
92
101
|
|
package/src/react/ui/modals/_internal/components/currencyOptionsSelect/__tests__/index.test.tsx
CHANGED
|
@@ -1,54 +1,12 @@
|
|
|
1
1
|
import '@testing-library/jest-dom/vitest';
|
|
2
|
-
import {
|
|
2
|
+
import { screen, cleanup, fireEvent } from '@testing-library/react';
|
|
3
3
|
import { describe, it, expect, vi, beforeEach } from 'vitest';
|
|
4
4
|
import { observable } from '@legendapp/state';
|
|
5
5
|
import CurrencyOptionsSelect from '..';
|
|
6
6
|
import type { Currency } from '../../../../../../_internal';
|
|
7
7
|
import { useCurrencies } from '../../../../../../hooks';
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
const MOCK_USDC: Currency = {
|
|
11
|
-
symbol: 'USDC',
|
|
12
|
-
contractAddress: '0x1234',
|
|
13
|
-
chainId: 1,
|
|
14
|
-
name: 'USD Coin',
|
|
15
|
-
decimals: 6,
|
|
16
|
-
imageUrl: 'https://example.com/usdc.png',
|
|
17
|
-
exchangeRate: 1,
|
|
18
|
-
defaultChainCurrency: false,
|
|
19
|
-
nativeCurrency: false,
|
|
20
|
-
createdAt: new Date().toISOString(),
|
|
21
|
-
updatedAt: new Date().toISOString(),
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
const MOCK_WETH: Currency = {
|
|
25
|
-
symbol: 'WETH',
|
|
26
|
-
contractAddress: '0x5678',
|
|
27
|
-
chainId: 1,
|
|
28
|
-
name: 'Wrapped Ether',
|
|
29
|
-
decimals: 18,
|
|
30
|
-
imageUrl: 'https://example.com/weth.png',
|
|
31
|
-
exchangeRate: 1,
|
|
32
|
-
defaultChainCurrency: false,
|
|
33
|
-
nativeCurrency: false,
|
|
34
|
-
createdAt: new Date().toISOString(),
|
|
35
|
-
updatedAt: new Date().toISOString(),
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
// Mock the required hooks
|
|
39
|
-
vi.mock('../../../../../../hooks/useCurrencyOptions', () => ({
|
|
40
|
-
useCurrencyOptions: vi.fn(() => ({
|
|
41
|
-
USDC: MOCK_USDC.contractAddress,
|
|
42
|
-
WETH: MOCK_WETH.contractAddress,
|
|
43
|
-
})),
|
|
44
|
-
}));
|
|
45
|
-
|
|
46
|
-
vi.mock('../../../../../../hooks', () => ({
|
|
47
|
-
useCurrencies: vi.fn(() => ({
|
|
48
|
-
data: [MOCK_USDC, MOCK_WETH],
|
|
49
|
-
isLoading: false,
|
|
50
|
-
})),
|
|
51
|
-
}));
|
|
8
|
+
import { mockCurrencies } from '../../../../../../_internal/api/__mocks__/marketplace.msw';
|
|
9
|
+
import { render } from '../../../../../../_internal/test-utils';
|
|
52
10
|
|
|
53
11
|
// Mock the Skeleton component
|
|
54
12
|
vi.mock('@0xsequence/design-system', async (importOriginal) => {
|
|
@@ -73,12 +31,6 @@ describe('CurrencyOptionsSelect', () => {
|
|
|
73
31
|
cleanup();
|
|
74
32
|
// Reset all mocks
|
|
75
33
|
vi.clearAllMocks();
|
|
76
|
-
|
|
77
|
-
// Setup default mock values
|
|
78
|
-
vi.mocked(useCurrencies as any).mockReturnValue({
|
|
79
|
-
data: [MOCK_USDC, MOCK_WETH],
|
|
80
|
-
isLoading: false,
|
|
81
|
-
});
|
|
82
34
|
});
|
|
83
35
|
|
|
84
36
|
it('should render loading skeleton when currencies are loading', () => {
|
|
@@ -100,7 +52,7 @@ describe('CurrencyOptionsSelect', () => {
|
|
|
100
52
|
/>,
|
|
101
53
|
);
|
|
102
54
|
|
|
103
|
-
expect(selectedCurrency$.get()).toEqual(
|
|
55
|
+
expect(selectedCurrency$.get()).toEqual(mockCurrencies[0]);
|
|
104
56
|
});
|
|
105
57
|
|
|
106
58
|
it('should set second currency as default when secondCurrencyAsDefault is true', () => {
|
|
@@ -113,11 +65,14 @@ describe('CurrencyOptionsSelect', () => {
|
|
|
113
65
|
/>,
|
|
114
66
|
);
|
|
115
67
|
|
|
116
|
-
expect(selectedCurrency$.get()).toEqual(
|
|
68
|
+
expect(selectedCurrency$.get()).toEqual(mockCurrencies[1]);
|
|
117
69
|
});
|
|
118
70
|
|
|
119
71
|
it('should update selected currency when user selects a different option', () => {
|
|
120
|
-
const
|
|
72
|
+
const firstCurrency = mockCurrencies[0];
|
|
73
|
+
const secondCurrency = mockCurrencies[1];
|
|
74
|
+
|
|
75
|
+
const selectedCurrency$ = observable(firstCurrency);
|
|
121
76
|
|
|
122
77
|
const { getByRole, getByText } = render(
|
|
123
78
|
<CurrencyOptionsSelect
|
|
@@ -131,14 +86,14 @@ describe('CurrencyOptionsSelect', () => {
|
|
|
131
86
|
fireEvent.click(selectButton);
|
|
132
87
|
|
|
133
88
|
// Find and click the WETH option in the dropdown
|
|
134
|
-
const wethOption = getByText(
|
|
89
|
+
const wethOption = getByText(secondCurrency.symbol);
|
|
135
90
|
fireEvent.click(wethOption);
|
|
136
91
|
|
|
137
|
-
expect(selectedCurrency$.get()).toEqual(
|
|
92
|
+
expect(selectedCurrency$.get()).toEqual(secondCurrency);
|
|
138
93
|
});
|
|
139
94
|
|
|
140
95
|
it('should maintain selected currency when currencies reload', () => {
|
|
141
|
-
const selectedCurrency$ = observable(
|
|
96
|
+
const selectedCurrency$ = observable(mockCurrencies[0]);
|
|
142
97
|
|
|
143
98
|
const { rerender } = render(
|
|
144
99
|
<CurrencyOptionsSelect
|
|
@@ -154,6 +109,6 @@ describe('CurrencyOptionsSelect', () => {
|
|
|
154
109
|
/>,
|
|
155
110
|
);
|
|
156
111
|
|
|
157
|
-
expect(selectedCurrency$.get()).toEqual(
|
|
112
|
+
expect(selectedCurrency$.get()).toEqual(mockCurrencies[0]);
|
|
158
113
|
});
|
|
159
114
|
});
|
|
@@ -10,6 +10,7 @@ import {
|
|
|
10
10
|
cleanup,
|
|
11
11
|
fireEvent,
|
|
12
12
|
} from '../../../../../../_internal/test-utils';
|
|
13
|
+
import { CurrencyStatus } from '../../../../../../_internal';
|
|
13
14
|
|
|
14
15
|
vi.mock('../hooks/usePriceInput', () => ({
|
|
15
16
|
usePriceInput: vi.fn(({ onPriceChange }) => ({
|
|
@@ -43,6 +44,7 @@ const MOCK_CURRENCY: Currency = {
|
|
|
43
44
|
name: 'USD Coin',
|
|
44
45
|
decimals: 6,
|
|
45
46
|
imageUrl: 'https://example.com/usdc.png',
|
|
47
|
+
status: CurrencyStatus.active,
|
|
46
48
|
exchangeRate: 1,
|
|
47
49
|
defaultChainCurrency: false,
|
|
48
50
|
nativeCurrency: false,
|
|
@@ -10,7 +10,6 @@ import { transactionStatusModal$ } from '../store';
|
|
|
10
10
|
import type { ShowTransactionStatusModalArgs } from '../index';
|
|
11
11
|
import { TransactionType } from '../../../../../../_internal/types';
|
|
12
12
|
import { beforeEach, describe, expect, it, vi, afterEach } from 'vitest';
|
|
13
|
-
import { WaitForTransactionReceiptTimeoutError } from 'viem';
|
|
14
13
|
|
|
15
14
|
const mockTransactionArgs: ShowTransactionStatusModalArgs = {
|
|
16
15
|
hash: '0x123' as `0x${string}`,
|
|
@@ -20,14 +19,12 @@ const mockTransactionArgs: ShowTransactionStatusModalArgs = {
|
|
|
20
19
|
type: TransactionType.BUY,
|
|
21
20
|
};
|
|
22
21
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
vi.mock('../../../../../../../utils/get-public-rpc-client', () => ({
|
|
28
|
-
getPublicRpcClient: vi.fn().mockImplementation(() => mockPublicClient),
|
|
22
|
+
vi.mock('../hooks/useTransactionStatus', () => ({
|
|
23
|
+
default: vi.fn(),
|
|
29
24
|
}));
|
|
30
25
|
|
|
26
|
+
import useTransactionStatus from '../hooks/useTransactionStatus';
|
|
27
|
+
|
|
31
28
|
describe('TransactionStatusModal', () => {
|
|
32
29
|
afterEach(() => {
|
|
33
30
|
cleanup();
|
|
@@ -36,6 +33,7 @@ describe('TransactionStatusModal', () => {
|
|
|
36
33
|
beforeEach(() => {
|
|
37
34
|
transactionStatusModal$.close();
|
|
38
35
|
vi.clearAllMocks();
|
|
36
|
+
(useTransactionStatus as any).mockReturnValue('PENDING');
|
|
39
37
|
});
|
|
40
38
|
|
|
41
39
|
it('should not render when closed', () => {
|
|
@@ -46,6 +44,7 @@ describe('TransactionStatusModal', () => {
|
|
|
46
44
|
});
|
|
47
45
|
|
|
48
46
|
it('should show processing state when transaction is processing', async () => {
|
|
47
|
+
(useTransactionStatus as any).mockReturnValue('PENDING');
|
|
49
48
|
transactionStatusModal$.open(mockTransactionArgs);
|
|
50
49
|
render(<TransactionStatusModal />);
|
|
51
50
|
|
|
@@ -61,9 +60,7 @@ describe('TransactionStatusModal', () => {
|
|
|
61
60
|
});
|
|
62
61
|
|
|
63
62
|
it('should show success state when transaction is successful', async () => {
|
|
64
|
-
|
|
65
|
-
status: 'success',
|
|
66
|
-
});
|
|
63
|
+
(useTransactionStatus as any).mockReturnValue('SUCCESS');
|
|
67
64
|
transactionStatusModal$.open(mockTransactionArgs);
|
|
68
65
|
render(<TransactionStatusModal />);
|
|
69
66
|
|
|
@@ -79,9 +76,7 @@ describe('TransactionStatusModal', () => {
|
|
|
79
76
|
});
|
|
80
77
|
|
|
81
78
|
it('should show failed state when transaction fails', async () => {
|
|
82
|
-
|
|
83
|
-
new Error('Transaction failed'),
|
|
84
|
-
);
|
|
79
|
+
(useTransactionStatus as any).mockReturnValue('FAILED');
|
|
85
80
|
transactionStatusModal$.open(mockTransactionArgs);
|
|
86
81
|
render(<TransactionStatusModal />);
|
|
87
82
|
|
|
@@ -95,9 +90,7 @@ describe('TransactionStatusModal', () => {
|
|
|
95
90
|
});
|
|
96
91
|
|
|
97
92
|
it('should show timeout state when transaction times out', async () => {
|
|
98
|
-
|
|
99
|
-
new WaitForTransactionReceiptTimeoutError({ hash: '0x123' }),
|
|
100
|
-
);
|
|
93
|
+
(useTransactionStatus as any).mockReturnValue('TIMEOUT');
|
|
101
94
|
transactionStatusModal$.open(mockTransactionArgs);
|
|
102
95
|
render(<TransactionStatusModal />);
|
|
103
96
|
|
|
@@ -112,8 +105,11 @@ describe('TransactionStatusModal', () => {
|
|
|
112
105
|
|
|
113
106
|
it('should call onSuccess callback when transaction succeeds', async () => {
|
|
114
107
|
const onSuccess = vi.fn();
|
|
115
|
-
|
|
116
|
-
|
|
108
|
+
(useTransactionStatus as any).mockImplementation(() => {
|
|
109
|
+
onSuccess({
|
|
110
|
+
hash: mockTransactionArgs.hash,
|
|
111
|
+
});
|
|
112
|
+
return 'SUCCESS';
|
|
117
113
|
});
|
|
118
114
|
|
|
119
115
|
transactionStatusModal$.open({
|
|
@@ -132,7 +128,10 @@ describe('TransactionStatusModal', () => {
|
|
|
132
128
|
it('should call onError callback when transaction fails', async () => {
|
|
133
129
|
const onError = vi.fn();
|
|
134
130
|
const error = new Error('Transaction failed');
|
|
135
|
-
|
|
131
|
+
(useTransactionStatus as any).mockImplementation(() => {
|
|
132
|
+
onError(error);
|
|
133
|
+
return 'FAILED';
|
|
134
|
+
});
|
|
136
135
|
|
|
137
136
|
transactionStatusModal$.open({
|
|
138
137
|
...mockTransactionArgs,
|
package/src/react/ui/modals/_internal/components/transactionStatusModal/__tests__/utils.test.ts
CHANGED
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
getTransactionStatusModalSpinnerTitle,
|
|
8
8
|
} from '../util/getTitle';
|
|
9
9
|
import type { TransactionStatus } from '../store';
|
|
10
|
+
import { CurrencyStatus } from '../../../../../../_internal';
|
|
10
11
|
|
|
11
12
|
describe('Transaction Status Modal Utils', () => {
|
|
12
13
|
describe('getFormattedType', () => {
|
|
@@ -111,6 +112,7 @@ describe('Transaction Status Modal Utils', () => {
|
|
|
111
112
|
nativeCurrency: true,
|
|
112
113
|
createdAt: '2024-01-21T00:00:00Z',
|
|
113
114
|
updatedAt: '2024-01-21T00:00:00Z',
|
|
115
|
+
status: CurrencyStatus.active,
|
|
114
116
|
},
|
|
115
117
|
},
|
|
116
118
|
}),
|