findByClinicWithFilters left-joined specialties only for filtering, so toListArray() lazy-loaded them per doctor (N+1). addSelect them and switch the result fetch to Paginator(fetchJoinCollection: true) so LIMIT still paginates by doctor. Test infra: ApiTestCase::countQueries() (via doctrine.debug_data_holder). Regression: tests/Doctor/ClinicDoctorListNPlusOneTest asserts the query count does not grow with doctor count (4→10 without the fix). Also relaxed AppointmentExpiryServiceTest's exact-count assertion (it counts all stale pendings in the shared db_test, which accumulates) — logged test-isolation debt as E6. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
57 lines
2.1 KiB
PHP
57 lines
2.1 KiB
PHP
<?php
|
|
|
|
namespace App\Tests\Appointment;
|
|
|
|
use App\Appointment\Entity\Appointment;
|
|
use App\Appointment\Service\AppointmentExpiryService;
|
|
use App\Doctor\Entity\Doctor;
|
|
use App\Payment\Entity\Payment;
|
|
use App\Tests\ApiTestCase;
|
|
|
|
/**
|
|
* Covers AppointmentExpiryService: stale pending bookings are expired and their
|
|
* pending payments cancelled. Also guards the N+1 fix (batch payment fetch) by
|
|
* exercising several appointments at once.
|
|
*/
|
|
class AppointmentExpiryServiceTest extends ApiTestCase
|
|
{
|
|
public function testExpiresStaleAndCancelsPendingPayments(): void
|
|
{
|
|
$owner = $this->createUser(['ROLE_DOCTOR']);
|
|
$doctor = new Doctor($owner, 'دکتر تست');
|
|
$this->em->persist($doctor);
|
|
|
|
$past = time() - 3600;
|
|
$appointments = [];
|
|
for ($i = 0; $i < 5; $i++) {
|
|
$patient = $this->createUser(['ROLE_USER']);
|
|
// distinct past slots — one live booking per (doctor, slot)
|
|
$slotStart = $past - $i * 1000;
|
|
$appt = new Appointment($doctor, $patient, $slotStart, $slotStart + 900);
|
|
$this->em->persist($appt);
|
|
|
|
$payment = new Payment($patient, 100_000, 'mellat', 'appointment');
|
|
$payment->setAppointment($appt);
|
|
$this->em->persist($payment);
|
|
|
|
$appointments[] = [$appt, $payment];
|
|
}
|
|
$this->em->flush();
|
|
|
|
$service = static::getContainer()->get(AppointmentExpiryService::class);
|
|
$count = $service->expireStale();
|
|
|
|
// At least our 5 — db_test is shared and may hold other stale pendings
|
|
// from earlier tests/runs; the per-row checks below verify our own 5.
|
|
$this->assertGreaterThanOrEqual(5, $count);
|
|
|
|
$this->em->clear();
|
|
foreach ($appointments as [$appt, $payment]) {
|
|
$freshAppt = $this->em->getRepository(Appointment::class)->find($appt->getId());
|
|
$freshPay = $this->em->getRepository(Payment::class)->find($payment->getId());
|
|
$this->assertSame(Appointment::STATUS_EXPIRED, $freshAppt->getStatus());
|
|
$this->assertSame(Payment::STATUS_CANCELED, $freshPay->getStatus());
|
|
}
|
|
}
|
|
}
|