@0xsequence/marketplace-sdk 0.8.4 → 0.8.6
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/CHANGELOG.md +16 -0
- package/dist/{chunk-VF3LWBQB.js → chunk-6SEJI7YS.js} +170 -9
- package/dist/chunk-6SEJI7YS.js.map +1 -0
- package/dist/{chunk-25CAMYCG.js → chunk-BB2PTJHI.js} +22 -20
- package/dist/chunk-BB2PTJHI.js.map +1 -0
- package/dist/{chunk-XUNDLCEH.js → chunk-LDZZUYG7.js} +2 -2
- package/dist/{chunk-44YGZVBS.js → chunk-QMWMJVTX.js} +2 -2
- package/dist/{chunk-HRL2TMXU.js → chunk-TGFX3TMV.js} +44 -34
- package/dist/{chunk-HRL2TMXU.js.map → chunk-TGFX3TMV.js.map} +1 -1
- package/dist/{chunk-VBRJ2OPM.js → chunk-V3NVAVHV.js} +2 -2
- package/dist/index.css +171 -36
- package/dist/index.css.map +1 -1
- package/dist/index.js +6 -6
- package/dist/react/_internal/databeat/index.js +5 -5
- package/dist/react/_internal/index.d.ts +1 -1
- package/dist/react/_internal/index.js +3 -1
- package/dist/react/_internal/wagmi/index.d.ts +3 -2
- package/dist/react/_internal/wagmi/index.js +3 -1
- package/dist/react/hooks/index.d.ts +246 -29
- package/dist/react/hooks/index.js +8 -4
- package/dist/react/hooks/options/index.js +2 -2
- package/dist/react/index.d.ts +2 -1
- package/dist/react/index.js +11 -7
- package/dist/react/queries/index.js +1 -1
- package/dist/react/ssr/index.js +1 -1
- package/dist/react/ui/components/collectible-card/index.d.ts +3 -2
- package/dist/react/ui/components/collectible-card/index.js +7 -7
- package/dist/react/ui/icons/index.js +2 -2
- package/dist/react/ui/index.js +7 -7
- package/dist/react/ui/modals/_internal/components/actionModal/index.js +5 -5
- package/dist/types/index.js +1 -1
- package/dist/utils/abi/index.js +5 -5
- package/dist/utils/index.js +6 -6
- package/package.json +20 -19
- package/src/react/_internal/wagmi/__tests__/create-config.test.ts +1 -11
- package/src/react/_internal/wagmi/get-connectors.ts +27 -24
- package/src/react/hooks/__tests__/useAutoSelectFeeOption.test.tsx +21 -75
- package/src/react/hooks/__tests__/useCurrencyBalance.test.tsx +4 -25
- package/src/react/hooks/index.ts +1 -0
- package/src/react/hooks/useFilterState.tsx +181 -0
- package/src/react/hooks/useFilters.tsx +24 -0
- package/src/react/ui/components/_internals/action-button/__tests__/ActionButtonBody.test.tsx +27 -94
- package/src/react/ui/components/_internals/action-button/__tests__/NonOwnerActions.test.tsx +59 -0
- package/src/react/ui/components/_internals/action-button/__tests__/OwnerActions.test.tsx +73 -0
- package/src/react/ui/components/_internals/action-button/__tests__/useActionButtonLogic.test.tsx +77 -0
- package/src/react/ui/components/_internals/action-button/components/ActionButtonBody.tsx +3 -2
- package/src/react/ui/components/_internals/action-button/hooks/useActionButtonLogic.ts +4 -3
- package/src/react/ui/components/collectible-card/CollectibleAsset.tsx +1 -0
- package/src/react/ui/components/collectible-card/CollectibleCard.tsx +18 -12
- package/src/react/ui/components/collectible-card/__tests__/CollectibleAsset.test.tsx +200 -0
- package/src/react/ui/components/collectible-card/__tests__/CollectibleCard.test.tsx +92 -123
- package/src/react/ui/components/collectible-card/__tests__/Footer.test.tsx +136 -0
- package/src/react/ui/modals/BuyModal/__tests__/Modal.test.tsx +2 -8
- package/src/react/ui/modals/SellModal/__tests__/Modal.test.tsx +72 -135
- package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/__tests__/ActionButtons.test.tsx +72 -0
- package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/__tests__/BalanceIndicator.test.tsx +50 -0
- package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/__tests__/SelectWaasFeeOptions.test.tsx +193 -0
- package/src/react/ui/modals/_internal/components/switchChainModal/__tests__/SwitchChainModal.test.tsx +38 -58
- package/src/react/ui/modals/_internal/components/switchChainModal/index.tsx +3 -1
- package/test/test-utils.tsx +12 -22
- package/tsconfig.tsbuildinfo +1 -1
- package/dist/chunk-25CAMYCG.js.map +0 -1
- package/dist/chunk-VF3LWBQB.js.map +0 -1
- package/src/react/ui/components/_internals/action-button/__tests__/ActionButton.test.tsx +0 -107
- /package/dist/{chunk-XUNDLCEH.js.map → chunk-LDZZUYG7.js.map} +0 -0
- /package/dist/{chunk-44YGZVBS.js.map → chunk-QMWMJVTX.js.map} +0 -0
- /package/dist/{chunk-VBRJ2OPM.js.map → chunk-V3NVAVHV.js.map} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { cleanup, render, screen } from '@test';
|
|
2
2
|
import { afterEach, beforeEach, describe, expect, it } from 'vitest';
|
|
3
3
|
|
|
4
4
|
import { server } from '@test';
|
|
@@ -46,9 +46,7 @@ describe('BuyModal', () => {
|
|
|
46
46
|
// },
|
|
47
47
|
// });
|
|
48
48
|
// render(
|
|
49
|
-
// <WebSdkWrapper>
|
|
50
49
|
// <BuyModal />
|
|
51
|
-
// </WebSdkWrapper>
|
|
52
50
|
// );
|
|
53
51
|
// // Should show error modal
|
|
54
52
|
// await waitFor(() => {
|
|
@@ -98,11 +96,7 @@ describe('BuyModal', () => {
|
|
|
98
96
|
},
|
|
99
97
|
});
|
|
100
98
|
|
|
101
|
-
render(
|
|
102
|
-
<WebSdkWrapper>
|
|
103
|
-
<BuyModal />
|
|
104
|
-
</WebSdkWrapper>,
|
|
105
|
-
);
|
|
99
|
+
render(<BuyModal />);
|
|
106
100
|
|
|
107
101
|
// Should show loading modal
|
|
108
102
|
expect(screen.getByText('Loading Sequence Pay')).toBeInTheDocument();
|
|
@@ -1,166 +1,103 @@
|
|
|
1
|
-
import { cleanup,
|
|
1
|
+
import { cleanup, render, renderHook, screen, waitFor } from '@test';
|
|
2
|
+
import { TEST_COLLECTIBLE } from '@test/const';
|
|
3
|
+
import { createMockWallet } from '@test/mocks/wallet';
|
|
2
4
|
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
3
|
-
import {
|
|
5
|
+
import { useSellModal } from '..';
|
|
6
|
+
import { StepType, WalletKind } from '../../../../_internal';
|
|
7
|
+
import { createMockStep } from '../../../../_internal/api/__mocks__/marketplace.msw';
|
|
8
|
+
import { mockOrder } from '../../../../_internal/api/__mocks__/marketplace.msw';
|
|
9
|
+
import * as walletModule from '../../../../_internal/wallet/useWallet';
|
|
4
10
|
import { SellModal } from '../Modal';
|
|
5
|
-
import
|
|
11
|
+
import * as useGetTokenApprovalDataModule from '../hooks/useGetTokenApproval';
|
|
6
12
|
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import { mockMarketplaceEndpoint } from '../../../../_internal/api/__mocks__/marketplace.msw';
|
|
12
|
-
import { useSell } from '../hooks/useSell';
|
|
13
|
-
|
|
14
|
-
// Test data
|
|
15
|
-
const mockOrder = {
|
|
16
|
-
orderId: '1',
|
|
17
|
-
priceAmount: '1000000000000000000',
|
|
18
|
-
priceCurrencyAddress: '0x0',
|
|
19
|
-
quantityRemaining: '1',
|
|
20
|
-
createdAt: new Date().toISOString(),
|
|
21
|
-
marketplace: MarketplaceKind.sequence_marketplace_v2,
|
|
22
|
-
} as Order;
|
|
23
|
-
|
|
24
|
-
const mockModalProps = {
|
|
25
|
-
collectionAddress: '0x123',
|
|
26
|
-
chainId: 1,
|
|
27
|
-
tokenId: '1',
|
|
13
|
+
const defaultArgs = {
|
|
14
|
+
collectionAddress: TEST_COLLECTIBLE.collectionAddress,
|
|
15
|
+
chainId: TEST_COLLECTIBLE.chainId,
|
|
16
|
+
tokenId: TEST_COLLECTIBLE.collectibleId,
|
|
28
17
|
order: mockOrder,
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
// TODO: remove when there is mocks for more endpoints
|
|
32
|
-
vi.mock(import('../../../../hooks'), async (importOriginal) => {
|
|
33
|
-
const mod = await importOriginal();
|
|
34
|
-
return {
|
|
35
|
-
...mod,
|
|
36
|
-
useCollection: vi.fn().mockImplementation(mod.useCollection),
|
|
37
|
-
useCurrency: vi.fn().mockImplementation(mod.useCurrency),
|
|
38
|
-
};
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
vi.mock('@0xsequence/kit', () => ({
|
|
42
|
-
useWaasFeeOptions: vi.fn().mockReturnValue([]),
|
|
43
|
-
}));
|
|
44
|
-
|
|
45
|
-
beforeEach(() => {
|
|
46
|
-
cleanup();
|
|
47
|
-
vi.clearAllMocks();
|
|
48
|
-
vi.mock('../hooks/useSell', () => ({
|
|
49
|
-
useSell: vi.fn().mockReturnValue({
|
|
50
|
-
isLoading: false,
|
|
51
|
-
executeApproval: vi.fn(),
|
|
52
|
-
sell: vi.fn(),
|
|
53
|
-
}),
|
|
54
|
-
}));
|
|
55
|
-
});
|
|
18
|
+
};
|
|
56
19
|
|
|
57
|
-
describe
|
|
58
|
-
|
|
59
|
-
render(<SellModal />);
|
|
60
|
-
expect(screen.queryByText('You have an offer')).toBeNull();
|
|
61
|
-
});
|
|
20
|
+
describe('MakeOfferModal', () => {
|
|
21
|
+
const mockWallet = createMockWallet();
|
|
62
22
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
);
|
|
70
|
-
sellModal$.open(mockModalProps);
|
|
71
|
-
render(<SellModal />);
|
|
72
|
-
const errorModal = await screen.findByTestId('error-modal');
|
|
73
|
-
expect(errorModal).toBeVisible();
|
|
23
|
+
beforeEach(() => {
|
|
24
|
+
cleanup();
|
|
25
|
+
// Reset all mocks
|
|
26
|
+
vi.clearAllMocks();
|
|
27
|
+
vi.resetAllMocks();
|
|
28
|
+
vi.restoreAllMocks();
|
|
74
29
|
});
|
|
75
30
|
|
|
76
|
-
it
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
31
|
+
it('should show main button if there is no approval step', async () => {
|
|
32
|
+
// Mock sequence wallet
|
|
33
|
+
const sequenceWallet = {
|
|
34
|
+
...mockWallet,
|
|
35
|
+
walletKind: WalletKind.sequence,
|
|
36
|
+
};
|
|
37
|
+
vi.spyOn(walletModule, 'useWallet').mockReturnValue({
|
|
38
|
+
wallet: sequenceWallet,
|
|
80
39
|
isLoading: false,
|
|
81
40
|
isError: false,
|
|
82
41
|
});
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
42
|
+
vi.spyOn(
|
|
43
|
+
useGetTokenApprovalDataModule,
|
|
44
|
+
'useGetTokenApprovalData',
|
|
45
|
+
).mockReturnValue({
|
|
46
|
+
data: {
|
|
47
|
+
step: null,
|
|
48
|
+
},
|
|
87
49
|
isLoading: false,
|
|
88
|
-
|
|
50
|
+
isSuccess: true,
|
|
89
51
|
});
|
|
90
52
|
|
|
91
|
-
|
|
53
|
+
// Render the modal
|
|
54
|
+
const { result } = renderHook(() => useSellModal());
|
|
55
|
+
result.current.show(defaultArgs);
|
|
56
|
+
|
|
92
57
|
render(<SellModal />);
|
|
93
|
-
|
|
94
|
-
|
|
58
|
+
|
|
59
|
+
// Wait for the component to update
|
|
60
|
+
await waitFor(() => {
|
|
61
|
+
// The Approve TOKEN button should not exist
|
|
62
|
+
expect(screen.queryByText('Approve TOKEN')).toBeNull();
|
|
63
|
+
|
|
64
|
+
// The Accept button should exist
|
|
65
|
+
expect(screen.getByRole('button', { name: 'Accept' })).toBeDefined();
|
|
66
|
+
});
|
|
95
67
|
});
|
|
96
|
-
});
|
|
97
68
|
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
},
|
|
69
|
+
it('(non-sequence wallets) should show approve token button if there is an approval step, disable main button', async () => {
|
|
70
|
+
const nonSequenceWallet = {
|
|
71
|
+
...mockWallet,
|
|
72
|
+
walletKind: 'unknown' as WalletKind,
|
|
73
|
+
};
|
|
74
|
+
vi.spyOn(walletModule, 'useWallet').mockReturnValue({
|
|
75
|
+
wallet: nonSequenceWallet,
|
|
106
76
|
isLoading: false,
|
|
107
77
|
isError: false,
|
|
108
78
|
});
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
79
|
+
vi.spyOn(
|
|
80
|
+
useGetTokenApprovalDataModule,
|
|
81
|
+
'useGetTokenApprovalData',
|
|
82
|
+
).mockReturnValue({
|
|
112
83
|
data: {
|
|
113
|
-
|
|
114
|
-
imageUrl: 'test-url',
|
|
84
|
+
step: createMockStep(StepType.tokenApproval),
|
|
115
85
|
},
|
|
116
86
|
isLoading: false,
|
|
117
|
-
|
|
87
|
+
isSuccess: true,
|
|
118
88
|
});
|
|
119
89
|
|
|
120
|
-
|
|
90
|
+
// Render the modal
|
|
91
|
+
const { result } = renderHook(() => useSellModal());
|
|
92
|
+
result.current.show(defaultArgs);
|
|
121
93
|
|
|
122
|
-
// biome-ignore lint/suspicious/noExplicitAny: <explanation>
|
|
123
|
-
(useSell as any).mockReturnValue({
|
|
124
|
-
isLoading: false,
|
|
125
|
-
executeApproval: mockExecuteApproval,
|
|
126
|
-
sell: vi.fn(),
|
|
127
|
-
});
|
|
128
|
-
|
|
129
|
-
sellModal$.open({
|
|
130
|
-
...mockModalProps,
|
|
131
|
-
order: {
|
|
132
|
-
...mockOrder,
|
|
133
|
-
quantityRemaining: '1',
|
|
134
|
-
},
|
|
135
|
-
});
|
|
136
|
-
sellModal$.steps.approval.exist.set(true);
|
|
137
|
-
sellModal$.steps.approval.isExecuting.set(false);
|
|
138
|
-
sellModal$.steps.transaction.isExecuting.set(false);
|
|
139
94
|
render(<SellModal />);
|
|
140
95
|
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
fireEvent.click(approveButton);
|
|
144
|
-
expect(mockExecuteApproval).toHaveBeenCalled();
|
|
145
|
-
});
|
|
146
|
-
});
|
|
96
|
+
await waitFor(() => {
|
|
97
|
+
expect(screen.getByText('Approve TOKEN')).toBeDefined();
|
|
147
98
|
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
(useSell as any).mockReturnValue({
|
|
152
|
-
isLoading: false,
|
|
153
|
-
executeApproval: vi.fn(),
|
|
154
|
-
sell: mockSell,
|
|
99
|
+
expect(screen.getByRole('button', { name: 'Accept' })).toBeDefined();
|
|
100
|
+
expect(screen.getByRole('button', { name: 'Accept' })).toBeDisabled();
|
|
101
|
+
});
|
|
155
102
|
});
|
|
156
|
-
|
|
157
|
-
sellModal$.open(mockModalProps);
|
|
158
|
-
sellModal$.steps.approval.exist.set(false);
|
|
159
|
-
sellModal$.steps.approval.isExecuting.set(false);
|
|
160
|
-
sellModal$.steps.transaction.isExecuting.set(false);
|
|
161
|
-
render(<SellModal />);
|
|
162
|
-
|
|
163
|
-
const acceptButton = screen.getByText('Accept');
|
|
164
|
-
fireEvent.click(acceptButton);
|
|
165
|
-
expect(mockSell).toHaveBeenCalled();
|
|
166
103
|
});
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { fireEvent, render, screen } from '@test';
|
|
4
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import ActionButtons from '../_components/ActionButtons';
|
|
6
|
+
|
|
7
|
+
describe('ActionButtons', () => {
|
|
8
|
+
const mockOnCancel = vi.fn();
|
|
9
|
+
const mockOnConfirm = vi.fn();
|
|
10
|
+
|
|
11
|
+
const defaultProps = {
|
|
12
|
+
onCancel: mockOnCancel,
|
|
13
|
+
onConfirm: mockOnConfirm,
|
|
14
|
+
disabled: false,
|
|
15
|
+
loading: false,
|
|
16
|
+
confirmed: false,
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
beforeEach(() => {
|
|
20
|
+
vi.clearAllMocks();
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
it('should render both buttons', () => {
|
|
24
|
+
render(<ActionButtons {...defaultProps} />);
|
|
25
|
+
|
|
26
|
+
expect(screen.getByText('Cancel')).toBeInTheDocument();
|
|
27
|
+
expect(screen.getByText('Continue with')).toBeInTheDocument();
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('should call onCancel when cancel button is clicked', () => {
|
|
31
|
+
render(<ActionButtons {...defaultProps} />);
|
|
32
|
+
|
|
33
|
+
const cancelButton = screen.getByText('Cancel');
|
|
34
|
+
fireEvent.click(cancelButton);
|
|
35
|
+
|
|
36
|
+
expect(mockOnCancel).toHaveBeenCalledTimes(1);
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('should call onConfirm when confirm button is clicked', () => {
|
|
40
|
+
render(<ActionButtons {...defaultProps} />);
|
|
41
|
+
|
|
42
|
+
const confirmButton = screen.getByText('Continue with');
|
|
43
|
+
fireEvent.click(confirmButton);
|
|
44
|
+
|
|
45
|
+
expect(mockOnConfirm).toHaveBeenCalledTimes(1);
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
it('should disable confirm button when disabled prop is true', () => {
|
|
49
|
+
render(<ActionButtons {...defaultProps} disabled={true} />);
|
|
50
|
+
|
|
51
|
+
const confirmButton = screen.getByText('Continue with').closest('button');
|
|
52
|
+
expect(confirmButton).toBeDisabled();
|
|
53
|
+
|
|
54
|
+
if (confirmButton) {
|
|
55
|
+
fireEvent.click(confirmButton);
|
|
56
|
+
}
|
|
57
|
+
expect(mockOnConfirm).not.toHaveBeenCalled();
|
|
58
|
+
});
|
|
59
|
+
|
|
60
|
+
it('should display token symbol when provided', () => {
|
|
61
|
+
render(<ActionButtons {...defaultProps} tokenSymbol="ETH" />);
|
|
62
|
+
|
|
63
|
+
expect(screen.getByText('Continue with ETH')).toBeInTheDocument();
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it('should show skeleton loading when tokenSymbol is not provided', () => {
|
|
67
|
+
render(<ActionButtons {...defaultProps} />);
|
|
68
|
+
|
|
69
|
+
expect(screen.getByText('Continue with')).toBeInTheDocument();
|
|
70
|
+
expect(document.querySelector('.animate-shimmer')).toBeInTheDocument();
|
|
71
|
+
});
|
|
72
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
import { render, screen } from '@test';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import BalanceIndicator from '../_components/BalanceIndicator';
|
|
6
|
+
|
|
7
|
+
describe('BalanceIndicator', () => {
|
|
8
|
+
it('should render warning icon and negative text when insufficient balance', () => {
|
|
9
|
+
render(
|
|
10
|
+
<BalanceIndicator
|
|
11
|
+
insufficientBalance={true}
|
|
12
|
+
currencyBalance={{ formatted: '0.5' }}
|
|
13
|
+
selectedFeeOption={{ token: { symbol: 'ETH' } }}
|
|
14
|
+
/>,
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
expect(document.querySelector('.text-negative')).toBeInTheDocument();
|
|
18
|
+
expect(screen.getByText('You have 0.5 ETH')).toBeInTheDocument();
|
|
19
|
+
expect(screen.getByText('You have 0.5 ETH').className).toContain(
|
|
20
|
+
'text-negative',
|
|
21
|
+
);
|
|
22
|
+
});
|
|
23
|
+
|
|
24
|
+
it('should render checkmark icon and normal text when balance is sufficient', () => {
|
|
25
|
+
render(
|
|
26
|
+
<BalanceIndicator
|
|
27
|
+
insufficientBalance={false}
|
|
28
|
+
currencyBalance={{ formatted: '1.5' }}
|
|
29
|
+
selectedFeeOption={{ token: { symbol: 'ETH' } }}
|
|
30
|
+
/>,
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
expect(document.querySelector('.text-positive')).toBeInTheDocument();
|
|
34
|
+
expect(screen.getByText('You have 1.5 ETH')).toBeInTheDocument();
|
|
35
|
+
expect(screen.getByText('You have 1.5 ETH').className).not.toContain(
|
|
36
|
+
'text-negative',
|
|
37
|
+
);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
it('should handle undefined currencyBalance gracefully', () => {
|
|
41
|
+
render(
|
|
42
|
+
<BalanceIndicator
|
|
43
|
+
insufficientBalance={false}
|
|
44
|
+
selectedFeeOption={{ token: { symbol: 'ETH' } }}
|
|
45
|
+
/>,
|
|
46
|
+
);
|
|
47
|
+
|
|
48
|
+
expect(screen.getByText('You have 0 ETH')).toBeInTheDocument();
|
|
49
|
+
});
|
|
50
|
+
});
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
import { TokenType } from '@0xsequence/api';
|
|
2
|
+
import * as useNetworkModule from '@0xsequence/connect';
|
|
3
|
+
import * as useWaasFeeOptionsModule from '@0xsequence/connect';
|
|
4
|
+
import { NetworkType } from '@0xsequence/network';
|
|
5
|
+
import { observable } from '@legendapp/state';
|
|
6
|
+
import { render, screen } from '@test';
|
|
7
|
+
import { TEST_CURRENCY } from '@test/const';
|
|
8
|
+
import { beforeEach, describe, expect, it, vi } from 'vitest';
|
|
9
|
+
import SelectWaasFeeOptions from '..';
|
|
10
|
+
import type {
|
|
11
|
+
FeeOption,
|
|
12
|
+
FeeOptionExtended,
|
|
13
|
+
WaasFeeOptionConfirmation,
|
|
14
|
+
} from '../../../../../../../types/waas-types';
|
|
15
|
+
import { selectWaasFeeOptions$ } from '../store';
|
|
16
|
+
import * as useWaasFeeOptionManagerModule from '../useWaasFeeOptionManager';
|
|
17
|
+
|
|
18
|
+
const mockFeeOption: FeeOptionExtended = {
|
|
19
|
+
gasLimit: 21000,
|
|
20
|
+
to: '0x123',
|
|
21
|
+
value: '1000000000000000',
|
|
22
|
+
token: {
|
|
23
|
+
chainId: 1,
|
|
24
|
+
contractAddress: TEST_CURRENCY.contractAddress,
|
|
25
|
+
decimals: TEST_CURRENCY.decimals,
|
|
26
|
+
logoURL: TEST_CURRENCY.imageUrl,
|
|
27
|
+
name: TEST_CURRENCY.name,
|
|
28
|
+
symbol: TEST_CURRENCY.symbol,
|
|
29
|
+
tokenID: null,
|
|
30
|
+
type: TokenType.ERC20,
|
|
31
|
+
},
|
|
32
|
+
balance: '1000000000000000',
|
|
33
|
+
balanceFormatted: '1',
|
|
34
|
+
hasEnoughBalanceForFee: true,
|
|
35
|
+
};
|
|
36
|
+
|
|
37
|
+
const mockPendingFeeOptionConfirmation: WaasFeeOptionConfirmation = {
|
|
38
|
+
id: 'fee-confirmation-id',
|
|
39
|
+
options: [mockFeeOption],
|
|
40
|
+
chainId: 1,
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
// Mock currency balance with formatted value
|
|
44
|
+
const mockCurrencyBalance = {
|
|
45
|
+
value: 2000000000000000n,
|
|
46
|
+
formatted: '0.002',
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
describe('SelectWaasFeeOptions', () => {
|
|
50
|
+
const mockOnCancel = vi.fn();
|
|
51
|
+
const mockHandleConfirmFeeOption = vi.fn();
|
|
52
|
+
|
|
53
|
+
beforeEach(() => {
|
|
54
|
+
vi.resetAllMocks();
|
|
55
|
+
vi.resetModules();
|
|
56
|
+
|
|
57
|
+
selectWaasFeeOptions$.isVisible.set(true);
|
|
58
|
+
selectWaasFeeOptions$.selectedFeeOption.set(undefined);
|
|
59
|
+
selectWaasFeeOptions$.pendingFeeOptionConfirmation.set(undefined);
|
|
60
|
+
});
|
|
61
|
+
|
|
62
|
+
it('should not render when isVisible is false', () => {
|
|
63
|
+
vi.spyOn(useWaasFeeOptionManagerModule, 'default').mockReturnValue({
|
|
64
|
+
selectedFeeOption$: observable<FeeOptionExtended | undefined>(
|
|
65
|
+
mockFeeOption,
|
|
66
|
+
),
|
|
67
|
+
selectedFeeOption: mockFeeOption,
|
|
68
|
+
// @ts-expect-error - types are not compatible
|
|
69
|
+
pendingFeeOptionConfirmation: mockPendingFeeOptionConfirmation,
|
|
70
|
+
currencyBalance: mockCurrencyBalance,
|
|
71
|
+
currencyBalanceLoading: false,
|
|
72
|
+
insufficientBalance: false,
|
|
73
|
+
feeOptionsConfirmed: false,
|
|
74
|
+
handleConfirmFeeOption: mockHandleConfirmFeeOption,
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
// Set isVisible to false
|
|
78
|
+
selectWaasFeeOptions$.isVisible.set(false);
|
|
79
|
+
|
|
80
|
+
const { container } = render(
|
|
81
|
+
<SelectWaasFeeOptions chainId={1} onCancel={mockOnCancel} />,
|
|
82
|
+
);
|
|
83
|
+
|
|
84
|
+
expect(container.firstChild).toBeNull();
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('should not render on testnet', () => {
|
|
88
|
+
vi.spyOn(useWaasFeeOptionManagerModule, 'default').mockReturnValue({
|
|
89
|
+
selectedFeeOption$: observable<FeeOption | undefined>(mockFeeOption),
|
|
90
|
+
selectedFeeOption: mockFeeOption,
|
|
91
|
+
// @ts-expect-error - types are not compatible
|
|
92
|
+
pendingFeeOptionConfirmation: mockPendingFeeOptionConfirmation,
|
|
93
|
+
currencyBalance: mockCurrencyBalance,
|
|
94
|
+
currencyBalanceLoading: false,
|
|
95
|
+
insufficientBalance: false,
|
|
96
|
+
feeOptionsConfirmed: false,
|
|
97
|
+
handleConfirmFeeOption: mockHandleConfirmFeeOption,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
vi.spyOn(useNetworkModule, 'getNetwork').mockReturnValue({
|
|
101
|
+
type: NetworkType.TESTNET,
|
|
102
|
+
chainId: 1,
|
|
103
|
+
name: 'Testnet',
|
|
104
|
+
nativeToken: TEST_CURRENCY,
|
|
105
|
+
});
|
|
106
|
+
vi.spyOn(useWaasFeeOptionsModule, 'useWaasFeeOptions').mockReturnValue([
|
|
107
|
+
// @ts-expect-error - types are not compatible
|
|
108
|
+
mockPendingFeeOptionConfirmation,
|
|
109
|
+
vi.fn(),
|
|
110
|
+
]);
|
|
111
|
+
|
|
112
|
+
const { container } = render(
|
|
113
|
+
<SelectWaasFeeOptions chainId={1} onCancel={mockOnCancel} />,
|
|
114
|
+
);
|
|
115
|
+
|
|
116
|
+
expect(container.firstChild).toBeNull();
|
|
117
|
+
});
|
|
118
|
+
|
|
119
|
+
it('should render loading skeleton when fee options are loading', () => {
|
|
120
|
+
// Mock the hook with loading state
|
|
121
|
+
vi.spyOn(useWaasFeeOptionManagerModule, 'default').mockReturnValue({
|
|
122
|
+
selectedFeeOption$: observable<FeeOption | undefined>(undefined),
|
|
123
|
+
selectedFeeOption: mockFeeOption,
|
|
124
|
+
pendingFeeOptionConfirmation: undefined,
|
|
125
|
+
currencyBalance: undefined,
|
|
126
|
+
currencyBalanceLoading: true,
|
|
127
|
+
insufficientBalance: false,
|
|
128
|
+
feeOptionsConfirmed: false,
|
|
129
|
+
handleConfirmFeeOption: mockHandleConfirmFeeOption,
|
|
130
|
+
});
|
|
131
|
+
vi.spyOn(useWaasFeeOptionsModule, 'useWaasFeeOptions').mockReturnValue([
|
|
132
|
+
// @ts-expect-error - types are not compatible
|
|
133
|
+
mockPendingFeeOptionConfirmation,
|
|
134
|
+
vi.fn(),
|
|
135
|
+
]);
|
|
136
|
+
vi.spyOn(useNetworkModule, 'getNetwork').mockReturnValue({
|
|
137
|
+
type: NetworkType.MAINNET,
|
|
138
|
+
chainId: 1,
|
|
139
|
+
name: 'Mainnet',
|
|
140
|
+
nativeToken: TEST_CURRENCY,
|
|
141
|
+
});
|
|
142
|
+
|
|
143
|
+
render(<SelectWaasFeeOptions chainId={1} onCancel={mockOnCancel} />);
|
|
144
|
+
|
|
145
|
+
expect(screen.getByText('Select a fee option')).toBeInTheDocument();
|
|
146
|
+
|
|
147
|
+
// Should render skeleton
|
|
148
|
+
const skeleton = document.querySelector('.h-\\[52px\\]');
|
|
149
|
+
expect(skeleton).toBeInTheDocument();
|
|
150
|
+
expect(skeleton).toHaveClass('animate-shimmer');
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
it('should render fee options when loaded', () => {
|
|
154
|
+
selectWaasFeeOptions$.pendingFeeOptionConfirmation.set(
|
|
155
|
+
mockPendingFeeOptionConfirmation,
|
|
156
|
+
);
|
|
157
|
+
selectWaasFeeOptions$.selectedFeeOption.set(mockFeeOption);
|
|
158
|
+
|
|
159
|
+
vi.spyOn(useWaasFeeOptionManagerModule, 'default').mockReturnValue({
|
|
160
|
+
selectedFeeOption$: selectWaasFeeOptions$.selectedFeeOption,
|
|
161
|
+
selectedFeeOption: mockFeeOption,
|
|
162
|
+
// @ts-expect-error - types are not compatible
|
|
163
|
+
pendingFeeOptionConfirmation: mockPendingFeeOptionConfirmation,
|
|
164
|
+
currencyBalance: mockCurrencyBalance,
|
|
165
|
+
currencyBalanceLoading: false,
|
|
166
|
+
insufficientBalance: false,
|
|
167
|
+
feeOptionsConfirmed: false,
|
|
168
|
+
handleConfirmFeeOption: mockHandleConfirmFeeOption,
|
|
169
|
+
});
|
|
170
|
+
vi.spyOn(useWaasFeeOptionsModule, 'useWaasFeeOptions').mockReturnValue([
|
|
171
|
+
// @ts-expect-error - types are not compatible
|
|
172
|
+
mockPendingFeeOptionConfirmation,
|
|
173
|
+
vi.fn(),
|
|
174
|
+
]);
|
|
175
|
+
vi.spyOn(useNetworkModule, 'getNetwork').mockReturnValue({
|
|
176
|
+
type: NetworkType.MAINNET,
|
|
177
|
+
chainId: 1,
|
|
178
|
+
name: 'Mainnet',
|
|
179
|
+
nativeToken: TEST_CURRENCY,
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
render(
|
|
183
|
+
<SelectWaasFeeOptions
|
|
184
|
+
chainId={1}
|
|
185
|
+
onCancel={mockOnCancel}
|
|
186
|
+
titleOnConfirm="Confirm fee option"
|
|
187
|
+
/>,
|
|
188
|
+
);
|
|
189
|
+
|
|
190
|
+
expect(screen.getByText('Select a fee option')).toBeInTheDocument();
|
|
191
|
+
expect(screen.queryByText('Confirm fee option')).not.toBeInTheDocument();
|
|
192
|
+
});
|
|
193
|
+
});
|