@0xsequence/marketplace-sdk 0.8.4 → 0.8.5

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 (56) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/{chunk-25CAMYCG.js → chunk-BB2PTJHI.js} +22 -20
  3. package/dist/chunk-BB2PTJHI.js.map +1 -0
  4. package/dist/{chunk-VBRJ2OPM.js → chunk-EZFCQZHU.js} +2 -2
  5. package/dist/{chunk-VF3LWBQB.js → chunk-KCLMSSPS.js} +6 -6
  6. package/dist/{chunk-XUNDLCEH.js → chunk-LDZZUYG7.js} +2 -2
  7. package/dist/{chunk-HRL2TMXU.js → chunk-SFSFIGHM.js} +44 -34
  8. package/dist/{chunk-HRL2TMXU.js.map → chunk-SFSFIGHM.js.map} +1 -1
  9. package/dist/{chunk-44YGZVBS.js → chunk-ZVTG6US2.js} +2 -2
  10. package/dist/index.css +4 -4
  11. package/dist/index.css.map +1 -1
  12. package/dist/index.js +6 -6
  13. package/dist/react/_internal/databeat/index.js +5 -5
  14. package/dist/react/_internal/index.d.ts +1 -1
  15. package/dist/react/_internal/index.js +3 -1
  16. package/dist/react/_internal/wagmi/index.d.ts +3 -2
  17. package/dist/react/_internal/wagmi/index.js +3 -1
  18. package/dist/react/hooks/index.js +4 -4
  19. package/dist/react/hooks/options/index.js +2 -2
  20. package/dist/react/index.js +7 -7
  21. package/dist/react/queries/index.js +1 -1
  22. package/dist/react/ssr/index.js +1 -1
  23. package/dist/react/ui/components/collectible-card/index.d.ts +3 -2
  24. package/dist/react/ui/components/collectible-card/index.js +7 -7
  25. package/dist/react/ui/icons/index.js +2 -2
  26. package/dist/react/ui/index.js +7 -7
  27. package/dist/react/ui/modals/_internal/components/actionModal/index.js +5 -5
  28. package/dist/types/index.js +1 -1
  29. package/dist/utils/abi/index.js +5 -5
  30. package/dist/utils/index.js +6 -6
  31. package/package.json +19 -19
  32. package/src/react/_internal/wagmi/__tests__/create-config.test.ts +1 -11
  33. package/src/react/_internal/wagmi/get-connectors.ts +27 -24
  34. package/src/react/ui/components/_internals/action-button/__tests__/ActionButtonBody.test.tsx +27 -94
  35. package/src/react/ui/components/_internals/action-button/__tests__/NonOwnerActions.test.tsx +59 -0
  36. package/src/react/ui/components/_internals/action-button/__tests__/OwnerActions.test.tsx +73 -0
  37. package/src/react/ui/components/_internals/action-button/__tests__/useActionButtonLogic.test.tsx +77 -0
  38. package/src/react/ui/components/_internals/action-button/components/ActionButtonBody.tsx +3 -2
  39. package/src/react/ui/components/_internals/action-button/hooks/useActionButtonLogic.ts +4 -3
  40. package/src/react/ui/components/collectible-card/CollectibleAsset.tsx +1 -0
  41. package/src/react/ui/components/collectible-card/CollectibleCard.tsx +18 -12
  42. package/src/react/ui/components/collectible-card/__tests__/CollectibleAsset.test.tsx +200 -0
  43. package/src/react/ui/components/collectible-card/__tests__/CollectibleCard.test.tsx +92 -123
  44. package/src/react/ui/components/collectible-card/__tests__/Footer.test.tsx +136 -0
  45. package/src/react/ui/modals/BuyModal/__tests__/Modal.test.tsx +2 -8
  46. package/src/react/ui/modals/SellModal/__tests__/Modal.test.tsx +72 -135
  47. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/__tests__/ActionButtons.test.tsx +72 -0
  48. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/__tests__/BalanceIndicator.test.tsx +50 -0
  49. package/src/react/ui/modals/_internal/components/selectWaasFeeOptions/__tests__/SelectWaasFeeOptions.test.tsx +193 -0
  50. package/test/test-utils.tsx +12 -22
  51. package/dist/chunk-25CAMYCG.js.map +0 -1
  52. package/src/react/ui/components/_internals/action-button/__tests__/ActionButton.test.tsx +0 -107
  53. /package/dist/{chunk-VBRJ2OPM.js.map → chunk-EZFCQZHU.js.map} +0 -0
  54. /package/dist/{chunk-VF3LWBQB.js.map → chunk-KCLMSSPS.js.map} +0 -0
  55. /package/dist/{chunk-XUNDLCEH.js.map → chunk-LDZZUYG7.js.map} +0 -0
  56. /package/dist/{chunk-44YGZVBS.js.map → chunk-ZVTG6US2.js.map} +0 -0
@@ -0,0 +1,200 @@
1
+ import { render, screen } from '@test/test-utils';
2
+ import { describe, expect, it, vi } from 'vitest';
3
+ import type { TokenMetadata } from '../../../../_internal';
4
+ import { CollectibleAsset } from '../CollectibleAsset';
5
+
6
+ describe('CollectibleAsset', () => {
7
+ it('renders image content correctly with proper loading states and fallback', async () => {
8
+ const originalImage = window.Image;
9
+
10
+ // We need to use a proper constructor function to match the Image interface
11
+ const MockImage = function (this: HTMLImageElement) {
12
+ this.src = '';
13
+ this.alt = '';
14
+ this.className = '';
15
+ this.onload = null;
16
+ this.onerror = null;
17
+ return this;
18
+ } as unknown as typeof Image;
19
+
20
+ window.Image = MockImage;
21
+
22
+ const mockMetadata: Partial<TokenMetadata> = {
23
+ tokenId: '1',
24
+ name: 'Test Collectible',
25
+ image: 'https://example.com/test-image.png',
26
+ attributes: [],
27
+ };
28
+
29
+ // Initial render should show the loading skeleton
30
+ const { rerender } = render(
31
+ <CollectibleAsset
32
+ name="Test Collectible"
33
+ collectibleMetadata={mockMetadata as TokenMetadata}
34
+ />,
35
+ );
36
+
37
+ // check if skeleton is rendered during loading
38
+ const skeleton = screen.getByTestId('collectible-asset-skeleton');
39
+ expect(skeleton).toBeInTheDocument();
40
+
41
+ // trigger the image load event to simulate successful loading
42
+ const imgElement = document.querySelector('img');
43
+ expect(imgElement).not.toBeNull();
44
+
45
+ if (imgElement) {
46
+ expect(imgElement.getAttribute('src')).toBe(
47
+ 'https://example.com/test-image.png',
48
+ );
49
+ expect(imgElement.getAttribute('alt')).toBe('Test Collectible');
50
+
51
+ // initial state should be invisible due to loading
52
+ expect(imgElement.className).toContain('invisible');
53
+
54
+ // successful image load
55
+ imgElement.dispatchEvent(new Event('load'));
56
+
57
+ // after loading, the image should be visible
58
+ expect(imgElement.className).toContain('visible');
59
+ }
60
+
61
+ // failing image that should use fallback
62
+ const mockMetadataWithBadImage: Partial<TokenMetadata> = {
63
+ tokenId: '1',
64
+ name: 'Test Collectible',
65
+ image: 'https://example.com/bad-image.png',
66
+ attributes: [],
67
+ };
68
+
69
+ rerender(
70
+ <CollectibleAsset
71
+ name="Test Collectible"
72
+ collectibleMetadata={mockMetadataWithBadImage as TokenMetadata}
73
+ />,
74
+ );
75
+
76
+ const updatedImgElement = document.querySelector('img');
77
+ if (updatedImgElement) {
78
+ // simulate image load error
79
+ updatedImgElement.dispatchEvent(new Event('error'));
80
+
81
+ // after error, the src should be changed to the placeholder
82
+ expect(updatedImgElement.className).toContain('visible');
83
+ }
84
+
85
+ // restore the original Image implementation
86
+ window.Image = originalImage;
87
+ });
88
+
89
+ it('handles video content with appropriate controls and loading states', () => {
90
+ // Create a mock for the HTMLVideoElement addEventListener
91
+ const originalAddEventListener =
92
+ HTMLVideoElement.prototype.addEventListener;
93
+ HTMLVideoElement.prototype.addEventListener = vi.fn(
94
+ (event: string, handler: EventListenerOrEventListenerObject) => {
95
+ // Immediately call the loadedmetadata handler to simulate video loaded
96
+ if (event === 'loadedmetadata' && typeof handler === 'function') {
97
+ handler(new Event('loadedmetadata'));
98
+ }
99
+ },
100
+ );
101
+
102
+ // Mock browser detection for Safari
103
+ const originalUserAgent = navigator.userAgent;
104
+ Object.defineProperty(navigator, 'userAgent', {
105
+ value:
106
+ 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/15.1 Safari/605.1.15',
107
+ configurable: true,
108
+ });
109
+
110
+ // Mock video metadata
111
+ const mockVideoMetadata: Partial<TokenMetadata> = {
112
+ tokenId: '1',
113
+ name: 'Video Collectible',
114
+ video: 'https://example.com/video.mp4',
115
+ attributes: [],
116
+ };
117
+
118
+ render(
119
+ <CollectibleAsset
120
+ name="Video Collectible"
121
+ collectibleMetadata={mockVideoMetadata as TokenMetadata}
122
+ />,
123
+ );
124
+
125
+ // Check that video element is present with correct attributes
126
+ const videoElement = document.querySelector('video');
127
+ expect(videoElement).not.toBeNull();
128
+
129
+ if (videoElement) {
130
+ // Video source should be set correctly
131
+ const sourceElement = videoElement.querySelector('source');
132
+ expect(sourceElement).not.toBeNull();
133
+ expect(sourceElement?.getAttribute('src')).toBe(
134
+ 'https://example.com/video.mp4',
135
+ );
136
+
137
+ // Video should have correct attributes for NFT display
138
+ expect(videoElement.autoplay).toBe(true);
139
+ expect(videoElement.loop).toBe(true);
140
+ expect(videoElement.controls).toBe(true);
141
+ expect(videoElement.playsInline).toBe(true);
142
+ expect(videoElement.muted).toBe(true);
143
+
144
+ // In Safari, pointer-events-none should be applied
145
+ expect(videoElement.className).toContain('pointer-events-none');
146
+
147
+ // After metadata loaded, video should be visible
148
+ expect(videoElement.className).toContain('visible');
149
+ expect(videoElement.className).not.toContain('invisible');
150
+ }
151
+
152
+ // Clean up mocks
153
+ HTMLVideoElement.prototype.addEventListener = originalAddEventListener;
154
+ Object.defineProperty(navigator, 'userAgent', {
155
+ value: originalUserAgent,
156
+ configurable: true,
157
+ });
158
+ });
159
+
160
+ it('handles HTML content in iframes with proper sandboxing', () => {
161
+ // Mock HTML content metadata
162
+ const mockHtmlMetadata: Partial<TokenMetadata> = {
163
+ tokenId: '1',
164
+ name: 'HTML Collectible',
165
+ animation_url: 'https://example.com/interactive.html',
166
+ attributes: [],
167
+ };
168
+
169
+ render(
170
+ <CollectibleAsset
171
+ name="HTML Collectible"
172
+ collectibleMetadata={mockHtmlMetadata as TokenMetadata}
173
+ />,
174
+ );
175
+
176
+ // Check that iframe element is present with correct attributes
177
+ const iframeElement = document.querySelector('iframe');
178
+ expect(iframeElement).not.toBeNull();
179
+
180
+ if (iframeElement) {
181
+ // iframe source should be set correctly
182
+ expect(iframeElement.getAttribute('src')).toBe(
183
+ 'https://example.com/interactive.html',
184
+ );
185
+
186
+ // iframe should have appropriate attributes for security
187
+ expect(iframeElement.getAttribute('sandbox')).toBe('allow-scripts');
188
+
189
+ // iframe should have title for accessibility
190
+ expect(iframeElement.getAttribute('title')).toBe('HTML Collectible');
191
+
192
+ // iframe should have proper styling
193
+ expect(iframeElement.className).toContain('aspect-square');
194
+ expect(iframeElement.className).toContain('w-full');
195
+
196
+ // Verify border styling
197
+ expect(iframeElement.style.border).toBe('0px');
198
+ }
199
+ });
200
+ });
@@ -1,125 +1,94 @@
1
- import { describe } from 'vitest';
1
+ import { TEST_COLLECTIBLE, TEST_CURRENCY } from '@test/const';
2
+ import { fireEvent, render, screen } from '@test/test-utils';
3
+ import { beforeEach, describe, expect, it, vi } from 'vitest';
4
+ import {
5
+ type CollectibleOrder,
6
+ ContractType,
7
+ OrderSide,
8
+ OrderbookKind,
9
+ } from '../../../../_internal';
10
+ import { mockTokenMetadata } from '../../../../_internal/api/__mocks__/indexer.msw';
11
+ import { mockOrder } from '../../../../_internal/api/__mocks__/marketplace.msw';
12
+ import * as hooks from '../../../../hooks';
13
+ import { CollectibleCard } from '../CollectibleCard';
2
14
 
3
- describe.skip('CollectibleCard', () => {
4
- // // Create a mock order that follows the Order interface
5
- // const mockOrder: Order = {
6
- // orderId: '1',
7
- // marketplace: MarketplaceKind.sequence_marketplace_v2,
8
- // side: OrderSide.listing,
9
- // status: OrderStatus.active,
10
- // chainId: 1,
11
- // originName: 'test marketplace',
12
- // collectionContractAddress: '0x1234567890123456789012345678901234567890',
13
- // tokenId: '123',
14
- // createdBy: '0x0000000000000000000000000000000000000000',
15
- // priceAmount: '1000000',
16
- // priceAmountFormatted: '1',
17
- // priceAmountNet: '1000000',
18
- // priceAmountNetFormatted: '1',
19
- // priceCurrencyAddress: USDC_ADDRESS,
20
- // priceDecimals: 6,
21
- // priceUSD: 1,
22
- // priceUSDFormatted: '1',
23
- // quantityInitial: '1',
24
- // quantityInitialFormatted: '1',
25
- // quantityRemaining: '1',
26
- // quantityRemainingFormatted: '1',
27
- // quantityAvailable: '1',
28
- // quantityAvailableFormatted: '1',
29
- // quantityDecimals: 0,
30
- // feeBps: 250,
31
- // feeBreakdown: [],
32
- // validFrom: new Date().toISOString(),
33
- // validUntil: new Date(Date.now() + 86400000).toISOString(),
34
- // blockNumber: 1,
35
- // createdAt: new Date().toISOString(),
36
- // updatedAt: new Date().toISOString(),
37
- // };
38
- // const defaultProps = {
39
- // collectibleId: '123',
40
- // chainId: 1,
41
- // collectionAddress:
42
- // '0x1234567890123456789012345678901234567890' as `0x${string}`,
43
- // lowestListing: {
44
- // metadata: {
45
- // tokenId: '123',
46
- // name: 'Test Collectible',
47
- // description: 'Test Description',
48
- // image: 'https://example.com/image.png',
49
- // external_url: 'https://example.com',
50
- // decimals: 0,
51
- // attributes: [],
52
- // } as TokenMetadata,
53
- // order: mockOrder,
54
- // },
55
- // orderbookKind: OrderbookKind.sequence_marketplace_v2,
56
- // collectionType: ContractType.ERC721,
57
- // };
58
- // it('should render loading state when cardLoading is true', () => {
59
- // render(<CollectibleCard {...defaultProps} cardLoading={true} />);
60
- // expect(screen.getByTestId('loading-skeleton')).toBeInTheDocument();
61
- // });
62
- // it('should render collectible with image and metadata', async () => {
63
- // render(<CollectibleCard {...defaultProps} />);
64
- // // Check if name is displayed
65
- // expect(screen.getByText('Test Collectible')).toBeInTheDocument();
66
- // // Check price
67
- // expect(screen.getByText(/1 USDC/)).toBeInTheDocument();
68
- // // Check if token type is displayed
69
- // expect(screen.getByText('ERC-721')).toBeInTheDocument();
70
- // });
71
- // it('should call onCollectibleClick when clicked', () => {
72
- // const onCollectibleClick = vi.fn();
73
- // render(
74
- // <CollectibleCard
75
- // {...defaultProps}
76
- // onCollectibleClick={onCollectibleClick}
77
- // />,
78
- // );
79
- // // Click on the collectible
80
- // const collectibleElement = screen
81
- // .getByText('Test Collectible')
82
- // .closest('article');
83
- // if (collectibleElement) {
84
- // fireEvent.click(collectibleElement);
85
- // }
86
- // expect(onCollectibleClick).toHaveBeenCalledWith(defaultProps.collectibleId);
87
- // });
88
- // it('should open external url in new tab when external link is clicked', () => {
89
- // render(<CollectibleCard {...defaultProps} />);
90
- // const externalLink = screen.getByRole('link');
91
- // expect(externalLink).toHaveAttribute('href', 'https://example.com');
92
- // expect(externalLink).toHaveAttribute('target', '_blank');
93
- // expect(externalLink).toHaveAttribute('rel', 'noopener noreferrer');
94
- // });
95
- // it('should use fallback image when image load fails', async () => {
96
- // render(<CollectibleCard {...defaultProps} />);
97
- // const image = screen.getByAltText('Test Collectible');
98
- // // Trigger error
99
- // fireEvent.error(image);
100
- // // Check if image source is changed to fallback
101
- // expect(image).toHaveAttribute('src', expect.stringContaining('chess-tile'));
102
- // });
103
- // it('should show balance for ERC-1155 tokens', () => {
104
- // const erc1155Props = {
105
- // ...defaultProps,
106
- // collectionType: ContractType.ERC1155,
107
- // balance: '5',
108
- // };
109
- // render(<CollectibleCard {...erc1155Props} />);
110
- // expect(screen.getByText('Owned: 5')).toBeInTheDocument();
111
- // });
112
- // it('should call onCannotPerformAction when action cannot be performed', async () => {
113
- // const onCannotPerformAction = vi.fn();
114
- // render(
115
- // <CollectibleCard
116
- // {...defaultProps}
117
- // onCannotPerformAction={onCannotPerformAction}
118
- // balance="1" // Make it owned to test owner actions
119
- // />,
120
- // );
121
- // // We can't directly test this without mocking the useActionButtonLogic hook
122
- // // Just testing the prop passes through
123
- // expect(onCannotPerformAction).not.toHaveBeenCalled();
124
- // });
15
+ const defaultProps = {
16
+ collectibleId: '1',
17
+ chainId: 1,
18
+ collectionAddress: TEST_COLLECTIBLE.collectionAddress,
19
+ collectible: {
20
+ order: mockOrder,
21
+ listing: { ...mockOrder, side: OrderSide.listing },
22
+ offer: { ...mockOrder, side: OrderSide.offer },
23
+ metadata: {
24
+ ...mockTokenMetadata,
25
+ tokenId: mockTokenMetadata.tokenId as string,
26
+ assets: mockTokenMetadata.assets
27
+ ? mockTokenMetadata.assets.map((asset) => ({
28
+ ...asset,
29
+ tokenId: asset.tokenId || '',
30
+ }))
31
+ : undefined,
32
+ },
33
+ } as CollectibleOrder,
34
+ balance: '100',
35
+ balanceIsLoading: false,
36
+ cardLoading: false,
37
+ onCannotPerformAction: vi.fn(),
38
+ assetSrcPrefixUrl: 'https://example.com/',
39
+ orderbookKind: OrderbookKind.sequence_marketplace_v2,
40
+ collectionType: ContractType.ERC721,
41
+ };
42
+
43
+ describe('CollectibleCard', () => {
44
+ beforeEach(() => {
45
+ vi.clearAllMocks();
46
+ vi.restoreAllMocks();
47
+
48
+ const useCurrencySpy = vi.spyOn(hooks, 'useCurrency');
49
+ useCurrencySpy.mockReturnValue({
50
+ data: TEST_CURRENCY,
51
+ } as ReturnType<typeof hooks.useCurrency>);
52
+ });
53
+
54
+ it('Renders correctly with valid props and shows proper collectible details', () => {
55
+ render(<CollectibleCard {...defaultProps} />);
56
+
57
+ expect(screen.getByText('Mock NFT')).toBeInTheDocument();
58
+ expect(screen.getByText('1 TEST')).toBeInTheDocument();
59
+ // there is an offer
60
+ expect(screen.getByTitle('Notification Bell')).toBeInTheDocument();
61
+ expect(screen.getByRole('img', { name: 'Mock NFT' })).toHaveAttribute(
62
+ 'src',
63
+ defaultProps.assetSrcPrefixUrl + defaultProps.collectible.metadata.image,
64
+ );
65
+ });
66
+
67
+ it('Handles loading state by showing skeleton component', () => {
68
+ render(<CollectibleCard {...defaultProps} cardLoading={true} />);
69
+ expect(screen.getByTestId('collectible-card-skeleton')).toBeInTheDocument();
70
+ });
71
+
72
+ it('Triggers appropriate callbacks when collectible or action buttons are clicked', () => {
73
+ const onCollectibleClick = vi.fn();
74
+ const onOfferClick = vi.fn();
75
+
76
+ render(
77
+ <CollectibleCard
78
+ {...defaultProps}
79
+ onCollectibleClick={onCollectibleClick}
80
+ onOfferClick={onOfferClick}
81
+ />,
82
+ );
83
+
84
+ const notificationBell = screen.getByRole('button', {
85
+ name: 'Notification Bell',
86
+ });
87
+ fireEvent.click(notificationBell);
88
+ expect(onOfferClick).toHaveBeenCalled();
89
+
90
+ const collectibleCard = screen.getByTestId('collectible-card');
91
+ fireEvent.click(collectibleCard);
92
+ expect(onCollectibleClick).toHaveBeenCalled();
93
+ });
125
94
  });
@@ -0,0 +1,136 @@
1
+ import { TEST_CURRENCY } from '@test/const';
2
+ import { render, screen } from '@test/test-utils';
3
+ import { describe, expect, it, vi } from 'vitest';
4
+ import { ContractType } from '../../../../_internal';
5
+ import { mockOrder } from '../../../../_internal/api/__mocks__/marketplace.msw';
6
+ import { Footer } from '../Footer';
7
+
8
+ const defaultProps = {
9
+ name: 'Test',
10
+ type: ContractType.ERC721,
11
+ decimals: 18,
12
+ onOfferClick: vi.fn(),
13
+ highestOffer: mockOrder,
14
+ lowestOffer: mockOrder,
15
+ lowestListingPriceAmount: '100',
16
+ lowestListingCurrency: TEST_CURRENCY,
17
+ balance: '100',
18
+ };
19
+
20
+ describe('Footer', () => {
21
+ it('Renders with basic props (name, type) correctly', () => {
22
+ render(<Footer {...defaultProps} />);
23
+
24
+ expect(screen.getByText('Test')).toBeInTheDocument();
25
+ expect(screen.getByText('0.0001 TEST')).toBeInTheDocument();
26
+
27
+ const notificationBell = screen.getByRole('button', {
28
+ name: 'Notification Bell',
29
+ });
30
+ expect(notificationBell).toBeInTheDocument();
31
+ });
32
+
33
+ it('Truncates long names appropriately based on presence of offers', () => {
34
+ const longName =
35
+ 'This is a very long collectible name that needs truncation';
36
+
37
+ // Test truncation with offer present (truncates to 13 chars + "...")
38
+ render(
39
+ <Footer {...defaultProps} name={longName} highestOffer={mockOrder} />,
40
+ );
41
+ expect(screen.getByText('This is a ver...')).toBeInTheDocument();
42
+
43
+ // Test truncation without offer present (truncates to 17 chars + "...")
44
+ render(
45
+ <Footer {...defaultProps} name={longName} highestOffer={undefined} />,
46
+ );
47
+ expect(screen.getByText('This is a very lo...')).toBeInTheDocument();
48
+
49
+ // Test short name with offer (no truncation needed)
50
+ render(
51
+ <Footer {...defaultProps} name="Short Name" highestOffer={mockOrder} />,
52
+ );
53
+ expect(screen.getByText('Short Name')).toBeInTheDocument();
54
+ });
55
+
56
+ it('Formats prices correctly for different scenarios (normal, overflow, underflow)', () => {
57
+ // Test normal price formatting
58
+ render(
59
+ <Footer
60
+ {...defaultProps}
61
+ lowestListingPriceAmount="1000000000000000000" // 1 TOKEN in wei
62
+ />,
63
+ );
64
+ expect(screen.getByText('1 TEST')).toBeInTheDocument();
65
+
66
+ // Test small number formatting (shows more decimals)
67
+ render(
68
+ <Footer
69
+ {...defaultProps}
70
+ lowestListingPriceAmount="5000000000000000" // 0.005 TOKEN in wei
71
+ />,
72
+ );
73
+ expect(screen.getByText('0.005 TEST')).toBeInTheDocument();
74
+
75
+ // Test underflow price (< 0.0001)
76
+ render(
77
+ <Footer
78
+ {...defaultProps}
79
+ lowestListingPriceAmount="10000000000000" // 0.00001 TOKEN in wei
80
+ />,
81
+ );
82
+ // Should display minimum price with chevron icon
83
+ expect(screen.getByText('0.0001 TEST')).toBeInTheDocument();
84
+
85
+ // Test overflow price (> 100,000,000)
86
+ render(
87
+ <Footer
88
+ {...defaultProps}
89
+ lowestListingPriceAmount="100000000000000000000000000" // 100M+ TOKEN in wei
90
+ />,
91
+ );
92
+ // Should display maximum price with chevron icon
93
+ expect(screen.getByText('100,000,000 TEST')).toBeInTheDocument();
94
+ });
95
+
96
+ it("Displays 'Not listed yet' when no listing price is provided", () => {
97
+ // Create props without listing price information
98
+ const propsWithoutListing = {
99
+ ...defaultProps,
100
+ lowestListingPriceAmount: undefined,
101
+ lowestListingCurrency: undefined,
102
+ };
103
+
104
+ render(<Footer {...propsWithoutListing} />);
105
+
106
+ // Verify "Not listed yet" text is displayed
107
+ expect(screen.getByText('Not listed yet')).toBeInTheDocument();
108
+ });
109
+
110
+ it('Shows proper token balance information for ERC721 vs ERC1155 tokens', () => {
111
+ // Test ERC721 token display
112
+ render(<Footer {...defaultProps} type={ContractType.ERC721} />);
113
+ expect(screen.getByText('ERC-721')).toBeInTheDocument();
114
+
115
+ // Test ERC1155 token display without balance
116
+ render(
117
+ <Footer
118
+ {...defaultProps}
119
+ type={ContractType.ERC1155}
120
+ balance={undefined}
121
+ />,
122
+ );
123
+ expect(screen.getByText('ERC-1155')).toBeInTheDocument();
124
+
125
+ // Test ERC1155 token display with balance
126
+ render(
127
+ <Footer
128
+ {...defaultProps}
129
+ type={ContractType.ERC1155}
130
+ balance="1000000000000000000"
131
+ decimals={18}
132
+ />,
133
+ );
134
+ expect(screen.getByText('Owned: 1')).toBeInTheDocument();
135
+ });
136
+ });
@@ -1,4 +1,4 @@
1
- import { WebSdkWrapper, cleanup, render, screen } from '@test';
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();