test(e2e): add 14 new web E2E test files for critical user flows
Cover auth (login, register, OAuth callbacks), search with filters, listing detail, dashboard, analytics, create listing form, admin dashboard/users/moderation/KYC, navigation routing, and responsive design. Total 91 test cases using Playwright with API route mocking. Co-Authored-By: Paperclip <noreply@paperclip.ing>
This commit is contained in:
86
e2e/web/analytics.spec.ts
Normal file
86
e2e/web/analytics.spec.ts
Normal file
@@ -0,0 +1,86 @@
|
||||
import { test, expect } from '@playwright/test';
|
||||
|
||||
const mockMarketReport = {
|
||||
districts: [
|
||||
{ district: 'Quan 1', propertyType: 'APARTMENT', avgPriceM2: 85000000, medianPriceM2: 80000000, totalListings: 150, daysOnMarket: 45, yoyChange: 5.2 },
|
||||
{ district: 'Quan 7', propertyType: 'HOUSE', avgPriceM2: 65000000, medianPriceM2: 60000000, totalListings: 200, daysOnMarket: 60, yoyChange: -2.1 },
|
||||
],
|
||||
};
|
||||
|
||||
const mockHeatmap = {
|
||||
dataPoints: [
|
||||
{ district: 'Quan 1', avgPriceM2: 85000000, totalListings: 150, lat: 10.7769, lng: 106.7009 },
|
||||
{ district: 'Quan 7', avgPriceM2: 65000000, totalListings: 200, lat: 10.7385, lng: 106.7218 },
|
||||
],
|
||||
};
|
||||
|
||||
const mockDistrictStats = {
|
||||
districts: [
|
||||
{ district: 'Quan 1', propertyType: 'APARTMENT', medianPrice: 5000000000, pricePerM2: 85000000, totalListings: 150, daysOnMarket: 45, yoyChange: 5.2 },
|
||||
],
|
||||
};
|
||||
|
||||
const mockTrends = {
|
||||
dataPoints: [
|
||||
{ period: '2025-Q1', avgPriceM2: 78000000, totalListings: 130, transactionVolume: 80 },
|
||||
{ period: '2025-Q2', avgPriceM2: 80000000, totalListings: 140, transactionVolume: 85 },
|
||||
{ period: '2026-Q1', avgPriceM2: 85000000, totalListings: 150, transactionVolume: 95 },
|
||||
],
|
||||
};
|
||||
|
||||
test.describe('Analytics Page', () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.route('**/analytics/market-report**', (route) =>
|
||||
route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(mockMarketReport) }),
|
||||
);
|
||||
await page.route('**/analytics/heatmap**', (route) =>
|
||||
route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(mockHeatmap) }),
|
||||
);
|
||||
await page.route('**/analytics/district-stats**', (route) =>
|
||||
route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(mockDistrictStats) }),
|
||||
);
|
||||
await page.route('**/analytics/price-trends**', (route) =>
|
||||
route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify(mockTrends) }),
|
||||
);
|
||||
});
|
||||
|
||||
test('renders analytics page with city selector', async ({ page }) => {
|
||||
await page.goto('/analytics');
|
||||
|
||||
// City selector buttons should be visible
|
||||
await expect(page.getByRole('button', { name: /Ho Chi Minh/i })).toBeVisible({ timeout: 10000 });
|
||||
await expect(page.getByRole('button', { name: /Ha Noi/i })).toBeVisible();
|
||||
await expect(page.getByRole('button', { name: /Da Nang/i })).toBeVisible();
|
||||
});
|
||||
|
||||
test('displays tabs for different views', async ({ page }) => {
|
||||
await page.goto('/analytics');
|
||||
|
||||
await expect(page.getByRole('tab', { name: /Overview/i }).or(page.getByText('Overview'))).toBeVisible({ timeout: 10000 });
|
||||
});
|
||||
|
||||
test('switches city when selector clicked', async ({ page }) => {
|
||||
await page.goto('/analytics');
|
||||
await expect(page.getByRole('button', { name: /Ha Noi/i })).toBeVisible({ timeout: 10000 });
|
||||
|
||||
await page.getByRole('button', { name: /Ha Noi/i }).click();
|
||||
|
||||
// The Ha Noi button should now appear selected/active
|
||||
// Page should re-fetch data for the new city
|
||||
await expect(page.getByRole('button', { name: /Ha Noi/i })).toBeVisible();
|
||||
});
|
||||
|
||||
test('handles empty data gracefully', async ({ page }) => {
|
||||
await page.route('**/analytics/market-report**', (route) =>
|
||||
route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ districts: [] }) }),
|
||||
);
|
||||
await page.route('**/analytics/heatmap**', (route) =>
|
||||
route.fulfill({ status: 200, contentType: 'application/json', body: JSON.stringify({ dataPoints: [] }) }),
|
||||
);
|
||||
|
||||
await page.goto('/analytics');
|
||||
|
||||
// Page should still render without crashing
|
||||
await expect(page.getByRole('button', { name: /Ho Chi Minh/i })).toBeVisible({ timeout: 10000 });
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user