Files
portal/app/tests/Unit/Supplier/SupplierProjectDtoTest.php
T
Дмитрий a8a23cb269 fix(supplier): Plan 3 Task 4 code-review fixes (4 Important defense-in-depth)
Закрывает 4 Important issues из code-review Task 4 (a2c5374):
- #1 SupplierPortalClient: parse_url host validation → SupplierClientException
  вместо silent cookie skip + false-positive SupplierAuthException
- #2 dispatch_sync(RefreshSupplierSessionJob) обёрнут try/catch (request retry +
  loadSession) → raw exceptions translated в SupplierAuthException для
  consistency с error taxonomy перед Task 5 real Playwright impl
- #3 RefreshSupplierSessionJob stub handle() теперь throws LogicException
  с понятным сообщением (вместо silent no-op → confusing 'cache still empty'
  error). После Task 5 — LogicException заменяется real Playwright code.
  Снят final-модификатор класса (test override через container bind + Laravel
  dispatchSync serialization не работает с anonymous classes).
- #5 SupplierProjectDto::equals → canonical order для workdays/regions
  через sort в constructor (defense vs PG jsonb non-deterministic order).
  Без этого Task 6 SyncJob false-positive обнаруживал бы diff где его нет
  → unnecessary updateProject HTTP calls.

+3 tests в SupplierPortalClientTest (malformed url, 2 retry-translation paths)
+2 tests в новом SupplierProjectDtoTest (order-independent equals + non-equal)
+1 stub-класс ThrowingRefreshSupplierSessionJob (anonymous classes несовместимы
  с SerializesModels trait в dispatchSync).

Pest: 38/38 supplier-suite, 574/574 full suite (576 total, 2 skipped, +5 new
tests vs Task 4 baseline). PHPStan 0 errors. Pint clean.
2026-05-11 06:46:13 +03:00

60 lines
1.6 KiB
PHP

<?php
declare(strict_types=1);
use App\Services\Supplier\Dto\SupplierProjectDto;
use Tests\TestCase;
uses(TestCase::class);
test('SupplierProjectDto::equals returns true for same fields regardless of workdays/regions input order', function (): void {
$dto1 = new SupplierProjectDto(
platform: 'B1',
signalType: 'site',
uniqueKey: 'a.com',
limit: 5,
workdays: [1, 2, 3],
regions: [50, 77],
regionsReverse: false,
status: 'active',
);
$dto2 = new SupplierProjectDto(
platform: 'B1',
signalType: 'site',
uniqueKey: 'a.com',
limit: 5,
workdays: [3, 1, 2], // same set, different order
regions: [77, 50], // same set, different order
regionsReverse: false,
status: 'active',
);
expect($dto1->equals($dto2))->toBeTrue()
->and($dto2->equals($dto1))->toBeTrue(); // symmetry
});
test('SupplierProjectDto::equals returns false when limit differs', function (): void {
$dto1 = new SupplierProjectDto(
platform: 'B1',
signalType: 'site',
uniqueKey: 'a.com',
limit: 5,
workdays: [1, 2, 3],
regions: [],
regionsReverse: false,
status: 'active',
);
$dto2 = new SupplierProjectDto(
platform: 'B1',
signalType: 'site',
uniqueKey: 'a.com',
limit: 6, // differs
workdays: [1, 2, 3],
regions: [],
regionsReverse: false,
status: 'active',
);
expect($dto1->equals($dto2))->toBeFalse();
});