Files
portal/app/tests/Unit/Autopodbor/Study/YandexPhoneReverseExpanderTest.php
T
Дмитрий 9fce28fda8 feat(autopodbor): Яндекс-разворот по телефонам на шаге 2 (рядом с 2ГИС)
Для застройщиков, которые сидят только в Яндексе. По каждому номеру ищем в
Яндекс.Картах, но список рыхлый — поэтому КАЖДУЮ карточку открываем и оставляем
только те, где искомый номер реально есть. Это отсекает «Похожие места рядом»,
рекламу и рыхлые совпадения по бренду. Оба справочника объединяются
(CompositePhoneReverse), дубли по домену схлопываются.

Переиспользована готовая механика Яндекса: render-yandex-list.cjs (список) +
DirectoryParser::parseYandexCard (карточка). Браузерные адаптеры за интерфейсами
(YandexPhoneSearch/YandexCardReader) — логика TDD-ится на фейках; порог общей
линии считается по подтверждённым карточкам.

За отдельным тумблером AUTOPODBOR_PHONE_REVERSE_YANDEX (по умолчанию ВЫКЛ,
требует phone_reverse). Юнит 267/267, feature 150/150. План и находки —
docs/superpowers/{plans,findings}/2026-07-05-*.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-05 09:30:27 +03:00

94 lines
4.3 KiB
PHP

<?php
use App\Services\Autopodbor\Agent\Study\Yandex\YandexCardReader;
use App\Services\Autopodbor\Agent\Study\Yandex\YandexPhoneSearch;
use App\Services\Autopodbor\Agent\Study\YandexPhoneReverseExpander;
function fakeSearch(array $map): YandexPhoneSearch
{
return new class($map) implements YandexPhoneSearch
{
public function __construct(private array $map) {}
public function candidates(string $yandexSlug, string $phoneDigits): array
{
return $this->map[$phoneDigits] ?? [];
}
};
}
function fakeCards(array $map): YandexCardReader
{
return new class($map) implements YandexCardReader
{
public function __construct(private array $map) {}
public function read(string $cardUrl): ?array
{
return $this->map[$cardUrl] ?? null;
}
};
}
it('оставляет только карточку, где искомый номер РЕАЛЬНО есть (отсекает похожие/рыхлые)', function () {
$search = fakeSearch(['73912179941' => [
['name' => 'СМ.Сити', 'card_url' => 'https://yandex.ru/maps/org/sm/1/'],
['name' => 'Похожее СпецСтрой', 'card_url' => 'https://yandex.ru/maps/org/spec/2/'],
['name' => 'СМ Сити Капитанская', 'card_url' => 'https://yandex.ru/maps/org/smk/3/'],
]]);
$cards = fakeCards([
'https://yandex.ru/maps/org/sm/1/' => ['phones' => ['73912179941'], 'site' => 'https://sm-city.ru'],
'https://yandex.ru/maps/org/spec/2/' => ['phones' => ['73912990000'], 'site' => 'https://specstroy.ru'],
'https://yandex.ru/maps/org/smk/3/' => ['phones' => ['73912749569'], 'site' => 'https://smk.ru'],
]);
$exp = new YandexPhoneReverseExpander($search, $cards);
$res = $exp->expand('', ['73912179941'], [], '62/krasnoyarsk');
$domains = array_column($res->sites, 'domain');
expect($domains)->toContain('sm-city.ru')
->and($domains)->not->toContain('specstroy.ru')
->and($domains)->not->toContain('smk.ru');
});
it('пустой yandexSlug → разворот невозможен, пусто', function () {
$exp = new YandexPhoneReverseExpander(fakeSearch([]), fakeCards([]));
$res = $exp->expand('', ['73912179941'], [], '');
expect($res->sites)->toBe([])->and($res->phones)->toBe([]);
});
it('порог общей линии — если подтверждённых карточек больше порога, номер общий, пропускаем', function () {
$cands = [];
$cardsMap = [];
foreach (range(1, 5) as $i) {
$u = "https://yandex.ru/maps/org/o$i/$i/";
$cands[] = ['name' => "O$i", 'card_url' => $u];
$cardsMap[$u] = ['phones' => ['78001234567'], 'site' => "https://o$i.ru"];
}
$exp = new YandexPhoneReverseExpander(fakeSearch(['78001234567' => $cands]), fakeCards($cardsMap), crowdedCap: 4);
$res = $exp->expand('', ['78001234567'], [], '62/krasnoyarsk');
expect($res->sites)->toBe([]);
});
it('уже известный домен фирмы не повторяет', function () {
$search = fakeSearch(['73912179941' => [['name' => 'СМ', 'card_url' => 'https://yandex.ru/maps/org/sm/1/']]]);
$cards = fakeCards(['https://yandex.ru/maps/org/sm/1/' => ['phones' => ['73912179941'], 'site' => 'https://sm-city.ru']]);
$exp = new YandexPhoneReverseExpander($search, $cards);
$res = $exp->expand('', ['73912179941'], ['sm-city.ru'], '62/krasnoyarsk');
expect(array_column($res->sites, 'domain'))->not->toContain('sm-city.ru');
});
it('цепочка: телефон найденной карточки разворачивается дальше', function () {
$search = fakeSearch([
'73912179941' => [['name' => 'A', 'card_url' => 'https://yandex.ru/maps/org/a/1/']],
'73912000002' => [['name' => 'B', 'card_url' => 'https://yandex.ru/maps/org/b/2/']],
]);
$cards = fakeCards([
'https://yandex.ru/maps/org/a/1/' => ['phones' => ['73912179941', '73912000002'], 'site' => 'https://a.ru'],
'https://yandex.ru/maps/org/b/2/' => ['phones' => ['73912000002'], 'site' => 'https://b-proekt.ru'],
]);
$exp = new YandexPhoneReverseExpander($search, $cards);
$res = $exp->expand('', ['73912179941'], [], '62/krasnoyarsk');
expect(array_column($res->sites, 'domain'))->toContain('b-proekt.ru');
});