Files
goodgo-platform/e2e/api/search.spec.ts
Ho Ngoc Hai da10ac64c6 test(e2e): update all E2E specs for latest API and fixtures
Update 17 E2E test files including admin, auth, inquiries, listings,
payments, search, subscriptions, and MCP specs. Update listings fixture
and global setup to align with latest schema changes.

Co-Authored-By: Paperclip <noreply@paperclip.ing>
2026-04-11 01:40:45 +07:00

169 lines
4.7 KiB
TypeScript

import { test, expect } from '@playwright/test';
test.describe('Search API', () => {
test.describe('GET /search — Text search', () => {
test('returns search results for a query', async ({ request }) => {
const res = await request.get('search', {
params: { q: 'apartment' },
});
// Typesense may not be running or collection may not exist — accept 200 or 500/503
if (res.status() >= 500) {
test.skip(true, 'Typesense not available');
return;
}
expect(res.status()).toBe(200);
const body = await res.json();
expect(body).toHaveProperty('hits');
expect(Array.isArray(body.hits)).toBeTruthy();
expect(body).toHaveProperty('totalFound');
});
test('returns empty results for nonsense query', async ({ request }) => {
const res = await request.get('search', {
params: { q: 'zzzznotexistingproperty999' },
});
if (res.status() >= 500) {
test.skip(true, 'Typesense not available');
return;
}
expect(res.status()).toBe(200);
const body = await res.json();
expect(body.hits).toHaveLength(0);
});
test('filters by property type', async ({ request }) => {
const res = await request.get('search', {
params: { propertyType: 'VILLA', q: '' },
});
if (res.status() >= 500) {
test.skip(true, 'Typesense not available');
return;
}
expect(res.status()).toBe(200);
const body = await res.json();
for (const item of body.hits) {
expect(item.propertyType).toBe('VILLA');
}
});
test('filters by price range', async ({ request }) => {
const res = await request.get('search', {
params: { priceMin: 1000000000, priceMax: 10000000000 },
});
if (res.status() >= 500) {
test.skip(true, 'Typesense not available');
return;
}
expect(res.status()).toBe(200);
});
test('supports sorting', async ({ request }) => {
const res = await request.get('search', {
params: { sortBy: 'price_asc' },
});
if (res.status() >= 500) {
test.skip(true, 'Typesense not available');
return;
}
expect(res.status()).toBe(200);
});
test('paginates correctly', async ({ request }) => {
const res = await request.get('search', {
params: { page: 1, perPage: 5 },
});
if (res.status() >= 500) {
test.skip(true, 'Typesense not available');
return;
}
expect(res.status()).toBe(200);
const body = await res.json();
expect(body.hits.length).toBeLessThanOrEqual(5);
});
});
test.describe('GET /search/geo — Geo search', () => {
test('returns results for geo search in Ho Chi Minh City', async ({ request }) => {
const res = await request.get('search/geo', {
params: { lat: 10.7769, lng: 106.7009, radiusKm: 5 },
});
if (res.status() >= 500) {
test.skip(true, 'Typesense not available');
return;
}
expect(res.status()).toBe(200);
const body = await res.json();
expect(body).toHaveProperty('hits');
expect(Array.isArray(body.hits)).toBeTruthy();
});
test('rejects missing required geo params', async ({ request }) => {
const res = await request.get('search/geo', {
params: { lat: 10.7769 },
});
expect(res.ok()).toBeFalsy();
expect(res.status()).toBe(400);
});
test('rejects invalid latitude', async ({ request }) => {
const res = await request.get('search/geo', {
params: { lat: 999, lng: 106.7009, radiusKm: 5 },
});
expect(res.ok()).toBeFalsy();
expect(res.status()).toBe(400);
});
test('rejects radius exceeding max', async ({ request }) => {
const res = await request.get('search/geo', {
params: { lat: 10.7769, lng: 106.7009, radiusKm: 200 },
});
expect(res.ok()).toBeFalsy();
expect(res.status()).toBe(400);
});
test('filters geo results by property type', async ({ request }) => {
const res = await request.get('search/geo', {
params: {
lat: 10.7769,
lng: 106.7009,
radiusKm: 10,
propertyType: 'APARTMENT',
},
});
if (res.status() >= 500) {
test.skip(true, 'Typesense not available');
return;
}
expect(res.status()).toBe(200);
});
});
test.describe('POST /search/reindex — Admin reindex', () => {
test('rejects unauthenticated reindex request', async ({ request }) => {
const res = await request.post('search/reindex');
expect(res.ok()).toBeFalsy();
expect(res.status()).toBe(401);
});
});
});