46426d586e
Фазы 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>
73 lines
3.5 KiB
PHP
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([]);
|
|
}
|
|
});
|