Skip to content
Merged
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
68 changes: 68 additions & 0 deletions miniapps/teleport/src/App.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -409,6 +409,74 @@ describe('Teleport App', () => {
})
})

it('should display ratio semantics clearly on confirm step', async () => {
const mockedGetTransmitAssetTypeList = vi.mocked(getTransmitAssetTypeList)
mockedGetTransmitAssetTypeList.mockResolvedValueOnce({
transmitSupport: {
BFCHAINV2: {
BFT: {
enable: true,
isAirdrop: false,
assetType: 'BFT',
recipientAddress: 'bReceiver',
targetChain: 'BFMCHAIN',
targetAsset: 'BFM',
ratio: { numerator: 416, denominator: 10000 },
transmitDate: {
startDate: '2020-01-01',
endDate: '2030-12-31',
},
},
},
},
})

mockBio.request.mockImplementation(({ method, params }: { method: string; params?: Array<{ chain?: string }> }) => {
if (method === 'bio_selectAccount') {
return Promise.resolve({ address: 'bSource', chain: params?.[0]?.chain ?? 'BFCHAINV2', name: 'Source' })
}
if (method === 'bio_getBalance') {
return Promise.resolve('100000000000000')
}
if (method === 'bio_pickWallet') {
return Promise.resolve({ address: 'bTarget', chain: 'bfmeta', name: 'Target' })
}
if (method === 'bio_closeSplashScreen') {
return Promise.resolve(null)
}
return Promise.resolve(null)
})

render(<App />, { wrapper: createWrapper() })

await waitFor(() => {
expect(screen.getByRole('button', { name: '启动 BFCHAINV2 传送门' })).toBeInTheDocument()
})

fireEvent.click(screen.getByRole('button', { name: '启动 BFCHAINV2 传送门' }))

await waitFor(() => {
expect(screen.getByTestId('asset-card-BFT')).toBeInTheDocument()
})

fireEvent.click(screen.getByTestId('asset-card-BFT'))
await waitFor(() => {
expect(screen.getByTestId('amount-input')).toBeInTheDocument()
})
fireEvent.change(screen.getByTestId('amount-input'), { target: { value: '10000' } })
fireEvent.click(screen.getByTestId('next-button'))

await waitFor(() => {
expect(screen.getByTestId('target-button')).toBeInTheDocument()
})
fireEvent.click(screen.getByTestId('target-button'))

await waitFor(() => {
expect(screen.getByText('1 BFT = 0.0416 BFM')).toBeInTheDocument()
expect(screen.getByText(/416 BFM/)).toBeInTheDocument()
})
})

it('should show sender/receiver addresses on confirm step and remove free-fee badge', async () => {
mockBio.request.mockImplementation(({ method, params }: { method: string; params?: Array<{ chain?: string }> }) => {
if (method === 'bio_selectAccount') {
Expand Down
29 changes: 22 additions & 7 deletions miniapps/teleport/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,16 @@ const formatRawBalance = (raw: string, decimals: number): string => {
return fractionPart.length > 0 ? `${integerWithComma}.${fractionPart}` : integerWithComma;
};

const formatRatioRate = (
ratio: { numerator: number | string; denominator: number | string } | null | undefined,
): string => {
if (!ratio) return '0';
const numerator = Number(ratio.numerator);
const denominator = Number(ratio.denominator);
if (!Number.isFinite(numerator) || !Number.isFinite(denominator) || denominator === 0) return '0';
return (numerator / denominator).toFixed(8).replace(/\.?0+$/, '');
};

export default function App() {
const { t } = useTranslation();
const [step, setStep] = useState<Step>('connect');
Expand Down Expand Up @@ -590,9 +600,10 @@ export default function App() {
// 计算预期接收金额
const expectedReceive = useMemo(() => {
if (!selectedAsset || !amount) return '0';
const { numerator, denominator } = selectedAsset.ratio;
const amountNum = parseFloat(amount);
const ratioNum = Number(numerator) / Number(denominator);
const amountNum = Number(amount);
if (!Number.isFinite(amountNum)) return '0';
const ratioNum = Number(selectedAsset.ratio.numerator) / Number(selectedAsset.ratio.denominator);
if (!Number.isFinite(ratioNum)) return '0';
return (amountNum * ratioNum).toFixed(8).replace(/\.?0+$/, '');
}, [selectedAsset, amount]);

Expand Down Expand Up @@ -734,9 +745,7 @@ export default function App() {
</Card>
) : (
sortedAvailableAssets.map((asset, i) => {
const rate = (Number(asset.ratio.numerator) / Number(asset.ratio.denominator))
.toFixed(4)
.replace(/\.?0+$/, '');
const rate = formatRatioRate(asset.ratio);
const routeLabel = `${asset.chain}/${asset.symbol} ${t('common.arrow')} ${asset.targetChain}/${asset.targetAsset}`;
return (
<motion.div
Expand Down Expand Up @@ -987,7 +996,13 @@ export default function App() {
<Separator />
<div className="flex justify-between">
<span className="text-muted-foreground">{t('confirm.ratio')}</span>
<span>{`${selectedAsset?.ratio.numerator}:${selectedAsset?.ratio.denominator}`}</span>
<span>
{t('asset.ratio', {
from: selectedAsset?.symbol ?? '',
rate: formatRatioRate(selectedAsset?.ratio),
to: selectedAsset?.targetAsset ?? '',
})}
</span>
</div>
<Separator />
<div className="flex justify-between">
Expand Down