Files
portal/app/tests/Unit/Autopodbor/Extract/TwoGisJsonReaderTest.php
T
Дмитрий 46426d586e feat(autopodbor): шов TwoGisReader + HtmlTwoGisReader + TwoGisJsonReader (TDD)
Фазы 2-3 плана self-render. Только новые файлы — существующий код не тронут,
xf4-путь цел. 281/281 юнит-тестов зелёные, Pint чисто.

- TwoGisReader — интерфейс разбора 2ГИС (3 метода: listing/card/branchList),
  единый контракт поверх HTML (xf4) ИЛИ initialState-JSON (self-render).
- HtmlTwoGisReader — xf4-путь: тонкий делегат к CategoryListingParser/
  DirectoryParser, поведение 1:1 (4 теста контракт-идентичности на реальных
  фикстурах 2gis-*-kraslombard).
- TwoGisJsonReader — self-render путь: разбор window.initialState по карте
  путей спайка (pagination-список → entity.profile), фильтр type=branch
  (фирма-в-фирму, без зданий/улиц). 5 тестов на реальных фикстурах: 12 фирм
  листинга, телефон+сайт карточки, 2 пути поиска-по-телефону, деградация.

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

73 lines
3.5 KiB
PHP

<?php
declare(strict_types=1);
use App\Services\Autopodbor\Agent\Extract\TwoGisJsonReader;
use App\Services\Autopodbor\Agent\Fetch\DirectoryCard;
// TwoGisJsonReader — self-render путь шва: из window.initialState 2ГИС отдаёт ТОТ ЖЕ контракт, что
// HTML-парсеры. Тесты на РЕАЛЬНЫХ фикстурах спайка 05.07 (tests/fixtures/autopodbor/2gis/).
// Карта JSON-путей — docs/superpowers/findings/2026-07-05-2gis-initialstate-spike.md.
beforeEach(function () {
$this->reader = new TwoGisJsonReader;
$this->listing = file_get_contents(base_path('tests/fixtures/autopodbor/2gis/listing.initialstate.json'));
$this->card = file_get_contents(base_path('tests/fixtures/autopodbor/2gis/card.initialstate.json'));
$this->phone = file_get_contents(base_path('tests/fixtures/autopodbor/2gis/phone.initialstate.json'));
});
// --- ЛИСТИНГ ---
it('listing: чистый список фирм в порядке ранга (фирма-в-фирму, без мусора)', function () {
$rows = $this->reader->listing($this->listing);
expect($rows)->toHaveCount(12)
->and($rows[0])->toEqual([
'name' => 'Ломбардико',
'card_url' => 'https://2gis.ru/krasnoyarsk/firm/70000001052966157',
'site' => null, // в листинге контактов нет — сайт из карточки
]);
// все имена — настоящие фирмы (ломбарды/микрозаймы), без «Бургер Кинг»/зданий
$names = array_column($rows, 'name');
expect($names)->toContain('КрасЛомбард')
->and(implode('|', $names))->not->toContain('Бургер');
});
it('listing: форма контракта = {name, card_url, site} — как CategoryListingParser', function () {
foreach ($this->reader->listing($this->listing) as $row) {
expect(array_keys($row))->toBe(['name', 'card_url', 'site']);
}
});
// --- КАРТОЧКА ---
it('card: телефон из value + сайт из url объекта-контакта, source 2ГИС', function () {
$url = 'https://2gis.ru/krasnoyarsk/firm/70000001052966157';
$cards = $this->reader->card($this->card, $url);
expect($cards)->not->toBeEmpty()
->and($cards[0])->toBeInstanceOf(DirectoryCard::class)
->and($cards[0]->source)->toBe('2ГИС')
->and($cards[0]->url)->toBe($url)
->and($cards[0]->siteUrl)->toContain('ломбардико-24.рф');
// телефон +79509744052 присутствует
$numbers = array_map(fn (DirectoryCard $c): string => preg_replace('/\D/', '', $c->number), $cards);
expect($numbers)->toContain('79509744052');
});
// --- ПОИСК ПО ТЕЛЕФОНУ ---
it('branchList: пути карточек холдинга (как parseBranchList)', function () {
$paths = $this->reader->branchList($this->phone);
expect($paths)->toHaveCount(2)
->and($paths)->toContain('/krasnoyarsk/firm/70000001052966157')
->and($paths)->toContain('/krasnoyarsk/firm/70000001052966076');
});
// --- ДЕГРАДАЦИЯ ---
it('пустой/битый JSON → пустой массив по всем трём (не падает)', function () {
foreach (['', '<html>не json</html>', '{}', '{"data":{}}'] as $bad) {
expect($this->reader->listing($bad))->toBe([])
->and($this->reader->branchList($bad))->toBe([])
->and($this->reader->card($bad, 'https://2gis.ru/x/firm/1'))->toBe([]);
}
});