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
4 changes: 2 additions & 2 deletions e2e/guide.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ test.describe('Guide 页面', () => {
await page.click('[data-testid="get-started-button"]', { force: true })

// 应该导航到创建钱包页
await expect(page).toHaveURL(/\/#\/wallet\/create\/?/)
await expect(page).toHaveURL(/(\/#\/wallet\/create)|(\/#\/onboarding\/create)\/?/)
})

test('我有钱包按钮导航到导入钱包页', async ({ page }) => {
Expand All @@ -79,6 +79,6 @@ test.describe('Guide 页面', () => {
await page.click('[data-testid="have-wallet-button"]', { force: true })

// 应该导航到导入钱包页
await expect(page).toHaveURL(/\/#\/wallet\/import\/?/)
await expect(page).toHaveURL(/(\/#\/wallet\/import)|(\/#\/onboarding\/recover)\/?/)
})
})
6 changes: 6 additions & 0 deletions playwright.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,12 @@ export default defineConfig({
viewport: { width: 1280, height: 720 },
},
},
{
name: 'Mobile Safari',
use: {
...devices['iPhone 12'],
},
},
],

// 使用标准 dev 服务器(端口 11173,避免与 vite 默认 517x 冲突)
Expand Down
3 changes: 2 additions & 1 deletion src/components/asset/asset-item.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ describe('AssetItem', () => {

it('renders formatted balance', () => {
render(<AssetItem asset={mockAsset} />)
expect(screen.getByText('1.5')).toBeInTheDocument()
// AmountDisplay uses aria-label due to NumberFlow dual-span structure
expect(screen.getByLabelText('1.5')).toBeInTheDocument()
})

it('uses assetType as name when name is not provided', () => {
Expand Down
7 changes: 4 additions & 3 deletions src/components/asset/asset-list.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,10 @@ describe('AssetList', () => {

it('renders asset balances', () => {
renderWithI18n(<AssetList assets={mockAssets} />)
expect(screen.getByText('1.5')).toBeInTheDocument() // ETH
expect(screen.getByText('100')).toBeInTheDocument() // USDT
expect(screen.getByText('0.5')).toBeInTheDocument() // BTC
// AmountDisplay uses aria-label due to NumberFlow dual-span structure
expect(screen.getByLabelText('1.5')).toBeInTheDocument()
expect(screen.getByLabelText('100')).toBeInTheDocument()
expect(screen.getByLabelText('0.5')).toBeInTheDocument()
})

it('applies custom className', () => {
Expand Down
13 changes: 9 additions & 4 deletions src/components/asset/asset-selector.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { describe, it, expect, vi } from 'vitest'
import { render, screen, fireEvent } from '@testing-library/react'
import userEvent from '@testing-library/user-event'
import { AssetSelector } from './asset-selector'
import type { TokenInfo } from '@/components/token/token-item'

Expand Down Expand Up @@ -78,7 +79,8 @@ describe('AssetSelector', () => {
expect(screen.getByText('Tether USD')).toBeInTheDocument()
})

it('calls onSelect when asset is clicked', () => {
it('calls onSelect when asset is clicked', async () => {
const user = userEvent.setup()
const onSelect = vi.fn()
render(
<AssetSelector
Expand All @@ -90,10 +92,13 @@ describe('AssetSelector', () => {
)

// Open dropdown
fireEvent.click(screen.getByTestId('asset-selector'))
await user.click(screen.getByTestId('asset-selector'))

// Click on USDT
fireEvent.click(screen.getByText('Tether USD'))
// Click on USDT option (Base UI Select uses role="option")
const options = screen.getAllByRole('option')
const usdtOption = options.find(opt => opt.textContent?.includes('Tether USD'))
expect(usdtOption).toBeDefined()
await user.click(usdtOption!)

expect(onSelect).toHaveBeenCalledWith(mockAssets[1])
})
Expand Down
38 changes: 22 additions & 16 deletions src/components/common/amount-display.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -50,79 +50,85 @@ describe('formatAmount', () => {
})

describe('AmountDisplay', () => {
// Helper to get amount element (uses aria-label due to NumberFlow dual-span structure)
const getAmount = (value: string) => screen.getByLabelText(value)
const queryAmount = (value: string) => screen.queryByLabelText(value)

it('renders value', () => {
render(<AmountDisplay value={100} />)
expect(screen.getByText('100')).toBeInTheDocument()
expect(getAmount('100')).toBeInTheDocument()
})

it('renders with symbol', () => {
render(<AmountDisplay value={100} symbol="USDT" />)
expect(screen.getByText('100')).toBeInTheDocument()
expect(screen.getByText('USDT')).toBeInTheDocument()
expect(getAmount('100 USDT')).toBeInTheDocument()
})

it('shows hidden state', () => {
render(<AmountDisplay value={100} symbol="USDT" hidden />)
expect(screen.getByText('••••••')).toBeInTheDocument()
expect(screen.queryByText('100')).not.toBeInTheDocument()
expect(queryAmount('100')).not.toBeInTheDocument()
})

it('shows + sign when sign=always for positive', () => {
render(<AmountDisplay value={100} sign="always" />)
expect(screen.getByText('+100')).toBeInTheDocument()
expect(getAmount('+100')).toBeInTheDocument()
})

it('shows - sign when sign=always for negative', () => {
render(<AmountDisplay value={-100} sign="always" />)
expect(screen.getByText('-100')).toBeInTheDocument()
expect(getAmount('-100')).toBeInTheDocument()
})

it('shows - sign when sign=auto for negative', () => {
render(<AmountDisplay value={-100} sign="auto" />)
expect(screen.getByText('-100')).toBeInTheDocument()
expect(getAmount('-100')).toBeInTheDocument()
})

it('applies positive color when color=auto', () => {
render(<AmountDisplay value={100} color="auto" />)
expect(screen.getByText('100')).toHaveClass('text-green-500')
expect(getAmount('100')).toHaveClass('text-green-500')
})

it('applies negative color when color=auto', () => {
render(<AmountDisplay value={-100} color="auto" />)
expect(screen.getByText('100')).toHaveClass('text-destructive')
expect(getAmount('100')).toHaveClass('text-destructive')
})

it('applies size classes', () => {
render(<AmountDisplay value={100} size="lg" />)
expect(screen.getByText('100')).toHaveClass('text-lg')
expect(getAmount('100')).toHaveClass('text-lg')
})

it('applies weight classes', () => {
render(<AmountDisplay value={100} weight="bold" />)
expect(screen.getByText('100')).toHaveClass('font-bold')
expect(getAmount('100')).toHaveClass('font-bold')
})

it('applies mono font', () => {
render(<AmountDisplay value={100} mono />)
expect(screen.getByText('100')).toHaveClass('font-mono')
expect(getAmount('100')).toHaveClass('font-mono')
})

it('uses compact format', () => {
render(<AmountDisplay value={1500000} compact />)
expect(screen.getByText('1.5M')).toBeInTheDocument()
expect(getAmount('1.5M')).toBeInTheDocument()
})
})

describe('AmountWithFiat', () => {
// Helper to get amount element (uses aria-label due to NumberFlow dual-span structure)
const getAmount = (value: string) => screen.getByLabelText(value)

it('renders amount and fiat value vertically', () => {
render(<AmountWithFiat value={100} symbol="USDT" fiatValue={100} />)
expect(screen.getByText('100')).toBeInTheDocument()
expect(getAmount('100 USDT')).toBeInTheDocument()
expect(screen.getByText('≈ $100')).toBeInTheDocument()
})

it('renders amount and fiat value horizontally', () => {
render(<AmountWithFiat value={100} fiatValue={100} layout="horizontal" />)
expect(screen.getByText('100')).toBeInTheDocument()
expect(getAmount('100')).toBeInTheDocument()
expect(screen.getByText('≈ $100')).toBeInTheDocument()
})

Expand All @@ -133,7 +139,7 @@ describe('AmountWithFiat', () => {

it('renders without fiat when not provided', () => {
render(<AmountWithFiat value={100} />)
expect(screen.getByText('100')).toBeInTheDocument()
expect(getAmount('100')).toBeInTheDocument()
expect(screen.queryByText(/≈/)).not.toBeInTheDocument()
})
})
5 changes: 3 additions & 2 deletions src/components/wallet/token-icon.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { render, screen, fireEvent } from '@testing-library/react'
import { TokenIcon, TokenBadge, TokenIconProvider } from './token-icon'

const mockGetTokenIconBases = (chainId: string) => {
// Templates use $symbol (lowercase) or $SYMBOL (uppercase) placeholders
const bases: Record<string, string[]> = {
ethereum: ['/icons/ethereum/tokens', 'https://cdn.example.com/eth'],
bfmeta: ['/icons/bfmeta/tokens', 'https://cdn.example.com/bfm'],
ethereum: ['/icons/ethereum/tokens/$symbol.svg', 'https://cdn.example.com/eth/$symbol.png'],
bfmeta: ['/icons/bfmeta/tokens/$symbol.svg', 'https://cdn.example.com/bfm/$symbol.png'],
}
return bases[chainId] ?? []
}
Expand Down
75 changes: 38 additions & 37 deletions src/i18n/locales/ar/common.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"a11y": {
"addWallet": "إضافة محفظة",
"addContact": "إضافة جهة اتصال",
"addWallet": "إضافة محفظة",
"appInfo": "معلومات التطبيق",
"back": "رجوع",
"chainSelector": "اختر شبكة البلوكتشين",
Expand Down Expand Up @@ -44,24 +44,42 @@
"acquisitionTime": "Acquisition time",
"add": "Add",
"addressBook": {
"addContact": "إضافة جهة اتصال",
"addresses": "العناوين",
"changeAvatar": "انقر لتغيير الصورة",
"delete": "حذف",
"deleteConfirm": "هل أنت متأكد من حذف جهة الاتصال \"{{name}}\"؟",
"deleteTitle": "حذف جهة الاتصال",
"edit": "تعديل",
"memo": "ملاحظة",
"memoPlaceholder": "أضف ملاحظة (اختياري)",
"namePlaceholder": "أدخل اسم جهة الاتصال",
"noContacts": "لا توجد جهات اتصال بعد",
"noResults": "لم يتم العثور على جهات اتصال",
"passwordError": "كلمة المرور غير صحيحة",
"scanToAdd": "امسح لإضافة جهة اتصال",
"searchPlaceholder": "البحث عن جهات الاتصال",
"title": "دفتر العناوين",
"verifyFailed": "فشل التحقق",
"addContact": "إضافة جهة اتصال",
"namePlaceholder": "أدخل اسم جهة الاتصال",
"addresses": "العناوين",
"memo": "ملاحظة",
"memoPlaceholder": "أضف ملاحظة (اختياري)",
"shareContact": "مشاركة البطاقة",
"scanToAdd": "امسح لإضافة جهة اتصال",
"changeAvatar": "انقر لتغيير الصورة"
"title": "دفتر العناوين",
"verifyFailed": "فشل التحقق"
},
"addressLookup": {
"address": "Address",
"addressOrHash": "Address or Transaction Hash",
"addressOrHashPlaceholder": "Enter address or tx hash",
"addressPlaceholder": "Enter wallet address",
"balanceTitle": "Address Balance",
"chain": "Chain",
"error": "Query Failed",
"explorerHint": "Transaction history requires block explorer",
"noTransactions": "No transactions found",
"onChain": "on {{chain}}",
"openExplorer": "Open {{name}} Explorer",
"otherChains": "Other Chains",
"queryError": "Failed to query transactions, please try again",
"transactionsTitle": "Address Transactions",
"useExplorerHint": "This chain does not support direct history query, please use the explorer",
"viewOnExplorer": "View on {{name}}"
},
"addressPlaceholder": "أدخل أو الصق العنوان",
"advancedEncryptionTechnologyDigitalWealthIsMoreSecure": "Advanced encryption technology &lt;br /&gt; Digital wealth is more secure",
Expand All @@ -86,6 +104,7 @@
"cancel": "Cancel",
"cardWorks": "[MISSING:ar] card works!",
"certificate": "Certificate",
"clickToCopy": "[MISSING:ar] 点击复制",
"clickToShowTheQr": "[MISSING:ar] 点开显示二维码",
"clickToShowTheQrCodeOfThePrivateKey": "Click to show the QR code of the private key",
"close": "Close",
Expand All @@ -99,9 +118,13 @@
"confirmToTurnOffVerification": "[MISSING:ar] 确认要关闭验证吗?",
"contact": {
"add": "إضافة",
"addAddress": "إضافة عنوان",
"addTitle": "إضافة جهة اتصال",
"address": "العنوان",
"addressLabel": "التسمية",
"addressLabelPlaceholder": "مثل: الحساب الرئيسي",
"addressPlaceholder": "أدخل عنوان المحفظة",
"addresses": "العناوين",
"cancel": "إلغاء",
"editTitle": "تعديل جهة اتصال",
"memoOptional": "ملاحظة (اختياري)",
Expand All @@ -113,11 +136,7 @@
"save": "حفظ",
"selectAddress": "اختر العنوان",
"selectContact": "اختر جهة اتصال",
"viewAll": "عرض جميع جهات الاتصال",
"addresses": "العناوين",
"addressLabel": "التسمية",
"addressLabelPlaceholder": "مثل: الحساب الرئيسي",
"addAddress": "إضافة عنوان"
"viewAll": "عرض جميع جهات الاتصال"
},
"continue": "Continue",
"contractMethods": "Contract methods",
Expand All @@ -134,6 +153,7 @@
"delete": "Delete",
"destroy": "Destroy",
"done": "Done",
"download": "تحميل",
"dpInTab": "[MISSING:ar] dp",
"dpName": "DP Name",
"dpType": "Type",
Expand Down Expand Up @@ -250,18 +270,17 @@
"resubmit": "Resubmit",
"retry": "Retry",
"save": "Save",
"saving": "جارٍ الحفظ...",
"saved": "تم الحفظ",
"saveQrCode": "Save QR code",
"saveSuccessful": "Saved Successfully",
"saved": "تم الحفظ",
"saving": "جارٍ الحفظ...",
"scan": "Scan",
"scanAgain": "Scan again",
"scanner": "Scanner",
"search": "Search",
"selectNetwork": "Select Network",
"selectionNetwork": "Selection network",
"share": "Share",
"download": "تحميل",
"shareCancel": "[MISSING:ar] 分享取消",
"shareCanceled": "Share canceled",
"shareSuccessful": "Shared Successfully",
Expand Down Expand Up @@ -329,23 +348,5 @@
"{{item}}Words": "words",
"{{length}}Words": "words",
"中文(简体)": "中文(简体)",
"中文(繁體)": "中文(繁體)",
"addressLookup": {
"balanceTitle": "Address Balance",
"transactionsTitle": "Address Transactions",
"chain": "Chain",
"address": "Address",
"addressPlaceholder": "Enter wallet address",
"addressOrHash": "Address or Transaction Hash",
"addressOrHashPlaceholder": "Enter address or tx hash",
"otherChains": "Other Chains",
"error": "Query Failed",
"queryError": "Failed to query transactions, please try again",
"noTransactions": "No transactions found",
"onChain": "on {{chain}}",
"explorerHint": "Transaction history requires block explorer",
"useExplorerHint": "This chain does not support direct history query, please use the explorer",
"openExplorer": "Open {{name}} Explorer",
"viewOnExplorer": "View on {{name}}"
}
"中文(繁體)": "中文(繁體)"
}
24 changes: 24 additions & 0 deletions src/i18n/locales/ar/ecosystem.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{
"title": "[MISSING:ar] 生态",
"empty": "[MISSING:ar] 暂无小程序",
"loading": "[MISSING:ar] 加载中...",
"notFound": "[MISSING:ar] 小程序不存在",
"refresh": "[MISSING:ar] 刷新",
"sources": {
"title": "[MISSING:ar] 可信源管理",
"add": "[MISSING:ar] 添加订阅",
"remove": "[MISSING:ar] 移除",
"empty": "[MISSING:ar] 暂无订阅源"
},
"permissions": {
"title": "[MISSING:ar] 权限请求",
"grant": "[MISSING:ar] 授权",
"deny": "[MISSING:ar] 拒绝",
"bio_requestAccounts": "[MISSING:ar] 访问钱包地址",
"bio_selectAccount": "[MISSING:ar] 选择账户",
"bio_pickWallet": "[MISSING:ar] 选择其他钱包",
"bio_signMessage": "[MISSING:ar] 签名消息",
"bio_signTypedData": "[MISSING:ar] 签名数据",
"bio_sendTransaction": "[MISSING:ar] 发起交易"
}
}
Loading