@0xsequence/marketplace-sdk 0.5.1 → 0.5.3
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/builder-types-wOwfTJpd.d.ts +73 -0
- package/dist/{chunk-FCF57DZI.js → chunk-7FN62HOP.js} +5 -9
- package/dist/chunk-7FN62HOP.js.map +1 -0
- package/dist/{chunk-F4E3WJ2K.js → chunk-BVXIRVEC.js} +261 -249
- package/dist/chunk-BVXIRVEC.js.map +1 -0
- package/dist/{chunk-XP3WY5AX.js → chunk-BZD2LDJJ.js} +2 -2
- package/dist/{chunk-XP3WY5AX.js.map → chunk-BZD2LDJJ.js.map} +1 -1
- package/dist/chunk-DZKPDV63.js +27 -0
- package/dist/chunk-DZKPDV63.js.map +1 -0
- package/dist/{chunk-I37CRQ4S.js → chunk-H5YWG6WN.js} +128 -88
- package/dist/chunk-H5YWG6WN.js.map +1 -0
- package/dist/{chunk-ZUEQGPLO.js → chunk-J6F5QOW5.js} +2 -2
- package/dist/{chunk-ZUEQGPLO.js.map → chunk-J6F5QOW5.js.map} +1 -1
- package/dist/{chunk-LJAB3S6U.js → chunk-TFRAOS7F.js} +22 -13
- package/dist/chunk-TFRAOS7F.js.map +1 -0
- package/dist/{chunk-5NORRVPM.js → chunk-UZIAX32Y.js} +1 -1
- package/dist/{chunk-5NORRVPM.js.map → chunk-UZIAX32Y.js.map} +1 -1
- package/dist/{chunk-MKGSGTQC.js → chunk-Y7YTLAO2.js} +3 -3
- package/dist/{create-config-BXvwUh55.d.ts → create-config-Bltg8Enl.d.ts} +1 -1
- package/dist/index.css +1 -1
- package/dist/index.d.ts +3 -3
- package/dist/index.js +10 -6
- package/dist/react/_internal/index.d.ts +3 -3
- package/dist/react/_internal/index.js +1 -1
- package/dist/react/_internal/wagmi/index.d.ts +2 -3
- package/dist/react/_internal/wagmi/index.js +1 -1
- package/dist/react/hooks/index.d.ts +72 -20
- package/dist/react/hooks/index.js +5 -7
- package/dist/react/index.css +1 -1
- package/dist/react/index.css.map +1 -1
- package/dist/react/index.d.ts +4 -4
- package/dist/react/index.js +8 -10
- package/dist/react/ssr/index.d.ts +54 -41
- package/dist/react/ssr/index.js +5 -9
- package/dist/react/ssr/index.js.map +1 -1
- package/dist/react/ui/components/collectible-card/index.css +1 -1
- package/dist/react/ui/components/collectible-card/index.css.map +1 -1
- package/dist/react/ui/components/collectible-card/index.d.ts +2 -2
- package/dist/react/ui/components/collectible-card/index.js +8 -8
- package/dist/react/ui/index.css +1 -1
- package/dist/react/ui/index.css.map +1 -1
- package/dist/react/ui/index.d.ts +2 -2
- package/dist/react/ui/index.js +8 -8
- package/dist/react/ui/modals/_internal/components/actionModal/index.d.ts +2 -2
- package/dist/react/ui/modals/_internal/components/actionModal/index.js +6 -6
- package/dist/styles/index.css +1 -1
- package/dist/styles/index.css.map +1 -1
- package/dist/styles/index.js +1 -1
- package/dist/types/index.d.ts +1 -3
- package/dist/types/index.js +9 -5
- package/dist/{types-Yto6KrTN.d.ts → types-BY3husBh.d.ts} +1 -1
- package/dist/utils/index.d.ts +2 -2
- package/dist/utils/index.js +4 -4
- package/package.json +11 -10
- package/src/react/_internal/api/__mocks__/indexer.msw.ts +197 -0
- package/src/react/_internal/api/__mocks__/marketplace.msw.ts +140 -1
- package/src/react/_internal/api/__mocks__/metadata.msw.ts +162 -0
- package/src/react/_internal/test/mocks/publicClient.ts +39 -0
- package/src/react/_internal/test/mocks/wagmi.ts +61 -0
- package/src/react/_internal/test/mocks/wallet.ts +61 -0
- package/src/react/_internal/test/setup.ts +28 -0
- package/src/react/_internal/test-utils.tsx +31 -2
- package/src/react/_internal/wagmi/__tests__/create-config.test.ts +53 -20
- package/src/react/_internal/wagmi/create-config.ts +3 -4
- package/src/react/_internal/wagmi/embedded.ts +1 -4
- package/src/react/_internal/wagmi/universal.ts +1 -4
- package/src/react/_internal/wallet/wallet.ts +1 -0
- package/src/react/hooks/__tests__/useAutoSelectFeeOption.test.tsx +314 -0
- package/src/react/hooks/__tests__/useBalanceOfCollectible.test.tsx +148 -0
- package/src/react/hooks/__tests__/useCancelOrder.test.tsx +410 -0
- package/src/react/hooks/__tests__/useCancelTransactionSteps.test.tsx +269 -0
- package/src/react/hooks/__tests__/useCollectible.test.tsx +120 -0
- package/src/react/hooks/__tests__/useCollection.test.tsx +101 -0
- package/src/react/hooks/__tests__/useCollectionBalanceDetails.test.tsx +175 -0
- package/src/react/hooks/__tests__/useCollectionDetails.test.tsx +82 -0
- package/src/react/hooks/__tests__/useCollectionDetailsPolling.test.tsx +133 -0
- package/src/react/hooks/__tests__/useCountListingsForCollectible.test.tsx +108 -0
- package/src/react/hooks/__tests__/useCountOfCollectables.test.tsx +129 -0
- package/src/react/hooks/__tests__/useCountOffersForCollectible.test.tsx +108 -0
- package/src/react/hooks/__tests__/useCurrencies.test.tsx +176 -0
- package/src/react/hooks/__tests__/useCurrency.test.tsx +153 -0
- package/src/react/hooks/__tests__/useCurrencyBalance.test.tsx +111 -0
- package/src/react/hooks/__tests__/useFilters.test.tsx +127 -0
- package/src/react/hooks/__tests__/useFloorOrder.test.tsx +101 -0
- package/src/react/hooks/__tests__/useGenerateBuyTransaction.test.tsx +173 -0
- package/src/react/hooks/__tests__/useGenerateCancelTransaction.test.tsx +207 -0
- package/src/react/hooks/__tests__/useGenerateListingTransaction.test.tsx +207 -0
- package/src/react/hooks/__tests__/useGenerateOfferTransaction.test.tsx +205 -0
- package/src/react/hooks/__tests__/useGenerateSellTransaction.test.tsx +181 -0
- package/src/react/hooks/__tests__/useHighestOffer.test.tsx +118 -0
- package/src/react/hooks/__tests__/useListBalances.test.tsx +136 -0
- package/src/react/hooks/__tests__/useListCollectibleActivities.test.tsx +200 -0
- package/src/react/hooks/__tests__/useListCollectibles.test.tsx +232 -0
- package/src/react/hooks/__tests__/useListCollectionActivities.test.tsx +235 -0
- package/src/react/hooks/__tests__/useListCollections.test.tsx +296 -0
- package/src/react/hooks/__tests__/useListListingsForCollectible.test.tsx +140 -0
- package/src/react/hooks/__tests__/useListOffersForCollectible.test.tsx +140 -0
- package/src/react/hooks/__tests__/useLowestListing.test.tsx +148 -0
- package/src/react/hooks/__tests__/useMarketplaceConfig.test.tsx +106 -0
- package/src/react/hooks/__tests__/useRoyaltyPercentage.test.tsx +129 -0
- package/src/react/hooks/index.ts +0 -1
- package/src/react/hooks/options/__mocks__/marketplaceConfig.msw.ts +66 -10
- package/src/react/hooks/options/__tests__/marketplaceConfigOptions.test.tsx +2 -11
- package/src/react/hooks/options/marketplaceConfigOptions.ts +8 -3
- package/src/react/hooks/useAutoSelectFeeOption.tsx +4 -3
- package/src/react/hooks/useCancelTransactionSteps.tsx +17 -9
- package/src/react/hooks/useCollectionDetailsPolling.tsx +1 -1
- package/src/react/hooks/useCurrencies.tsx +29 -28
- package/src/react/hooks/useFilters.tsx +69 -2
- package/src/react/hooks/useGenerateBuyTransaction.tsx +13 -5
- package/src/react/hooks/useListCollectibleActivities.tsx +1 -0
- package/src/react/hooks/useListCollectibles.tsx +1 -0
- package/src/react/hooks/useListCollectionActivities.tsx +1 -0
- package/src/react/hooks/useListCollections.tsx +2 -2
- package/src/react/ui/components/_internals/custom-select/__tests__/CustomSelect.test.tsx +6 -2
- package/src/react/ui/components/collectible-card/CollectibleCard.tsx +1 -1
- package/src/react/ui/components/collectible-card/Footer.tsx +9 -5
- package/src/react/ui/modals/BuyModal/Modal.tsx +9 -4
- package/src/react/ui/modals/BuyModal/__tests__/Modal.test.tsx +0 -1
- package/src/react/ui/modals/BuyModal/__tests__/store.test.ts +4 -2
- package/src/react/ui/modals/BuyModal/hooks/__tests__/useBuyCollectable.test.tsx +1 -24
- package/src/react/ui/modals/BuyModal/hooks/__tests__/useCheckoutOptions.test.tsx +152 -210
- package/src/react/ui/modals/BuyModal/hooks/__tests__/useFees.test.tsx +19 -49
- package/src/react/ui/modals/BuyModal/hooks/useFees.ts +6 -6
- package/src/react/ui/modals/BuyModal/modals/Modal1155.tsx +4 -2
- package/src/react/ui/modals/BuyModal/modals/__tests__/Modal1155.test.tsx +161 -52
- package/src/react/ui/modals/BuyModal/store.ts +7 -0
- package/src/react/ui/modals/CreateListingModal/Modal.tsx +1 -3
- package/src/react/ui/modals/CreateListingModal/__tests__/Modal.test.tsx +59 -227
- package/src/react/ui/modals/CreateListingModal/hooks/useCreateListing.tsx +2 -1
- package/src/react/ui/modals/CreateListingModal/hooks/useGetTokenApproval.ts +8 -2
- package/src/react/ui/modals/CreateListingModal/hooks/useTransactionSteps.tsx +9 -5
- package/src/react/ui/modals/MakeOfferModal/Modal.tsx +1 -8
- package/src/react/ui/modals/MakeOfferModal/__tests__/Modal.test.tsx +41 -118
- package/src/react/ui/modals/MakeOfferModal/hooks/useMakeOffer.tsx +2 -1
- package/src/react/ui/modals/MakeOfferModal/hooks/useTransactionSteps.tsx +9 -5
- package/src/react/ui/modals/SellModal/__tests__/Modal.test.tsx +4 -3
- package/src/react/ui/modals/SellModal/hooks/useGetTokenApproval.tsx +33 -31
- package/src/react/ui/modals/SellModal/hooks/useSell.tsx +1 -0
- package/src/react/ui/modals/SellModal/hooks/useTransactionSteps.tsx +9 -5
- package/src/react/ui/modals/SuccessfulPurchaseModal/__tests__/Modal.test.tsx +0 -1
- package/src/react/ui/modals/_internal/components/actionModal/ErrorModal.tsx +4 -2
- package/src/react/ui/modals/_internal/components/currencyOptionsSelect/__tests__/index.test.tsx +129 -57
- package/src/react/ui/modals/_internal/components/currencyOptionsSelect/index.tsx +1 -3
- package/src/react/ui/modals/_internal/components/priceInput/__tests__/index.test.tsx +1 -3
- package/src/react/ui/modals/_internal/components/transactionDetails/index.tsx +2 -2
- package/src/react/ui/modals/_internal/components/transactionStatusModal/__tests__/TransactionStatusModal.test.tsx +8 -8
- package/src/react/ui/modals/_internal/components/transactionStatusModal/hooks/useTransactionStatus.ts +1 -0
- package/src/types/builder-types.ts +79 -0
- package/src/types/index.ts +1 -1
- package/src/utils/__tests__/get-public-rpc-client.test.ts +2 -0
- package/src/utils/getMarketplaceDetails.ts +2 -2
- package/tsconfig.tsbuildinfo +1 -1
- package/vitest.config.js +2 -1
- package/dist/chunk-F4E3WJ2K.js.map +0 -1
- package/dist/chunk-FCF57DZI.js.map +0 -1
- package/dist/chunk-I37CRQ4S.js.map +0 -1
- package/dist/chunk-LJAB3S6U.js.map +0 -1
- package/dist/chunk-RK6KYMZM.js +0 -18
- package/dist/chunk-RK6KYMZM.js.map +0 -1
- package/dist/marketplace-config-znEu4L0K.d.ts +0 -60
- package/src/react/hooks/useCurrencyOptions.tsx +0 -16
- package/src/types/marketplace-config.ts +0 -67
- /package/dist/{chunk-MKGSGTQC.js.map → chunk-Y7YTLAO2.js.map} +0 -0
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { useCollectible } from '../useCollectible';
|
|
3
|
+
import { renderHook, waitFor } from '../../_internal/test-utils';
|
|
4
|
+
import { zeroAddress } from 'viem';
|
|
5
|
+
import type { UseCollectibleArgs } from '../useCollectible';
|
|
6
|
+
import { http, HttpResponse } from 'msw';
|
|
7
|
+
import {
|
|
8
|
+
mockTokenMetadata,
|
|
9
|
+
mockMetadataEndpoint,
|
|
10
|
+
} from '../../_internal/api/__mocks__/metadata.msw';
|
|
11
|
+
import { server } from '../../_internal/test/setup';
|
|
12
|
+
|
|
13
|
+
describe('useCollectible', () => {
|
|
14
|
+
const defaultArgs: UseCollectibleArgs = {
|
|
15
|
+
chainId: '1',
|
|
16
|
+
collectionAddress: zeroAddress,
|
|
17
|
+
collectibleId: '1',
|
|
18
|
+
query: {},
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
it('should fetch collectible data successfully', async () => {
|
|
22
|
+
const { result } = renderHook(() => useCollectible(defaultArgs));
|
|
23
|
+
|
|
24
|
+
// Initially loading
|
|
25
|
+
expect(result.current.isLoading).toBe(true);
|
|
26
|
+
expect(result.current.data).toBeUndefined();
|
|
27
|
+
|
|
28
|
+
// Wait for data to be loaded
|
|
29
|
+
await waitFor(() => {
|
|
30
|
+
expect(result.current.isLoading).toBe(false);
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
// Verify the data matches our mock
|
|
34
|
+
expect(result.current.data).toEqual(mockTokenMetadata);
|
|
35
|
+
expect(result.current.error).toBeNull();
|
|
36
|
+
});
|
|
37
|
+
|
|
38
|
+
it('should handle error states', async () => {
|
|
39
|
+
// Override the handler for this test to return an error
|
|
40
|
+
server.use(
|
|
41
|
+
http.post(mockMetadataEndpoint('GetTokenMetadata'), () => {
|
|
42
|
+
return HttpResponse.json(
|
|
43
|
+
{ error: { message: 'Failed to fetch collectible' } },
|
|
44
|
+
{ status: 500 },
|
|
45
|
+
);
|
|
46
|
+
}),
|
|
47
|
+
);
|
|
48
|
+
|
|
49
|
+
const { result } = renderHook(() => useCollectible(defaultArgs));
|
|
50
|
+
|
|
51
|
+
await waitFor(() => {
|
|
52
|
+
expect(result.current.isError).toBe(true);
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
expect(result.current.error).toBeDefined();
|
|
56
|
+
expect(result.current.data).toBeUndefined();
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('should refetch when args change', async () => {
|
|
60
|
+
const { result, rerender } = renderHook(() => useCollectible(defaultArgs));
|
|
61
|
+
|
|
62
|
+
// Wait for initial data
|
|
63
|
+
await waitFor(() => {
|
|
64
|
+
expect(result.current.isLoading).toBe(false);
|
|
65
|
+
});
|
|
66
|
+
|
|
67
|
+
// Change args and rerender
|
|
68
|
+
const newArgs = {
|
|
69
|
+
...defaultArgs,
|
|
70
|
+
collectibleId: '2',
|
|
71
|
+
collectionAddress:
|
|
72
|
+
'0x1234567890123456789012345678901234567890' as `0x${string}`,
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
rerender(() => useCollectible(newArgs));
|
|
76
|
+
|
|
77
|
+
// Wait for new data
|
|
78
|
+
await waitFor(() => {
|
|
79
|
+
expect(result.current.data).toBeDefined();
|
|
80
|
+
});
|
|
81
|
+
|
|
82
|
+
// Verify that the query was refetched with new args
|
|
83
|
+
expect(result.current.data).toBeDefined();
|
|
84
|
+
expect(result.current.isSuccess).toBe(true);
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should handle undefined query params', async () => {
|
|
88
|
+
const argsWithoutQuery: UseCollectibleArgs = {
|
|
89
|
+
chainId: '1',
|
|
90
|
+
collectionAddress: zeroAddress,
|
|
91
|
+
collectibleId: '1',
|
|
92
|
+
query: {},
|
|
93
|
+
};
|
|
94
|
+
|
|
95
|
+
const { result } = renderHook(() => useCollectible(argsWithoutQuery));
|
|
96
|
+
|
|
97
|
+
await waitFor(() => {
|
|
98
|
+
expect(result.current.isLoading).toBe(false);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
expect(result.current.data).toBeDefined();
|
|
102
|
+
expect(result.current.error).toBeNull();
|
|
103
|
+
});
|
|
104
|
+
|
|
105
|
+
it('should validate input parameters', async () => {
|
|
106
|
+
const invalidArgs: UseCollectibleArgs = {
|
|
107
|
+
...defaultArgs,
|
|
108
|
+
// @ts-expect-error
|
|
109
|
+
chainId: {}, // Using an object instead of a string/number will fail validation
|
|
110
|
+
};
|
|
111
|
+
|
|
112
|
+
const { result } = renderHook(() => useCollectible(invalidArgs));
|
|
113
|
+
|
|
114
|
+
await waitFor(() => {
|
|
115
|
+
expect(result.current.isError).toBe(true);
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
expect(result.current.error).toBeDefined();
|
|
119
|
+
});
|
|
120
|
+
});
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { useCollection } from '../useCollection';
|
|
3
|
+
import { renderHook, waitFor } from '../../_internal/test-utils';
|
|
4
|
+
import { zeroAddress } from 'viem';
|
|
5
|
+
import type { UseCollectionArgs } from '../useCollection';
|
|
6
|
+
import { http, HttpResponse } from 'msw';
|
|
7
|
+
import {
|
|
8
|
+
mockContractInfo,
|
|
9
|
+
mockMetadataEndpoint,
|
|
10
|
+
} from '../../_internal/api/__mocks__/metadata.msw';
|
|
11
|
+
import { server } from '../../_internal/test/setup';
|
|
12
|
+
|
|
13
|
+
describe('useCollection', () => {
|
|
14
|
+
const defaultArgs: UseCollectionArgs = {
|
|
15
|
+
chainId: '1',
|
|
16
|
+
collectionAddress: zeroAddress,
|
|
17
|
+
query: {},
|
|
18
|
+
};
|
|
19
|
+
|
|
20
|
+
it('should fetch collection data successfully', async () => {
|
|
21
|
+
const { result } = renderHook(() => useCollection(defaultArgs));
|
|
22
|
+
|
|
23
|
+
// Initially loading
|
|
24
|
+
expect(result.current.isLoading).toBe(true);
|
|
25
|
+
expect(result.current.data).toBeUndefined();
|
|
26
|
+
|
|
27
|
+
// Wait for data to be loaded
|
|
28
|
+
await waitFor(() => {
|
|
29
|
+
expect(result.current.isLoading).toBe(false);
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
// Verify the data matches our mock
|
|
33
|
+
expect(result.current.data).toEqual(mockContractInfo);
|
|
34
|
+
expect(result.current.error).toBeNull();
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it('should handle error states', async () => {
|
|
38
|
+
// Override the handler for this test to return an error
|
|
39
|
+
server.use(
|
|
40
|
+
http.post(mockMetadataEndpoint('GetContractInfo'), () => {
|
|
41
|
+
return HttpResponse.json(
|
|
42
|
+
{ error: { message: 'Failed to fetch collection' } },
|
|
43
|
+
{ status: 500 },
|
|
44
|
+
);
|
|
45
|
+
}),
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
const { result } = renderHook(() => useCollection(defaultArgs));
|
|
49
|
+
|
|
50
|
+
await waitFor(() => {
|
|
51
|
+
expect(result.current.isError).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
expect(result.current.error).toBeDefined();
|
|
55
|
+
expect(result.current.data).toBeUndefined();
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
it('should refetch when args change', async () => {
|
|
59
|
+
const { result, rerender } = renderHook(() => useCollection(defaultArgs));
|
|
60
|
+
|
|
61
|
+
// Wait for initial data
|
|
62
|
+
await waitFor(() => {
|
|
63
|
+
expect(result.current.isLoading).toBe(false);
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
// Change args and rerender
|
|
67
|
+
const newArgs = {
|
|
68
|
+
...defaultArgs,
|
|
69
|
+
collectionAddress:
|
|
70
|
+
'0x1234567890123456789012345678901234567890' as `0x${string}`,
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
rerender(() => useCollection(newArgs));
|
|
74
|
+
|
|
75
|
+
// Wait for new data
|
|
76
|
+
await waitFor(() => {
|
|
77
|
+
expect(result.current.data).toBeDefined();
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// Verify that the query was refetched with new args
|
|
81
|
+
expect(result.current.data).toBeDefined();
|
|
82
|
+
expect(result.current.isSuccess).toBe(true);
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it('should handle undefined query params', async () => {
|
|
86
|
+
const argsWithoutQuery: UseCollectionArgs = {
|
|
87
|
+
chainId: '1',
|
|
88
|
+
collectionAddress: zeroAddress,
|
|
89
|
+
query: {},
|
|
90
|
+
};
|
|
91
|
+
|
|
92
|
+
const { result } = renderHook(() => useCollection(argsWithoutQuery));
|
|
93
|
+
|
|
94
|
+
await waitFor(() => {
|
|
95
|
+
expect(result.current.isLoading).toBe(false);
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
expect(result.current.data).toBeDefined();
|
|
99
|
+
expect(result.current.error).toBeNull();
|
|
100
|
+
});
|
|
101
|
+
});
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { waitFor } from '@testing-library/react';
|
|
3
|
+
import { useCollectionBalanceDetails } from '../useCollectionBalanceDetails';
|
|
4
|
+
import { mockTokenBalance } from '../../_internal/api/__mocks__/indexer.msw';
|
|
5
|
+
import { zeroAddress } from 'viem';
|
|
6
|
+
import { renderHook } from '../../_internal/test-utils';
|
|
7
|
+
import { http, HttpResponse } from 'msw';
|
|
8
|
+
import { server } from '../../_internal/test/setup';
|
|
9
|
+
import { mockIndexerEndpoint } from '../../_internal/api/__mocks__/indexer.msw';
|
|
10
|
+
|
|
11
|
+
describe('useCollectionBalanceDetails', () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
vi.clearAllMocks();
|
|
14
|
+
server.resetHandlers();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
server.resetHandlers();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
const defaultArgs = {
|
|
22
|
+
chainId: 1,
|
|
23
|
+
filter: {
|
|
24
|
+
accountAddresses: [zeroAddress],
|
|
25
|
+
omitNativeBalances: true,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
it('should fetch balance details successfully', async () => {
|
|
30
|
+
const { result } = renderHook(() =>
|
|
31
|
+
useCollectionBalanceDetails(defaultArgs),
|
|
32
|
+
);
|
|
33
|
+
|
|
34
|
+
// Initially loading
|
|
35
|
+
expect(result.current.isLoading).toBe(true);
|
|
36
|
+
expect(result.current.data).toBeUndefined();
|
|
37
|
+
|
|
38
|
+
// Wait for data to be loaded
|
|
39
|
+
await waitFor(() => {
|
|
40
|
+
expect(result.current.isLoading).toBe(false);
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
// Verify the data matches our mock
|
|
44
|
+
expect(result.current.data).toBeDefined();
|
|
45
|
+
expect(result.current.data?.balances[0]).toEqual(mockTokenBalance);
|
|
46
|
+
expect(result.current.error).toBeNull();
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should handle error states', async () => {
|
|
50
|
+
// Override the handler for this test to return an error
|
|
51
|
+
server.use(
|
|
52
|
+
http.post(mockIndexerEndpoint('GetTokenBalancesDetails'), () => {
|
|
53
|
+
return HttpResponse.json(
|
|
54
|
+
{ error: { message: 'Failed to fetch balances' } },
|
|
55
|
+
{ status: 500 },
|
|
56
|
+
);
|
|
57
|
+
}),
|
|
58
|
+
);
|
|
59
|
+
|
|
60
|
+
const { result } = renderHook(() =>
|
|
61
|
+
useCollectionBalanceDetails(defaultArgs),
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
// Wait for the error state
|
|
65
|
+
await waitFor(() => {
|
|
66
|
+
expect(result.current.isError).toBe(true);
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
expect(result.current.error).toBeDefined();
|
|
70
|
+
expect(result.current.data).toBeUndefined();
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
it('should refetch when args change', async () => {
|
|
74
|
+
const { result, rerender } = renderHook(() =>
|
|
75
|
+
useCollectionBalanceDetails(defaultArgs),
|
|
76
|
+
);
|
|
77
|
+
|
|
78
|
+
// Wait for initial data
|
|
79
|
+
await waitFor(() => {
|
|
80
|
+
expect(result.current.isLoading).toBe(false);
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
// Change args and rerender
|
|
84
|
+
const newArgs = {
|
|
85
|
+
...defaultArgs,
|
|
86
|
+
filter: {
|
|
87
|
+
...defaultArgs.filter,
|
|
88
|
+
accountAddresses: [
|
|
89
|
+
'0x1234567890123456789012345678901234567890' as `0x${string}`,
|
|
90
|
+
],
|
|
91
|
+
},
|
|
92
|
+
};
|
|
93
|
+
|
|
94
|
+
rerender(() => useCollectionBalanceDetails(newArgs));
|
|
95
|
+
|
|
96
|
+
// Wait for new data
|
|
97
|
+
await waitFor(() => {
|
|
98
|
+
expect(result.current.data).toBeDefined();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
expect(result.current.isSuccess).toBe(true);
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
it('should handle multiple accounts', async () => {
|
|
105
|
+
const multipleAccountsArgs = {
|
|
106
|
+
...defaultArgs,
|
|
107
|
+
filter: {
|
|
108
|
+
...defaultArgs.filter,
|
|
109
|
+
accountAddresses: [
|
|
110
|
+
zeroAddress,
|
|
111
|
+
'0x1234567890123456789012345678901234567890' as `0x${string}`,
|
|
112
|
+
],
|
|
113
|
+
},
|
|
114
|
+
};
|
|
115
|
+
|
|
116
|
+
const { result } = renderHook(() =>
|
|
117
|
+
useCollectionBalanceDetails(multipleAccountsArgs),
|
|
118
|
+
);
|
|
119
|
+
|
|
120
|
+
await waitFor(() => {
|
|
121
|
+
expect(result.current.isSuccess).toBe(true);
|
|
122
|
+
});
|
|
123
|
+
|
|
124
|
+
expect(result.current.data?.balances).toHaveLength(2);
|
|
125
|
+
expect(result.current.data?.balances).toEqual(
|
|
126
|
+
expect.arrayContaining([mockTokenBalance, mockTokenBalance]),
|
|
127
|
+
);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
it('should handle contract whitelist filter', async () => {
|
|
131
|
+
const whitelistArgs = {
|
|
132
|
+
...defaultArgs,
|
|
133
|
+
filter: {
|
|
134
|
+
...defaultArgs.filter,
|
|
135
|
+
contractWhitelist: [zeroAddress],
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
|
|
139
|
+
const { result } = renderHook(() =>
|
|
140
|
+
useCollectionBalanceDetails(whitelistArgs),
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
await waitFor(() => {
|
|
144
|
+
expect(result.current.isSuccess).toBe(true);
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
expect(result.current.data?.balances[0].contractAddress).toBe(zeroAddress);
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
it('should handle validation errors', () => {
|
|
151
|
+
expect(() =>
|
|
152
|
+
renderHook(() =>
|
|
153
|
+
useCollectionBalanceDetails({
|
|
154
|
+
chainId: 'invalid-chain-id' as unknown as number,
|
|
155
|
+
filter: {
|
|
156
|
+
accountAddresses: [zeroAddress],
|
|
157
|
+
omitNativeBalances: true,
|
|
158
|
+
},
|
|
159
|
+
}),
|
|
160
|
+
),
|
|
161
|
+
).toThrow();
|
|
162
|
+
|
|
163
|
+
expect(() =>
|
|
164
|
+
renderHook(() =>
|
|
165
|
+
useCollectionBalanceDetails({
|
|
166
|
+
chainId: 1,
|
|
167
|
+
filter: {
|
|
168
|
+
accountAddresses: ['invalid-address' as unknown as `0x${string}`],
|
|
169
|
+
omitNativeBalances: true,
|
|
170
|
+
},
|
|
171
|
+
}),
|
|
172
|
+
),
|
|
173
|
+
).toThrow();
|
|
174
|
+
});
|
|
175
|
+
});
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { useCollectionDetails } from '../useCollectionDetails';
|
|
3
|
+
import { renderHook, waitFor } from '../../_internal/test-utils';
|
|
4
|
+
import { zeroAddress } from 'viem';
|
|
5
|
+
import { http, HttpResponse } from 'msw';
|
|
6
|
+
import { mockCollection } from '../../_internal/api/__mocks__/marketplace.msw';
|
|
7
|
+
import { server } from '../../_internal/test/setup';
|
|
8
|
+
import { mockMarketplaceEndpoint } from '../../_internal/api/__mocks__/marketplace.msw';
|
|
9
|
+
|
|
10
|
+
describe('useCollectionDetails', () => {
|
|
11
|
+
const defaultArgs = {
|
|
12
|
+
chainId: 1,
|
|
13
|
+
collectionAddress: zeroAddress,
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
it('should fetch collection details successfully', async () => {
|
|
17
|
+
const { result } = renderHook(() => useCollectionDetails(defaultArgs));
|
|
18
|
+
|
|
19
|
+
// Initially loading
|
|
20
|
+
expect(result.current.isLoading).toBe(true);
|
|
21
|
+
expect(result.current.data).toBeUndefined();
|
|
22
|
+
|
|
23
|
+
// Wait for data to be loaded
|
|
24
|
+
await waitFor(() => {
|
|
25
|
+
expect(result.current.isLoading).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// Verify the data matches our mock
|
|
29
|
+
expect(result.current.data).toEqual(mockCollection);
|
|
30
|
+
expect(result.current.error).toBeNull();
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
it('should handle error states', async () => {
|
|
34
|
+
// Override the handler for this test to return an error
|
|
35
|
+
server.use(
|
|
36
|
+
http.post(mockMarketplaceEndpoint('GetCollectionDetail'), () => {
|
|
37
|
+
return HttpResponse.json(
|
|
38
|
+
{ error: { message: 'Failed to fetch collection details' } },
|
|
39
|
+
{ status: 500 },
|
|
40
|
+
);
|
|
41
|
+
}),
|
|
42
|
+
);
|
|
43
|
+
|
|
44
|
+
const { result } = renderHook(() => useCollectionDetails(defaultArgs));
|
|
45
|
+
|
|
46
|
+
await waitFor(() => {
|
|
47
|
+
expect(result.current.isError).toBe(true);
|
|
48
|
+
});
|
|
49
|
+
|
|
50
|
+
expect(result.current.error).toBeDefined();
|
|
51
|
+
expect(result.current.data).toBeUndefined();
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
it('should refetch when args change', async () => {
|
|
55
|
+
const { result, rerender } = renderHook(() =>
|
|
56
|
+
useCollectionDetails(defaultArgs),
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
// Wait for initial data
|
|
60
|
+
await waitFor(() => {
|
|
61
|
+
expect(result.current.isLoading).toBe(false);
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Change args and rerender
|
|
65
|
+
const newArgs = {
|
|
66
|
+
...defaultArgs,
|
|
67
|
+
collectionAddress:
|
|
68
|
+
'0x1234567890123456789012345678901234567890' as `0x${string}`,
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
rerender(() => useCollectionDetails(newArgs));
|
|
72
|
+
|
|
73
|
+
// Wait for new data
|
|
74
|
+
await waitFor(() => {
|
|
75
|
+
expect(result.current.data).toBeDefined();
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Verify that the query was refetched with new args
|
|
79
|
+
expect(result.current.data).toBeDefined();
|
|
80
|
+
expect(result.current.isSuccess).toBe(true);
|
|
81
|
+
});
|
|
82
|
+
});
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { describe, expect, it, vi, beforeEach, afterEach } from 'vitest';
|
|
2
|
+
import { useCollectionDetailsPolling } from '../useCollectionDetailsPolling';
|
|
3
|
+
import { renderHook, waitFor } from '../../_internal/test-utils';
|
|
4
|
+
import { zeroAddress } from 'viem';
|
|
5
|
+
import { http, HttpResponse } from 'msw';
|
|
6
|
+
import { mockCollection } from '../../_internal/api/__mocks__/marketplace.msw';
|
|
7
|
+
import { server } from '../../_internal/test/setup';
|
|
8
|
+
import { mockMarketplaceEndpoint } from '../../_internal/api/__mocks__/marketplace.msw';
|
|
9
|
+
import { CollectionStatus } from '../../_internal/api/marketplace.gen';
|
|
10
|
+
|
|
11
|
+
describe('useCollectionDetailsPolling', () => {
|
|
12
|
+
const defaultArgs = {
|
|
13
|
+
chainId: 1,
|
|
14
|
+
collectionAddress: zeroAddress,
|
|
15
|
+
};
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
vi.useFakeTimers({ shouldAdvanceTime: true });
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
afterEach(() => {
|
|
22
|
+
vi.useRealTimers();
|
|
23
|
+
server.resetHandlers();
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it('should poll collection details until terminal state is reached', async () => {
|
|
27
|
+
// Mock initial syncing state
|
|
28
|
+
const syncingCollection = {
|
|
29
|
+
...mockCollection,
|
|
30
|
+
status: CollectionStatus.syncing_metadata,
|
|
31
|
+
};
|
|
32
|
+
let requestCount = 0;
|
|
33
|
+
|
|
34
|
+
server.use(
|
|
35
|
+
http.post(mockMarketplaceEndpoint('GetCollectionDetail'), () => {
|
|
36
|
+
requestCount++;
|
|
37
|
+
// Return syncing state for first request, then active state
|
|
38
|
+
const response =
|
|
39
|
+
requestCount === 1
|
|
40
|
+
? { collection: syncingCollection }
|
|
41
|
+
: {
|
|
42
|
+
collection: {
|
|
43
|
+
...mockCollection,
|
|
44
|
+
status: CollectionStatus.active,
|
|
45
|
+
},
|
|
46
|
+
};
|
|
47
|
+
return HttpResponse.json(response);
|
|
48
|
+
}),
|
|
49
|
+
);
|
|
50
|
+
|
|
51
|
+
const { result } = renderHook(() =>
|
|
52
|
+
useCollectionDetailsPolling(defaultArgs),
|
|
53
|
+
);
|
|
54
|
+
|
|
55
|
+
// Initially loading
|
|
56
|
+
expect(result.current.isLoading).toBe(true);
|
|
57
|
+
expect(result.current.data).toBeUndefined();
|
|
58
|
+
|
|
59
|
+
// Wait for first data fetch
|
|
60
|
+
await waitFor(() => {
|
|
61
|
+
expect(result.current.data).toBeDefined();
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
// Should be in syncing state
|
|
65
|
+
expect(result.current.data?.status).toBe(CollectionStatus.syncing_metadata);
|
|
66
|
+
|
|
67
|
+
// Advance timer and run pending timers to trigger next poll
|
|
68
|
+
await vi.advanceTimersByTimeAsync(2000);
|
|
69
|
+
await vi.runOnlyPendingTimersAsync();
|
|
70
|
+
|
|
71
|
+
// Wait for second fetch to complete
|
|
72
|
+
await waitFor(() => {
|
|
73
|
+
expect(result.current.data?.status).toBe(CollectionStatus.active);
|
|
74
|
+
});
|
|
75
|
+
|
|
76
|
+
// Verify polling stops after reaching terminal state
|
|
77
|
+
const currentRequestCount = requestCount;
|
|
78
|
+
await vi.advanceTimersByTimeAsync(2000);
|
|
79
|
+
await vi.runOnlyPendingTimersAsync();
|
|
80
|
+
expect(requestCount).toBe(currentRequestCount); // Should not make additional requests
|
|
81
|
+
}, 10000);
|
|
82
|
+
|
|
83
|
+
it('should stop polling after max attempts', async () => {
|
|
84
|
+
const syncingCollection = {
|
|
85
|
+
...mockCollection,
|
|
86
|
+
status: CollectionStatus.syncing_metadata,
|
|
87
|
+
};
|
|
88
|
+
let requestCount = 0;
|
|
89
|
+
|
|
90
|
+
server.use(
|
|
91
|
+
http.post(mockMarketplaceEndpoint('GetCollectionDetail'), () => {
|
|
92
|
+
requestCount++;
|
|
93
|
+
return HttpResponse.json({ collection: syncingCollection });
|
|
94
|
+
}),
|
|
95
|
+
);
|
|
96
|
+
|
|
97
|
+
renderHook(() => useCollectionDetailsPolling(defaultArgs));
|
|
98
|
+
|
|
99
|
+
// Fast-forward through all attempts
|
|
100
|
+
for (let i = 0; i < 30; i++) {
|
|
101
|
+
await vi.advanceTimersByTimeAsync(2000);
|
|
102
|
+
await vi.runOnlyPendingTimersAsync();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const finalCount = requestCount;
|
|
106
|
+
await vi.advanceTimersByTimeAsync(30000);
|
|
107
|
+
await vi.runOnlyPendingTimersAsync();
|
|
108
|
+
expect(requestCount).toBe(finalCount); // Should not increase after max attempts
|
|
109
|
+
expect(requestCount).toBeLessThanOrEqual(30); // Should not exceed MAX_ATTEMPTS
|
|
110
|
+
}, 10000);
|
|
111
|
+
|
|
112
|
+
it('should handle error states', async () => {
|
|
113
|
+
server.use(
|
|
114
|
+
http.post(mockMarketplaceEndpoint('GetCollectionDetail'), () => {
|
|
115
|
+
return HttpResponse.json(
|
|
116
|
+
{ error: { message: 'Failed to fetch collection details' } },
|
|
117
|
+
{ status: 500 },
|
|
118
|
+
);
|
|
119
|
+
}),
|
|
120
|
+
);
|
|
121
|
+
|
|
122
|
+
const { result } = renderHook(() =>
|
|
123
|
+
useCollectionDetailsPolling(defaultArgs),
|
|
124
|
+
);
|
|
125
|
+
|
|
126
|
+
await waitFor(() => {
|
|
127
|
+
expect(result.current.isError).toBe(true);
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
expect(result.current.error).toBeDefined();
|
|
131
|
+
expect(result.current.data).toBeUndefined();
|
|
132
|
+
}, 10000);
|
|
133
|
+
});
|