Files
clinicpro/tests/Subscription/ActivateTrialTest.php
T
hamedandClaude Opus 5 8a43297e24 test: remove the two real sources of full-run flakiness, and the mock notices
createUser() drew a random mobile and recovered from a collision by catching
the unique-constraint violation and calling resetManager(). That hands back a
brand-new EntityManager, which detaches every entity the running test had
built so far; its next flush died with "Multiple non-persisted new entities
were found", always in a different test and never reproducible in isolation.
The number is now checked before the insert, so the collision never reaches
the database and the manager stays open.

testParentIdAddsNoQueryPerSpecialty counted queries on the first request of
each size, so one-shot per-process caches — site config, subscription plan,
Doctrine metadata — landed inside the count or not depending on which tests
had run before it. Both requests are now warmed first; the assertion measures
steady-state growth, which is what it was always about.

The 23 PHPUnit notices were all one complaint: doubles created with
createMock() that never had an expectation. The ones that only stub return
values became createStub(); in SmsServiceLookupOnlyTest the provider and the
bus got the expectations they were missing, since "dispatch does not touch
the provider" and "sendNow does not enqueue" are exactly what that suite is
there to prove.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-08-18 09:57:29 +03:30

115 lines
3.8 KiB
PHP

<?php
namespace App\Tests\Subscription;
use App\Config\Repository\SiteConfigRepository;
use App\Shared\Constant\ErrorCodes;
use App\Shared\Exception\AppException;
use App\Subscription\Entity\SubscriptionPlan;
use App\Subscription\Repository\ClinicSubscriptionRepository;
use App\Subscription\Repository\SubscriptionPeriodRepository;
use App\Subscription\Repository\SubscriptionPlanRepository;
use App\Subscription\Service\SubscriptionService;
use PHPUnit\Framework\TestCase;
/**
* A `basic` plan whose trial period has been deactivated is a normal admin
* configuration. It used to surface as ERR_NOT_FOUND_001/500; it must now be
* the same ERR_TRIAL_DISABLED/422 the trial_enabled flag produces.
*/
class ActivateTrialTest extends TestCase
{
private function service(
bool $usedTrial,
?string $trialEnabled,
?SubscriptionPlan $basicPlan,
mixed $trialPeriod,
): SubscriptionService {
$subscriptionRepo = $this->createStub(ClinicSubscriptionRepository::class);
$subscriptionRepo->method('hasUsedTrial')->willReturn($usedTrial);
$planRepo = $this->createStub(SubscriptionPlanRepository::class);
$planRepo->method('findByName')->willReturn($basicPlan);
$periodRepo = $this->createStub(SubscriptionPeriodRepository::class);
$periodRepo->method('findTrialPeriodForPlan')->willReturn($trialPeriod);
$configRepo = $this->createStub(SiteConfigRepository::class);
$configRepo->method('get')->willReturn($trialEnabled);
return new SubscriptionService($subscriptionRepo, $planRepo, $periodRepo, $configRepo);
}
public function testNoActiveTrialPeriodIsReportedAsTrialDisabled(): void
{
$service = $this->service(
usedTrial: false,
trialEnabled: '1',
basicPlan: $this->createStub(SubscriptionPlan::class),
trialPeriod: null,
);
try {
$service->activateTrial('doctor', 1);
$this->fail('expected AppException');
} catch (AppException $e) {
$this->assertSame(ErrorCodes::ERR_TRIAL_DISABLED, $e->getErrorCode());
$this->assertSame(422, $e->getHttpStatus());
}
}
public function testMissingBasicPlanStaysAServerError(): void
{
$service = $this->service(
usedTrial: false,
trialEnabled: '1',
basicPlan: null,
trialPeriod: null,
);
try {
$service->activateTrial('doctor', 1);
$this->fail('expected AppException');
} catch (AppException $e) {
$this->assertSame(ErrorCodes::ERR_NOT_FOUND_001, $e->getErrorCode());
$this->assertSame(500, $e->getHttpStatus());
}
}
public function testAlreadyUsedTrialTakesPrecedence(): void
{
$service = $this->service(
usedTrial: true,
trialEnabled: '1',
basicPlan: null,
trialPeriod: null,
);
try {
$service->activateTrial('doctor', 1);
$this->fail('expected AppException');
} catch (AppException $e) {
$this->assertSame(ErrorCodes::ERR_TRIAL_ALREADY_USED, $e->getErrorCode());
$this->assertSame(422, $e->getHttpStatus());
}
}
public function testDisabledFlagTakesPrecedenceOverMissingPlan(): void
{
$service = $this->service(
usedTrial: false,
trialEnabled: '0',
basicPlan: null,
trialPeriod: null,
);
try {
$service->activateTrial('doctor', 1);
$this->fail('expected AppException');
} catch (AppException $e) {
$this->assertSame(ErrorCodes::ERR_TRIAL_DISABLED, $e->getErrorCode());
$this->assertSame(422, $e->getHttpStatus());
}
}
}