Files
portal/app/tests/Feature/Autopodbor/StudyPerElementTest.php
T
Дмитрий 50d6da5931 feat(autopodbor): шаг 2 изучает каждый элемент конкурента отдельно
Глубокое изучение строит отпечаток на КАЖДЫЙ элемент холдинга - имя элемента плюс
его первый сайт - и сводит телефоны со всех. Без элементов - как раньше.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-04 18:39:37 +03:00

85 lines
3.1 KiB
PHP

<?php
declare(strict_types=1);
use App\Services\Autopodbor\Agent\Dto\StudyCompetitorRequest;
use App\Services\Autopodbor\Agent\Fetch\FetchedSite;
use App\Services\Autopodbor\Agent\Fetch\Fetcher;
use App\Services\Autopodbor\Agent\FakeCompetitorAgent;
use App\Services\Autopodbor\Agent\RealCompetitorAgent;
use App\Services\Autopodbor\Agent\Study\Fingerprint;
use App\Services\Autopodbor\Agent\Study\SourceCollector;
/** Фейк-собиратель: запоминает отпечатки и отдаёт по строке-телефону на каждый. */
class FakeStudyCollector implements SourceCollector
{
/** @var list<Fingerprint> */
public array $seen = [];
public function collect(Fingerprint $fp): array
{
$this->seen[] = $fp;
return [[
'signal_type' => 'call', 'identifier' => 'phone-'.$fp->name,
'phone_kind' => 'real', 'phone_type' => 'city',
'provenance_url' => null, 'provenance_label' => $fp->name,
'where_found' => [], 'office' => null, 'confirmations' => 1,
]];
}
}
/** Фетчер-заглушка: в глубоком пути не вызывается. */
class NullStudyFetcher implements Fetcher
{
public function site(string $url): FetchedSite
{
throw new \LogicException('not used in deep path');
}
public function directory(string $url): array
{
return [];
}
}
function studyAgent(FakeStudyCollector $c): RealCompetitorAgent
{
return new RealCompetitorAgent(new NullStudyFetcher, new FakeCompetitorAgent, deep: $c);
}
it('глубокое изучение строит отпечаток на КАЖДЫЙ элемент и сводит строки', function () {
config(['autopodbor.deep_study' => true]);
$c = new FakeStudyCollector;
$res = studyAgent($c)->studyCompetitor(new StudyCompetitorRequest(
competitor: [
'name' => 'Сибиряк',
'is_federal' => false,
'elements' => [
['name' => 'Нанжуль', 'sites' => ['nanzhul.ru'], 'cards' => []],
['name' => 'Плодово', 'sites' => ['plodovo.ru'], 'cards' => []],
],
],
regionCode: 24,
));
expect(array_map(fn (Fingerprint $fp) => $fp->name, $c->seen))->toBe(['Нанжуль', 'Плодово'])
->and(array_map(fn (Fingerprint $fp) => $fp->seedDomain, $c->seen))->toBe(['nanzhul.ru', 'plodovo.ru'])
->and(collect($res->sources)->pluck('identifier')->all())->toBe(['phone-Нанжуль', 'phone-Плодово']);
});
it('без элементов — один отпечаток из имени+сайта (обратная совместимость)', function () {
config(['autopodbor.deep_study' => true]);
$c = new FakeStudyCollector;
studyAgent($c)->studyCompetitor(new StudyCompetitorRequest(
competitor: ['name' => 'Одиночка', 'site_url' => 'one.ru', 'is_federal' => false],
regionCode: 24,
));
expect($c->seen)->toHaveCount(1)
->and($c->seen[0]->name)->toBe('Одиночка')
->and($c->seen[0]->seedDomain)->toBe('one.ru');
});