f298984055
Компоненты:
- 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.
37 lines
1.2 KiB
PHP
37 lines
1.2 KiB
PHP
<?php
|
|
|
|
declare(strict_types=1);
|
|
|
|
use App\Services\Supplier\PlaywrightBridge;
|
|
use Illuminate\Support\Facades\Cache;
|
|
|
|
beforeEach(function () {
|
|
config([
|
|
'services.supplier.login' => 'test_login',
|
|
'services.supplier.password' => 'test_password',
|
|
'services.supplier.portal_url' => 'https://crm.bp-gr.ru',
|
|
]);
|
|
Cache::store('redis')->forget('supplier:session');
|
|
});
|
|
|
|
afterEach(function () {
|
|
Cache::store('redis')->forget('supplier:session');
|
|
});
|
|
|
|
test('command supplier:session:refresh dispatches job synchronously and writes cache', function () {
|
|
$bridge = Mockery::mock(PlaywrightBridge::class);
|
|
/** @var PlaywrightBridge $bridge */
|
|
$bridge->shouldReceive('refreshSession')->andReturn([
|
|
'phpsessid' => 'cmd_sess',
|
|
'csrf' => 'cmd_csrf',
|
|
'refreshed_at' => '2026-05-11T10:00:00Z',
|
|
]);
|
|
app()->instance(PlaywrightBridge::class, $bridge);
|
|
|
|
// @phpstan-ignore-next-line method.notFound (Pest TestCall->artisan() mixin)
|
|
$this->artisan('supplier:session:refresh')->assertExitCode(0);
|
|
|
|
expect(Cache::store('redis')->get('supplier:session'))->toBeArray()
|
|
->and(Cache::store('redis')->get('supplier:session')['phpsessid'])->toBe('cmd_sess');
|
|
});
|