feat: enhance search functionality to include parent names and related fields across categories
This commit is contained in:
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
namespace App\Tests\Category;
|
||||
|
||||
use App\Tests\ApiTestCase;
|
||||
|
||||
/**
|
||||
* search=… on the admin category lists must reach the parent, not just the row's
|
||||
* own name — operators look a child up by the name of the thing that owns it
|
||||
* ("all services under Dermatology"), and by slug when they paste one from a URL.
|
||||
*
|
||||
* Covers: /admin/specialties (parent specialty), /admin/doctor-services
|
||||
* (specialty), /admin/cities (province).
|
||||
*/
|
||||
class AdminCategorySearchTest extends ApiTestCase
|
||||
{
|
||||
/** @return list<int> */
|
||||
private function idsOf(array $body): array
|
||||
{
|
||||
return array_map(static fn(array $r) => (int) $r['id'], $body['data']);
|
||||
}
|
||||
|
||||
private function createdId(array $body): int
|
||||
{
|
||||
return (int) $body['data']['data']['id'];
|
||||
}
|
||||
|
||||
// ── specialties ───────────────────────────────────────────────────────────
|
||||
|
||||
public function testSpecialtySearchByParentNameReturnsChildren(): void
|
||||
{
|
||||
$admin = $this->createUser(['ROLE_ADMIN']);
|
||||
$marker = 'پوستآزمون' . uniqid();
|
||||
|
||||
$parentId = $this->createdId(
|
||||
$this->authJson('POST', '/api/v1/admin/specialty', $admin, ['name' => $marker])
|
||||
);
|
||||
$childId = $this->createdId(
|
||||
$this->authJson('POST', '/api/v1/admin/specialty', $admin, ['name' => 'لیزر درمانی ' . uniqid(), 'parent_id' => $parentId])
|
||||
);
|
||||
$unrelatedId = $this->createdId(
|
||||
$this->authJson('POST', '/api/v1/admin/specialty', $admin, ['name' => 'قلب' . uniqid()])
|
||||
);
|
||||
|
||||
$body = $this->authJson('GET', '/api/v1/admin/specialties?limit=100&search=' . urlencode($marker), $admin);
|
||||
|
||||
self::assertSame(200, $this->responseCode());
|
||||
$ids = $this->idsOf($body);
|
||||
self::assertContains($childId, $ids, 'فرزند باید با نام والد پیدا شود');
|
||||
self::assertContains($parentId, $ids, 'خودِ والد هم باید بماند');
|
||||
self::assertNotContains($unrelatedId, $ids);
|
||||
}
|
||||
|
||||
public function testSpecialtyRowCarriesParentName(): void
|
||||
{
|
||||
$admin = $this->createUser(['ROLE_ADMIN']);
|
||||
$marker = 'والدآزمون' . uniqid();
|
||||
|
||||
$parentId = $this->createdId(
|
||||
$this->authJson('POST', '/api/v1/admin/specialty', $admin, ['name' => $marker])
|
||||
);
|
||||
$this->authJson('POST', '/api/v1/admin/specialty', $admin, ['name' => 'زیرشاخه ' . uniqid(), 'parent_id' => $parentId]);
|
||||
|
||||
$body = $this->authJson('GET', '/api/v1/admin/specialties?limit=100&search=' . urlencode($marker), $admin);
|
||||
|
||||
$child = null;
|
||||
foreach ($body['data'] as $row) {
|
||||
if ((int) ($row['parent_id'] ?? 0) === $parentId) $child = $row;
|
||||
}
|
||||
|
||||
self::assertNotNull($child);
|
||||
self::assertSame($marker, $child['parent_name']);
|
||||
}
|
||||
|
||||
public function testSpecialtySearchBySlugStillMatches(): void
|
||||
{
|
||||
$admin = $this->createUser(['ROLE_ADMIN']);
|
||||
$slug = 'slug-test-' . uniqid();
|
||||
|
||||
$id = $this->createdId(
|
||||
$this->authJson('POST', '/api/v1/admin/specialty', $admin, ['name' => 'نام دلخواه ' . uniqid(), 'slug' => $slug])
|
||||
);
|
||||
|
||||
$body = $this->authJson('GET', '/api/v1/admin/specialties?limit=100&search=' . urlencode($slug), $admin);
|
||||
|
||||
self::assertContains($id, $this->idsOf($body));
|
||||
}
|
||||
|
||||
// ── doctor services ───────────────────────────────────────────────────────
|
||||
|
||||
public function testDoctorServiceSearchBySpecialtyName(): void
|
||||
{
|
||||
$admin = $this->createUser(['ROLE_ADMIN']);
|
||||
$marker = 'تخصصآزمون' . uniqid();
|
||||
|
||||
$specialtyId = $this->createdId(
|
||||
$this->authJson('POST', '/api/v1/admin/specialty', $admin, ['name' => $marker])
|
||||
);
|
||||
$serviceId = $this->createdId(
|
||||
$this->authJson('POST', '/api/v1/admin/doctor-service', $admin, ['name' => 'بوتاکس ' . uniqid(), 'specialty_id' => $specialtyId])
|
||||
);
|
||||
$unrelatedId = $this->createdId(
|
||||
$this->authJson('POST', '/api/v1/admin/doctor-service', $admin, ['name' => 'اکو' . uniqid()])
|
||||
);
|
||||
|
||||
$body = $this->authJson('GET', '/api/v1/admin/doctor-services?limit=100&search=' . urlencode($marker), $admin);
|
||||
|
||||
self::assertSame(200, $this->responseCode());
|
||||
$ids = $this->idsOf($body);
|
||||
self::assertContains($serviceId, $ids);
|
||||
self::assertNotContains($unrelatedId, $ids);
|
||||
|
||||
$row = null;
|
||||
foreach ($body['data'] as $r) {
|
||||
if ((int) $r['id'] === $serviceId) $row = $r;
|
||||
}
|
||||
self::assertSame($marker, $row['specialty_name']);
|
||||
}
|
||||
|
||||
public function testDoctorServiceWithoutSpecialtyIsStillListed(): void
|
||||
{
|
||||
$admin = $this->createUser(['ROLE_ADMIN']);
|
||||
$marker = 'خدمتتنها' . uniqid();
|
||||
|
||||
$id = $this->createdId(
|
||||
$this->authJson('POST', '/api/v1/admin/doctor-service', $admin, ['name' => $marker])
|
||||
);
|
||||
|
||||
$body = $this->authJson('GET', '/api/v1/admin/doctor-services?limit=100&search=' . urlencode($marker), $admin);
|
||||
|
||||
$ids = $this->idsOf($body);
|
||||
self::assertContains($id, $ids, 'LEFT JOIN نباید ردیفِ بدون تخصص را حذف کند');
|
||||
self::assertSame(1, $body['meta']['totalRecords']);
|
||||
}
|
||||
|
||||
// ── cities ────────────────────────────────────────────────────────────────
|
||||
|
||||
public function testCitySearchByProvinceName(): void
|
||||
{
|
||||
$admin = $this->createUser(['ROLE_ADMIN']);
|
||||
$marker = 'استانآزمون' . uniqid();
|
||||
|
||||
$provinceId = $this->createdId(
|
||||
$this->authJson('POST', '/api/v1/admin/province', $admin, ['name' => $marker])
|
||||
);
|
||||
$cityId = $this->createdId(
|
||||
$this->authJson('POST', '/api/v1/admin/city', $admin, ['name' => 'شهر یک ' . uniqid(), 'province_id' => $provinceId])
|
||||
);
|
||||
$unrelatedId = $this->createdId(
|
||||
$this->authJson('POST', '/api/v1/admin/city', $admin, ['name' => 'شهر دو' . uniqid()])
|
||||
);
|
||||
|
||||
$body = $this->authJson('GET', '/api/v1/admin/cities?limit=100&search=' . urlencode($marker), $admin);
|
||||
|
||||
self::assertSame(200, $this->responseCode());
|
||||
$ids = $this->idsOf($body);
|
||||
self::assertContains($cityId, $ids);
|
||||
self::assertNotContains($unrelatedId, $ids);
|
||||
}
|
||||
|
||||
public function testCitySearchByDomain(): void
|
||||
{
|
||||
$admin = $this->createUser(['ROLE_ADMIN']);
|
||||
$domain = 'search-test-' . uniqid() . '.example';
|
||||
|
||||
$cityId = $this->createdId(
|
||||
$this->authJson('POST', '/api/v1/admin/city', $admin, ['name' => 'شهر دامنهدار ' . uniqid(), 'domain' => $domain])
|
||||
);
|
||||
|
||||
$body = $this->authJson('GET', '/api/v1/admin/cities?limit=100&search=' . urlencode($domain), $admin);
|
||||
|
||||
self::assertContains($cityId, $this->idsOf($body));
|
||||
}
|
||||
|
||||
// ── boundaries ────────────────────────────────────────────────────────────
|
||||
|
||||
public function testUnknownTermReturnsEmptyList(): void
|
||||
{
|
||||
$admin = $this->createUser(['ROLE_ADMIN']);
|
||||
|
||||
$body = $this->authJson('GET', '/api/v1/admin/specialties?search=' . urlencode('چنینچیزینیست' . uniqid()), $admin);
|
||||
|
||||
self::assertSame(200, $this->responseCode());
|
||||
self::assertSame([], $body['data']);
|
||||
self::assertSame(0, $body['meta']['totalRecords']);
|
||||
}
|
||||
|
||||
public function testNonAdminForbidden(): void
|
||||
{
|
||||
$user = $this->createUser(['ROLE_USER']);
|
||||
$this->authJson('GET', '/api/v1/admin/specialties?search=x', $user);
|
||||
self::assertSame(403, $this->responseCode());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user