Files
clinicpro/tests/Tag/TenantTagTest.php
T
hamedandClaude Opus 4.8 76f9fbe88f feat(settings): complete remaining settings tabs (account, tags, turns)
Fill the three previously-placeholder settings sections so every menu item
is now a real page inside the settings shell:

- حساب کاربری: new authenticated POST /api/v1/user/change-password
  (verifies current password, ≥8 chars, must differ) + account page with a
  profile summary and change-password form.
- برچسب‌ها: new per-tenant TenantTag domain (entity/repo/controller +
  migration) with tenant-scoped CRUD at /api/v1/tenant-tag(s), plus a tags
  management page (list + color + add/edit/delete).
- مدیریت نوبت دهی: export the existing WeeklyScheduleTab from
  DoctorDetailPage and reuse it in a standalone AppointmentSettingsPage
  (current doctor's uuid + addresses).

Wire all three menu entries to their routes. Backend covered by PHPUnit
(change-password, tenant-tag CRUD + ownership); FE covered by Vitest.
API docs updated (auth.md, tag.md).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-13 14:16:21 +03:30

79 lines
2.6 KiB
PHP

<?php
namespace App\Tests\Tag;
use App\Doctor\Entity\Doctor;
use App\Tests\ApiTestCase;
/**
* Per-tenant tag CRUD, scoped to the caller's doctor/clinic entity.
*/
class TenantTagTest extends ApiTestCase
{
private function doctorUser(): array
{
$user = $this->createUser(['ROLE_DOCTOR']);
$doctor = new Doctor($user, 'دکتر');
$this->em->persist($doctor);
$this->em->flush();
return [$user, $doctor];
}
public function testCreateListUpdateDelete(): void
{
[$user] = $this->doctorUser();
// create
$created = $this->authJson('POST', '/api/v1/tenant-tag', $user, [
'name' => 'فوری', 'color' => '#FF0000',
]);
self::assertSame(201, $this->responseCode());
self::assertSame('فوری', $created['data']['name']);
self::assertSame('#FF0000', $created['data']['color']);
$uuid = $created['data']['uuid'];
// list
$list = $this->authJson('GET', '/api/v1/tenant-tags', $user);
self::assertSame(200, $this->responseCode());
self::assertSame('فوری', $list['data'][0]['name']);
// update
$this->authJson('PATCH', '/api/v1/tenant-tag/' . $uuid, $user, [
'name' => 'مهم', 'color' => '#00AA00', 'active' => false,
]);
self::assertSame(200, $this->responseCode());
// delete
$this->authJson('DELETE', '/api/v1/tenant-tag/' . $uuid, $user);
self::assertSame(200, $this->responseCode());
$after = $this->authJson('GET', '/api/v1/tenant-tags', $user);
self::assertCount(0, $after['data']);
}
public function testRejectsInvalidNameAndColor(): void
{
[$user] = $this->doctorUser();
$this->authJson('POST', '/api/v1/tenant-tag', $user, ['name' => '', 'color' => '#FF0000']);
self::assertSame(422, $this->responseCode());
$this->authJson('POST', '/api/v1/tenant-tag', $user, ['name' => 'ok', 'color' => 'red']);
self::assertSame(422, $this->responseCode());
}
public function testCannotTouchAnotherTenantsTag(): void
{
[$ownerA] = $this->doctorUser();
$created = $this->authJson('POST', '/api/v1/tenant-tag', $ownerA, ['name' => 'مال A', 'color' => '#123456']);
$uuid = $created['data']['uuid'];
[$ownerB] = $this->doctorUser();
$this->authJson('PATCH', '/api/v1/tenant-tag/' . $uuid, $ownerB, ['name' => 'دزدی']);
self::assertSame(404, $this->responseCode());
$this->authJson('DELETE', '/api/v1/tenant-tag/' . $uuid, $ownerB);
self::assertSame(404, $this->responseCode());
}
}