test(e2e): align web specs with current app routes

This commit is contained in:
Ho Ngoc Hai
2026-05-04 20:11:09 +07:00
parent f112045826
commit 39156fc107
21 changed files with 334 additions and 458 deletions

View File

@@ -7,110 +7,55 @@
*/
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,
};
import { mockAuthenticatedUser } from './support/auth';
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 },
},
};
const seededAgentId = 'seed-agentprofile-001';
const seededAgentName = 'Nguyễn Văn An';
const seededAgentAgency = 'GoodGo Premium Realty';
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.beforeEach(async ({ page, context, baseURL }) => {
await mockAuthenticatedUser(page, context, baseURL, { role: 'AGENT' });
});
test('renders agent name and verified badge', async ({ page }) => {
await page.goto('/agents/agent-1');
await page.goto(`/agents/${seededAgentId}`);
await expect(page.getByText('Nguyễn Văn Minh')).toBeVisible({ timeout: 10_000 });
await expect(page.getByRole('heading', { name: seededAgentName })).toBeVisible({
timeout: 10_000,
});
await expect(page.getByText('KYC xác minh')).toBeVisible();
});
test('shows agent agency and contact info', async ({ page }) => {
await page.goto('/agents/agent-1');
await page.goto(`/agents/${seededAgentId}`);
await expect(page.getByText('Nguyễn Văn Minh')).toBeVisible({ timeout: 10_000 });
await expect(page.getByText(/GoodGo Realty/)).toBeVisible();
await expect(page.getByRole('heading', { name: seededAgentName })).toBeVisible({
timeout: 10_000,
});
await expect(page.getByText(seededAgentAgency)).toBeVisible();
await expect(page.getByText('+84900000002').first()).toBeVisible();
});
test('shows active listings section', async ({ page }) => {
await page.goto('/agents/agent-1');
test('shows listings and reviews sections', async ({ page }) => {
await page.goto(`/agents/${seededAgentId}`);
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();
await expect(page.getByRole('heading', { name: seededAgentName })).toBeVisible({
timeout: 10_000,
});
await expect(page.getByText('Danh mục bất động sản')).toBeVisible();
await expect(page.getByRole('heading', { name: /Đánh giá/ })).toBeVisible();
});
test('has breadcrumb back to homepage', async ({ page }) => {
await page.goto('/agents/agent-1');
await page.goto(`/agents/${seededAgentId}`);
await expect(page.getByText('Nguyễn Văn Minh')).toBeVisible({ timeout: 10_000 });
await expect(page.getByRole('link', { name: /Trang chủ/i })).toBeVisible();
await expect(page.getByRole('heading', { name: seededAgentName })).toBeVisible({
timeout: 10_000,
});
await expect(
page.locator('#main-content').getByRole('link', { name: /Trang chủ/i }),
).toBeVisible();
});
test('renders without critical console errors', async ({ page }) => {
@@ -130,17 +75,13 @@ test.describe('Agent Profile Page', () => {
}
});
await page.goto('/agents/agent-1');
await page.goto(`/agents/${seededAgentId}`);
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) {
@@ -158,26 +99,15 @@ test.describe('Agent Profile — Responsive', () => {
];
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),
}),
);
test(`renders at ${vp.label}`, async ({ page, context, baseURL }) => {
await mockAuthenticatedUser(page, context, baseURL, { role: 'AGENT' });
await page.setViewportSize({ width: vp.width, height: vp.height });
await page.goto('/agents/agent-1');
await page.goto(`/agents/${seededAgentId}`);
await expect(page.getByText('Nguyễn Văn Minh')).toBeVisible({ timeout: 10_000 });
await expect(page.getByRole('heading', { name: seededAgentName })).toBeVisible({
timeout: 10_000,
});
// No horizontal overflow (layout break indicator)
const bodyWidth = await page.evaluate(() => document.body.scrollWidth);