import { test, expect } from '@playwright/test'; const mockListing = { id: 'listing-1', transactionType: 'SALE', priceVND: '5000000000', pricePerM2: 66666667, rentPriceMonthly: null, commissionPct: 2.5, status: 'ACTIVE', viewCount: 120, saveCount: 15, inquiryCount: 8, publishedAt: '2026-01-15T00:00:00Z', property: { id: 'prop-1', propertyType: 'APARTMENT', title: 'Căn hộ cao cấp Quận 1', description: 'Căn hộ đẹp view sông Sài Gòn, nội thất cao cấp, tiện ích đầy đủ.', address: '123 Nguyễn Huệ', ward: 'Bến Nghé', district: 'Quận 1', city: 'Hồ Chí Minh', latitude: 10.7769, longitude: 106.7009, areaM2: 75, bedrooms: 2, bathrooms: 2, floors: 1, direction: 'SOUTH', yearBuilt: 2022, legalStatus: 'Sổ hồng', projectName: 'Vinhomes Central Park', amenities: ['Hồ bơi', 'Gym', 'Bãi đỗ xe'], media: [ { id: 'm1', url: '/placeholder.jpg', type: 'IMAGE', order: 0 }, { id: 'm2', url: '/placeholder2.jpg', type: 'IMAGE', order: 1 }, ], }, seller: { id: 's1', fullName: 'Nguyen Van A', phone: '0912345678' }, agent: { id: 'a1', agency: 'GoodGo Realty', licenseNumber: 'AGT-001' }, }; test.describe('Listing Detail Page', () => { test.beforeEach(async ({ page }) => { await page.route('**/listings/listing-1', (route) => route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(mockListing), }), ); }); test('renders listing title and price', async ({ page }) => { await page.goto('/listings/listing-1'); await expect(page.getByRole('heading', { name: 'Căn hộ cao cấp Quận 1' })).toBeVisible({ timeout: 10000, }); await expect(page.getByText(/5\.0 tỷ/)).toBeVisible(); await expect(page.getByText('VND')).toBeVisible(); }); test('displays breadcrumb navigation', async ({ page }) => { await page.goto('/listings/listing-1'); await expect(page.getByText('Căn hộ cao cấp Quận 1').first()).toBeVisible({ timeout: 10000 }); await expect(page.getByRole('link', { name: 'Trang chu' })).toBeVisible(); await expect(page.getByRole('link', { name: 'Tim kiem' })).toBeVisible(); }); test('shows property badges (transaction type and property type)', async ({ page }) => { await page.goto('/listings/listing-1'); await expect(page.getByText('Căn hộ cao cấp Quận 1').first()).toBeVisible({ timeout: 10000 }); // Transaction type and property type badges const badges = page.locator('[class*="badge"]'); await expect(badges.first()).toBeVisible(); }); test('displays address information', async ({ page }) => { await page.goto('/listings/listing-1'); await expect(page.getByText('Căn hộ cao cấp Quận 1').first()).toBeVisible({ timeout: 10000 }); await expect(page.getByText(/123 Nguyễn Huệ/)).toBeVisible(); await expect(page.getByText(/Bến Nghé/)).toBeVisible(); await expect(page.getByText(/Quận 1/)).toBeVisible(); }); test('shows quick stats bar', async ({ page }) => { await page.goto('/listings/listing-1'); await expect(page.getByText('Căn hộ cao cấp Quận 1').first()).toBeVisible({ timeout: 10000 }); await expect(page.getByText('75 m²')).toBeVisible(); await expect(page.getByText('Dien tich')).toBeVisible(); await expect(page.getByText('Phong ngu')).toBeVisible(); await expect(page.getByText('Phong tam')).toBeVisible(); }); test('displays description section', async ({ page }) => { await page.goto('/listings/listing-1'); await expect(page.getByText('Căn hộ cao cấp Quận 1').first()).toBeVisible({ timeout: 10000 }); await expect(page.getByText('Mo ta')).toBeVisible(); await expect(page.getByText('Căn hộ đẹp view sông Sài Gòn')).toBeVisible(); }); test('shows detailed property info grid', async ({ page }) => { await page.goto('/listings/listing-1'); await expect(page.getByText('Căn hộ cao cấp Quận 1').first()).toBeVisible({ timeout: 10000 }); await expect(page.getByText('Thong tin chi tiet')).toBeVisible(); await expect(page.getByText('Loai BDS')).toBeVisible(); await expect(page.getByText('Sổ hồng')).toBeVisible(); await expect(page.getByText('Vinhomes Central Park')).toBeVisible(); }); test('displays amenities', async ({ page }) => { await page.goto('/listings/listing-1'); await expect(page.getByText('Căn hộ cao cấp Quận 1').first()).toBeVisible({ timeout: 10000 }); await expect(page.getByText('Tien ich')).toBeVisible(); await expect(page.getByText('Hồ bơi')).toBeVisible(); await expect(page.getByText('Gym')).toBeVisible(); await expect(page.getByText('Bãi đỗ xe')).toBeVisible(); }); test('shows seller contact card', async ({ page }) => { await page.goto('/listings/listing-1'); await expect(page.getByText('Căn hộ cao cấp Quận 1').first()).toBeVisible({ timeout: 10000 }); await expect(page.getByText('Lien he')).toBeVisible(); await expect(page.getByText('Nguyen Van A')).toBeVisible(); await expect(page.getByText('0912345678')).toBeVisible(); await expect(page.getByRole('button', { name: /Goi ngay/i })).toBeVisible(); await expect(page.getByRole('button', { name: /Nhan tin/i })).toBeVisible(); }); test('shows agent info when available', async ({ page }) => { await page.goto('/listings/listing-1'); await expect(page.getByText('Căn hộ cao cấp Quận 1').first()).toBeVisible({ timeout: 10000 }); await expect(page.getByText('Moi gioi')).toBeVisible(); await expect(page.getByText('GoodGo Realty')).toBeVisible(); await expect(page.getByText(/2\.5%/)).toBeVisible(); }); test('displays listing statistics', async ({ page }) => { await page.goto('/listings/listing-1'); await expect(page.getByText('Căn hộ cao cấp Quận 1').first()).toBeVisible({ timeout: 10000 }); await expect(page.getByText('120')).toBeVisible(); // viewCount await expect(page.getByText('Luot xem')).toBeVisible(); await expect(page.getByText('Luot luu')).toBeVisible(); }); test('shows error state for non-existent listing', async ({ page }) => { await page.route('**/listings/nonexistent', (route) => route.fulfill({ status: 404, contentType: 'application/json', body: '{}' }), ); await page.goto('/listings/nonexistent'); await expect(page.getByText(/Khong/)).toBeVisible({ timeout: 10000 }); await expect(page.getByRole('link', { name: /Quay lai tim kiem/i })).toBeVisible(); }); test('shows loading skeleton initially', async ({ page }) => { await page.route('**/listings/listing-1', async (route) => { await new Promise((r) => setTimeout(r, 2000)); await route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(mockListing), }); }); await page.goto('/listings/listing-1'); // Skeleton elements should be visible during loading const skeleton = page.locator('.animate-pulse'); await expect(skeleton.first()).toBeVisible({ timeout: 3000 }); }); test('breadcrumb navigates to search page', async ({ page }) => { await page.goto('/listings/listing-1'); await expect(page.getByText('Căn hộ cao cấp Quận 1').first()).toBeVisible({ timeout: 10000 }); await page.getByRole('link', { name: 'Tim kiem' }).click(); await expect(page).toHaveURL(/\/search/); }); });