/** * Agents Page E2E Tests * * Tests the agent profile page at /agents/[id]. * The app does not have a public agent listing page, only individual agent profiles. * Tests use route mocking to avoid API dependency. */ import { test, expect } from '@playwright/test'; const mockAgent = { id: 'agent-1', fullName: 'Nguyễn Văn Minh', avatarUrl: null, phone: '0912345678', email: 'minh@goodgo.vn', agency: 'GoodGo Realty', licenseNumber: 'GPHN-2025-001', bio: 'Chuyên viên tư vấn bất động sản khu vực Quận 7 và Quận 2 với hơn 5 năm kinh nghiệm.', qualityScore: 88, totalDeals: 45, isVerified: true, serviceAreas: ['Quận 7', 'Quận 2', 'Nhà Bè'], memberSince: '2023-06-15T00:00:00Z', activeListings: [ { id: 'listing-1', transactionType: 'SALE', priceVND: '5000000000', status: 'ACTIVE', property: { id: 'prop-1', title: 'Căn hộ cao cấp Quận 7', propertyType: 'APARTMENT', address: '123 Nguyễn Thị Thập', district: 'Quận 7', city: 'Hồ Chí Minh', areaM2: 75, bedrooms: 2, bathrooms: 2, imageUrl: null, }, }, ], avgReviewRating: 4.8, totalReviews: 12, }; const mockReviews = { data: [ { id: 'review-1', userId: 'user-1', userName: 'Trần Thị B', targetType: 'AGENT', targetId: 'agent-1', rating: 5, comment: 'Môi giới tận tình, hỗ trợ nhiệt tình.', createdAt: '2026-03-01T00:00:00Z', }, ], stats: { targetType: 'AGENT', targetId: 'agent-1', averageRating: 4.8, totalReviews: 12, distribution: { 5: 10, 4: 2 }, }, }; test.describe('Agent Profile Page', () => { test.beforeEach(async ({ page }) => { await page.route('**/agents/agent-1', (route) => route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(mockAgent), }), ); await page.route('**/agents/agent-1/reviews**', (route) => route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(mockReviews), }), ); }); test('renders agent name and verified badge', async ({ page }) => { await page.goto('/agents/agent-1'); await expect(page.getByText('Nguyễn Văn Minh')).toBeVisible({ timeout: 10_000 }); }); test('shows agent agency and contact info', async ({ page }) => { await page.goto('/agents/agent-1'); await expect(page.getByText('Nguyễn Văn Minh')).toBeVisible({ timeout: 10_000 }); await expect(page.getByText(/GoodGo Realty/)).toBeVisible(); }); test('shows active listings section', async ({ page }) => { await page.goto('/agents/agent-1'); await expect(page.getByText('Nguyễn Văn Minh')).toBeVisible({ timeout: 10_000 }); // Listing should appear await expect(page.getByText(/Căn hộ cao cấp Quận 7/)).toBeVisible(); }); test('has breadcrumb back to homepage', async ({ page }) => { await page.goto('/agents/agent-1'); await expect(page.getByText('Nguyễn Văn Minh')).toBeVisible({ timeout: 10_000 }); await expect(page.getByRole('link', { name: /Trang chủ/i })).toBeVisible(); }); test('renders without critical console errors', async ({ page }) => { const criticalErrors: string[] = []; page.on('console', (msg) => { if (msg.type() === 'error') { const text = msg.text(); if ( text.includes('mapbox') || text.includes('NEXT_PUBLIC') || text.includes('net::ERR') || text.includes('Failed to load resource') ) { return; } criticalErrors.push(text); } }); await page.goto('/agents/agent-1'); await page.waitForLoadState('networkidle', { timeout: 15_000 }).catch(() => {}); expect(criticalErrors).toHaveLength(0); }); test('handles 404 for unknown agent gracefully', async ({ page }) => { await page.route('**/agents/nonexistent**', (route) => route.fulfill({ status: 404, body: JSON.stringify({ message: 'Not found' }) }), ); const res = await page.goto('/agents/nonexistent-agent-id'); const status = res?.status(); if (status && status >= 500) { throw new Error(`Agent page returned ${status} for unknown ID (expected 404 or redirect)`); } }); }); test.describe('Agent Profile — Responsive', () => { const viewports = [ { label: '375px (mobile)', width: 375, height: 667 }, { label: '768px (tablet)', width: 768, height: 1024 }, { label: '1280px (laptop)', width: 1280, height: 800 }, { label: '1920px (desktop)', width: 1920, height: 1080 }, ]; for (const vp of viewports) { test(`renders at ${vp.label}`, async ({ page }) => { await page.route('**/agents/agent-1', (route) => route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(mockAgent), }), ); await page.route('**/agents/agent-1/reviews**', (route) => route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(mockReviews), }), ); await page.setViewportSize({ width: vp.width, height: vp.height }); await page.goto('/agents/agent-1'); await expect(page.getByText('Nguyễn Văn Minh')).toBeVisible({ timeout: 10_000 }); // No horizontal overflow (layout break indicator) const bodyWidth = await page.evaluate(() => document.body.scrollWidth); const viewportWidth = await page.evaluate(() => window.innerWidth); expect(bodyWidth).toBeLessThanOrEqual(viewportWidth + 2); // 2px tolerance }); } });