import { render, screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; import { describe, expect, it, vi } from 'vitest'; import type { ListingDetail } from '@/lib/listings-api'; import { ComparisonTable } from '../comparison-table'; // Mock next/image vi.mock('next/image', () => ({ default: (props: Record) => , })); // Mock next-intl vi.mock('next-intl', () => ({ useTranslations: () => (key: string) => { const translations: Record = { property: 'Bất động sản', price: 'Giá', transactionType: 'Loại giao dịch', propertyType: 'Loại BĐS', area: 'Diện tích', pricePerM2: 'Giá/m²', bedrooms: 'Phòng ngủ', bathrooms: 'Phòng tắm', direction: 'Hướng', floors: 'Số tầng', yearBuilt: 'Năm xây', legalStatus: 'Pháp lý', location: 'Vị trí', amenities: 'Tiện ích', projectName: 'Dự án', rooms: 'phòng', remove: 'Xóa', noImage: 'Chưa có ảnh', sale: 'Bán', rent: 'Cho thuê', }; return translations[key] ?? key; }, })); // Mock @/i18n/navigation vi.mock('@/i18n/navigation', () => ({ Link: ({ children, href }: { children: React.ReactNode; href: string }) => ( {children} ), })); // Mock currency vi.mock('@/lib/currency', () => ({ formatPrice: (price: string) => { const n = Number(price); return n >= 1_000_000_000 ? `${(n / 1_000_000_000).toFixed(1)} tỷ` : String(n); }, formatPricePerM2: (price: number) => `${(price / 1_000_000).toFixed(1)} tr/m²`, })); // Mock image-blur vi.mock('@/lib/image-blur', () => ({ shimmerBlurDataURL: () => 'data:image/svg+xml;base64,mock', })); // Mock lucide-react vi.mock('lucide-react', () => ({ X: () => X, })); function makeListing(id: string, overrides: Partial = {}): ListingDetail { return { id, status: 'ACTIVE', transactionType: 'SALE', priceVND: '3500000000', pricePerM2: 40_000_000, rentPriceMonthly: null, commissionPct: null, viewCount: 100, saveCount: 10, inquiryCount: 5, publishedAt: '2026-01-01T00:00:00Z', createdAt: '2025-12-01T00:00:00Z', property: { id: `prop-${id}`, propertyType: 'APARTMENT', title: `Căn hộ ${id}`, description: 'Test', address: '123 Test St', ward: 'Ward', district: 'Quận 1', city: 'HCMC', areaM2: 75, bedrooms: 2, bathrooms: 2, floors: null, direction: 'SOUTH', yearBuilt: 2020, legalStatus: 'Sổ hồng', amenities: ['Gym', 'Pool'], projectName: 'Vinhomes', latitude: null, longitude: null, media: [{ id: 'm1', type: 'image', url: 'https://example.com/img.jpg', order: 0, caption: null }], }, seller: { id: 's1', fullName: 'Seller', phone: '0901234567' }, agent: null, ...overrides, }; } describe('ComparisonTable', () => { it('returns null when listings are empty', () => { const { container } = render(); expect(container.firstChild).toBeNull(); }); it('renders table with listings', () => { render(); expect(screen.getByText('Căn hộ 1')).toBeInTheDocument(); expect(screen.getByText('Căn hộ 2')).toBeInTheDocument(); }); it('renders comparison rows', () => { render(); expect(screen.getByText('Giá')).toBeInTheDocument(); expect(screen.getByText('Loại giao dịch')).toBeInTheDocument(); expect(screen.getByText('Loại BĐS')).toBeInTheDocument(); expect(screen.getByText('Diện tích')).toBeInTheDocument(); }); it('renders property area', () => { render(); expect(screen.getByText('75 m²')).toBeInTheDocument(); }); it('renders remove button', () => { render(); expect(screen.getByText('Xóa')).toBeInTheDocument(); }); it('calls onRemove when remove clicked', async () => { const user = userEvent.setup(); const onRemove = vi.fn(); render(); await user.click(screen.getByText('Xóa')); expect(onRemove).toHaveBeenCalledWith('1'); }); it('renders direction value', () => { render(); expect(screen.getByText('Nam')).toBeInTheDocument(); }); it('renders amenities', () => { render(); expect(screen.getByText('Gym')).toBeInTheDocument(); expect(screen.getByText('Pool')).toBeInTheDocument(); }); it('renders project name', () => { render(); expect(screen.getByText('Vinhomes')).toBeInTheDocument(); }); it('shows "—" for missing values', () => { const listing = makeListing('1'); listing.property.floors = null; render(); // floors row should have — const dashes = screen.getAllByText('—'); expect(dashes.length).toBeGreaterThan(0); }); it('renders bedrooms with room suffix', () => { render(); // Bedrooms and bathrooms both show "2 phòng" expect(screen.getAllByText('2 phòng').length).toBeGreaterThanOrEqual(1); }); });