Files
portal/app/tests/Unit/Supplier/Stubs/ThrowingRefreshSupplierSessionJob.php
T
Дмитрий f298984055 feat(supplier): Plan 3 Task 5 — RefreshSupplierSessionJob + PlaywrightBridge
Компоненты:
- app/playwright/{package.json, refresh-session.js} — изолированный Node.js
  + Playwright chromium subprocess для headless логина
- PlaywrightProcessHandle interface + SymfonyPlaywrightProcessHandle (prod) +
  StubPlaywrightProcessHandle (test) для DI без extending Symfony Process
- ProcessFactory + SymfonyProcessFactory
- PlaywrightBridge: PHP-обёртка, timeout 75s, JSON contract, exit code
  → SupplierAuthException
- RefreshSupplierSessionJob: stub → real (tries=3, backoff [2m/10m/30m],
  Cache::lock concurrent guard, Redis TTL 6h)
- supplier:session:refresh Console command
- AppServiceProvider binds ProcessFactory → SymfonyProcessFactory

+7 tests (4 PlaywrightBridge + 2 Job + 1 Command).

NOTE: DOM-селекторы placeholder — финализация после Task 1 discovery.
NOTE: app/playwright/node_modules в .gitignore.

Quirks resolved:
- Mockery::mock(Process::class) + laravel/pao = stream_filter_remove fatal.
  Решение: handle interface, pure-PHP test stub без extends Process.
- PHPStan Mockery union types — baseline entries (known Mockery+PHPStan compat).

KNOWN LIMITATION: на этой Windows машине pao stream filter conflict при
serial run SupplierPortalClient+RefreshSupplierSessionJob combo.
Tests pass individually + парами. Production Linux CI не affected.
2026-05-11 06:46:13 +03:00

33 lines
981 B
PHP

<?php
declare(strict_types=1);
namespace Tests\Unit\Supplier\Stubs;
use App\Jobs\Supplier\RefreshSupplierSessionJob;
use App\Services\Supplier\PlaywrightBridge;
use RuntimeException;
/**
* Test stub: simulates Task 5 Playwright failure by throwing a deterministic
* RuntimeException from handle(). Used in SupplierPortalClientTest to verify
* SupplierPortalClient correctly translates raw exceptions from the refresh
* job into typed SupplierAuthException (preserves error taxonomy).
*
* Cannot be an anonymous class because Laravel's dispatchSync serializes the
* job (SerializesModels trait), and anonymous classes cannot be serialized.
*/
class ThrowingRefreshSupplierSessionJob extends RefreshSupplierSessionJob
{
public function __construct(
public readonly string $simulatedMessage,
) {
//
}
public function handle(?PlaywrightBridge $bridge = null): void
{
throw new RuntimeException($this->simulatedMessage);
}
}