Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 45 additions & 0 deletions packages/ui-components/src/__tests__/OrderDetail.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import type { ComponentProps } from 'svelte';
import { invalidateTanstackQueries } from '$lib/queries/queryClient';
import { useToasts } from '$lib/providers/toasts/useToasts';
import { useRaindexClient } from '$lib/hooks/useRaindexClient';
import { getExplorerLink } from '$lib/services/getExplorerLink';

vi.mock('$lib/hooks/useRaindexClient', () => ({
useRaindexClient: vi.fn()
Expand Down Expand Up @@ -46,6 +47,10 @@ vi.mock('$lib/components/charts/OrderTradesChart.svelte', async () => {
const mockLightweightCharts = (await import('../lib/__mocks__/MockComponent.svelte')).default;
return { default: mockLightweightCharts };
});

vi.mock('$lib/services/getExplorerLink', () => ({
getExplorerLink: vi.fn()
}));
const orderbookAddress = '0x123456789012345678901234567890123456abcd';
const orderHash = '0x0234';

Expand Down Expand Up @@ -157,6 +162,10 @@ describe('OrderDetail', () => {
errToast: mockErrToast,
removeToast: vi.fn()
});

(getExplorerLink as Mock).mockReturnValue(
'https://etherscan.io/address/0x1234567890123456789012345678901234567890'
);
});

it('calls the order detail query with the correct order hash', async () => {
Expand Down Expand Up @@ -335,4 +344,40 @@ describe('OrderDetail', () => {

expect(mockOnWithdraw).toHaveBeenCalledWith(mockRaindexClient, mockOrder.vaultsList.items[1]);
});

it('renders owner address as explorer link when explorer is available', async () => {
const explorerUrl = 'https://etherscan.io/address/0x1234567890123456789012345678901234567890';
(getExplorerLink as Mock).mockReturnValue(explorerUrl);

render(OrderDetail, {
props: defaultProps,
context: new Map([['$$_queryClient', queryClient]])
});

await waitFor(() => {
const ownerLink = screen.getByRole('link', {
name: /0x1234567890123456789012345678901234567890/i
});
expect(ownerLink).toBeInTheDocument();
expect(ownerLink).toHaveAttribute('href', explorerUrl);
expect(ownerLink).toHaveAttribute('target', '_blank');
expect(ownerLink).toHaveAttribute('rel', 'noopener noreferrer');
});
});

it('falls back to Hash component when no explorer link is available', async () => {
(getExplorerLink as Mock).mockReturnValue('');

render(OrderDetail, {
props: defaultProps,
context: new Map([['$$_queryClient', queryClient]])
});

await waitFor(() => {
expect(screen.getByText('0x1234567890123456789012345678901234567890')).toBeInTheDocument();
expect(
screen.queryByRole('link', { name: /0x1234567890123456789012345678901234567890/i })
).not.toBeInTheDocument();
});
});
});
45 changes: 45 additions & 0 deletions packages/ui-components/src/__tests__/VaultDetail.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import { useAccount } from '../lib/providers/wallet/useAccount';
import { QKEY_VAULT } from '$lib/queries/keys';
import { useToasts } from '../lib/providers/toasts/useToasts';
import { invalidateTanstackQueries } from '$lib/queries/queryClient';
import { getExplorerLink } from '$lib/services/getExplorerLink';

type VaultDetailProps = ComponentProps<VaultDetail>;

Expand Down Expand Up @@ -44,6 +45,10 @@ vi.mock('$lib/providers/toasts/useToasts', () => ({
useToasts: vi.fn()
}));

vi.mock('$lib/services/getExplorerLink', () => ({
getExplorerLink: vi.fn()
}));

const mockErrToast = vi.fn();

const defaultProps: VaultDetailProps = {
Expand Down Expand Up @@ -78,6 +83,10 @@ describe('VaultDetail', () => {
removeToast: vi.fn()
});

(getExplorerLink as Mock).mockReturnValue(
'https://etherscan.io/address/0x1234567890123456789012345678901234567890'
);

mockRaindexClient = {
getVault: vi.fn()
} as unknown as RaindexClient;
Expand Down Expand Up @@ -214,4 +223,40 @@ describe('VaultDetail', () => {
expect(mockErrToast).toHaveBeenCalledWith('Failed to refresh');
});
});

it('renders owner address as explorer link when explorer is available', async () => {
const explorerUrl = 'https://etherscan.io/address/0x1234567890123456789012345678901234567890';
(getExplorerLink as Mock).mockReturnValue(explorerUrl);

render(VaultDetail, {
props: defaultProps,
context: new Map([['$$_queryClient', queryClient]])
});

await waitFor(() => {
const ownerLink = screen.getByRole('link', {
name: /0x1234567890123456789012345678901234567890/i
});
expect(ownerLink).toBeInTheDocument();
expect(ownerLink).toHaveAttribute('href', explorerUrl);
expect(ownerLink).toHaveAttribute('target', '_blank');
expect(ownerLink).toHaveAttribute('rel', 'noopener noreferrer');
});
});

it('falls back to Hash component when no explorer link is available', async () => {
(getExplorerLink as Mock).mockReturnValue('');

render(VaultDetail, {
props: defaultProps,
context: new Map([['$$_queryClient', queryClient]])
});

await waitFor(() => {
expect(screen.getByTestId('vaultDetailOwnerAddress')).toHaveTextContent('0x123');
expect(
screen.queryByRole('link', { name: /0x1234567890123456789012345678901234567890/i })
).not.toBeInTheDocument();
});
});
});
8 changes: 4 additions & 4 deletions packages/ui-components/src/__tests__/getExplorerLink.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ vi.mock('viem/chains', () => ({
}));

describe('getExplorerLink', () => {
it('should return the explorer link', async () => {
expect(await getExplorerLink('0x123', 999, 'tx')).toBe('https://etherscan.io/tx/0x123');
it('should return the explorer link', () => {
expect(getExplorerLink('0x123', 999, 'tx')).toBe('https://etherscan.io/tx/0x123');
});
it('should return an empty string if the chain is not found', async () => {
expect(await getExplorerLink('0x123', 1, 'tx')).toBe('');
it('should return an empty string if the chain is not found', () => {
expect(getExplorerLink('0x123', 1, 'tx')).toBe('');
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,10 @@
import {
ArrowDownToBracketOutline,
ArrowUpFromBracketOutline,
InfoCircleOutline
InfoCircleOutline,
WalletOutline
} from 'flowbite-svelte-icons';
import { getExplorerLink } from '$lib/services/getExplorerLink';
import { useAccount } from '$lib/providers/wallet/useAccount';
import {
RaindexClient,
Expand Down Expand Up @@ -155,7 +157,20 @@
<CardProperty>
<svelte:fragment slot="key">Owner</svelte:fragment>
<svelte:fragment slot="value">
<Hash type={HashType.Wallet} shorten={false} value={data.owner} />
{@const explorerLink = getExplorerLink(data.owner, chainId, 'address')}
{#if explorerLink}
<a
href={explorerLink}
target="_blank"
rel="noopener noreferrer"
class="flex items-center justify-start space-x-2 text-left text-blue-500 hover:underline"
>
<WalletOutline size="sm" />
<span>{data.owner}</span>
</a>
{:else}
<Hash type={HashType.Wallet} shorten={false} value={data.owner} />
{/if}
</svelte:fragment>
</CardProperty>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,12 @@
import { invalidateTanstackQueries } from '$lib/queries/queryClient';
import { useAccount } from '$lib/providers/wallet/useAccount';
import { Button } from 'flowbite-svelte';
import { ArrowDownToBracketOutline, ArrowUpFromBracketOutline } from 'flowbite-svelte-icons';
import {
ArrowDownToBracketOutline,
ArrowUpFromBracketOutline,
WalletOutline
} from 'flowbite-svelte-icons';
import { getExplorerLink } from '$lib/services/getExplorerLink';
import { useToasts } from '$lib/providers/toasts/useToasts';
import { useRaindexClient } from '$lib/hooks/useRaindexClient';

Expand Down Expand Up @@ -128,7 +133,20 @@
<CardProperty data-testid="vaultDetailOwnerAddress">
<svelte:fragment slot="key">Owner address</svelte:fragment>
<svelte:fragment slot="value">
<Hash type={HashType.Wallet} value={data.owner} />
{@const explorerLink = getExplorerLink(data.owner, chainId, 'address')}
{#if explorerLink}
<a
href={explorerLink}
target="_blank"
rel="noopener noreferrer"
class="flex items-center justify-start space-x-2 text-left text-blue-500 hover:underline"
>
<WalletOutline size="sm" />
<span>{data.owner}</span>
</a>
{:else}
<Hash type={HashType.Wallet} value={data.owner} />
{/if}
</svelte:fragment>
</CardProperty>

Expand Down
5 changes: 2 additions & 3 deletions packages/ui-components/src/lib/services/getExplorerLink.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
import * as chains from 'viem/chains';

export const getExplorerLink = async (hash: string, chainId: number, type: 'tx' | 'address') => {
export const getExplorerLink = (hash: string, chainId: number, type: 'tx' | 'address'): string => {
const chain = Object.values(chains).find((chain) => chain.id === chainId);
if (chain?.blockExplorers) {
return chain.blockExplorers.default.url + `/${type}/${hash}`;
} else {
return '';
}
return '';
};
Loading