Ф1Ф2' .'дубльне филиал'; $links = (new DirectoryParser)->parseBranchList($html); expect($links)->toBe(['/krasnoyarsk/firm/111', '/krasnoyarsk/firm/222']); }); it('берёт ссылки на филиалы, даже когда они в данных страницы, а не в href', function () { // 2ГИС иногда рендерит карточки без чистого href — ссылка лежит в JSON-состоянии страницы $html = '{"items":[{"link":"/krasnoyarsk/firm/111"},{"link":"/krasnoyarsk/firm/222"}]}' .'дубль'; $links = (new DirectoryParser)->parseBranchList($html); expect($links)->toBe(['/krasnoyarsk/firm/111', '/krasnoyarsk/firm/222']); }); it('из карточки 2ГИС берёт телефон из tel: и адрес из заголовка', function () { $html = 'КрасЛомбард, улица Ладо Кецховели, 30, Красноярск — 2ГИС' .'

КрасЛомбард

+7 (391) 2...'; $cards = (new DirectoryParser)->parseFirmCard($html, 'https://2gis.ru/krasnoyarsk/firm/111', '2ГИС'); expect($cards)->toHaveCount(1); expect($cards[0]->number)->toBe('+73912920000'); expect($cards[0]->office)->toBe('улица Ладо Кецховели, 30'); expect($cards[0]->url)->toBe('https://2gis.ru/krasnoyarsk/firm/111'); expect($cards[0]->source)->toBe('2ГИС'); }); it('схлопывает неразрывные/двойные пробелы в адресе из заголовка', function () { $html = "КрасЛомбард,\u{00A0}улица Весны,\u{00A0}7а, Красноярск — 2ГИС" .'x'; $cards = (new DirectoryParser)->parseFirmCard($html, 'u', '2ГИС'); expect($cards[0]->office)->toBe('улица Весны, 7а'); }); // ── Яндекс.Карты ──────────────────────────────────────────────────────────── it('parseYandexCard: извлекает телефон из div orgpage-phones-view и сайт из business-urls-link', function () { $html = <<<'HTML' Автодом24, микрофинансовая организация, Красноярск, Караульная ул., 88 — Яндекс Карты
+7 (913) 539-65-46
HTML; $cards = (new DirectoryParser)->parseYandexCard($html, 'https://yandex.ru/maps/org/avtodom24/8905494012/'); expect($cards)->not->toBeEmpty(); // Номер хранится в сыром виде «+7 (913) 539-65-46», проверяем по цифрам $digitsAll = implode('', array_map(fn ($c) => preg_replace('/\D/', '', $c->number), $cards)); expect($digitsAll)->toContain('9135396546'); expect($cards[0]->siteUrl)->toContain('automoney-krsk.ru'); expect($cards[0]->source)->toBe('Яндекс.Карты'); }); it('parseYandexCard: дедуп телефонов — wa.me не дублирует основной номер', function () { $html = <<<'HTML' Автодом24, микрофинансовая организация, Красноярск, Красная ул., 1 — Яндекс Карты
+7 (913) 539-65-46
HTML; $cards = (new DirectoryParser)->parseYandexCard($html, 'https://yandex.ru/maps/org/avtodom24/1/'); // wa.me не должен дублировать тот же номер expect($cards)->toHaveCount(1); expect($cards[0]->siteUrl)->toContain('automoney-krsk.ru'); }); it('parseYandexCard: если телефонов нет но сайт есть — одна карточка с пустым number', function () { $html = <<<'HTML' Тест, Красноярск — Яндекс Карты
HTML; $cards = (new DirectoryParser)->parseYandexCard($html, 'https://yandex.ru/maps/org/test/1/'); expect($cards)->toHaveCount(1); expect($cards[0]->number)->toBe(''); expect($cards[0]->siteUrl)->toContain('example.com'); expect($cards[0]->source)->toBe('Яндекс.Карты'); }); it('parseYandexCard: нет ни телефона, ни сайта — возвращает пустой массив', function () { $html = 'Тест — Яндекс Карты
нет контактов
'; $cards = (new DirectoryParser)->parseYandexCard($html, 'https://yandex.ru/maps/org/test/2/'); expect($cards)->toBe([]); }); it('parseYandexCard: адрес офиса берётся из заголовка страницы Яндекса', function () { $html = <<<'HTML' Автодом24, микрофинансовая организация, Красноярск, Караульная ул., 88 — Яндекс Карты
+7 (913) 539-65-46
HTML; $cards = (new DirectoryParser)->parseYandexCard($html, 'https://yandex.ru/maps/org/avtodom24/1/'); expect($cards)->not->toBeEmpty(); // officeFromTitle должен отрезать «Автодом24» и «Яндекс Карты», оставить «микрофинансовая организация, Красноярск, Караульная ул., 88» // Точнее: первый кусок = имя, последний = город; середина = адрес expect($cards[0]->office)->not->toBeNull(); }); // ── 2ГИС «вскрыть всё»: сайт + все телефоны + описание из карточки ─────────── it('parse2gisCard: сайт берёт из поля url объекта-контакта website, НЕ из value-редиректа', function () { // Контакты 2ГИС — JSON-массив объектов. У сайта настоящий адрес в "url", // а в "value" — редирект link.2gis.ru (его брать нельзя). $html = 'AutoMoney, Красноярск, Ленина, 1 — 2ГИС' .'{"url":"http://automoney-krsk.ru","text":"automoney-krsk.ru","code":"70000001093406076","type":"website","value":"http://link.2gis.ru/redirect/xxx"}' .'{"contact_text":"+7‒913‒539‒65‒46","type":"phone","value":"+79135396546"}'; $cards = (new DirectoryParser)->parse2gisCard($html, 'https://2gis.ru/krasnoyarsk/firm/111'); expect($cards)->not->toBeEmpty(); expect($cards[0]->siteUrl)->toContain('automoney-krsk.ru'); expect($cards[0]->siteUrl)->not->toContain('link.2gis.ru'); expect($cards[0]->source)->toBe('2ГИС'); }); it('parse2gisCard: берёт ВСЕ телефоны из value объектов phone, без дублей', function () { $html = 'Тест, Красноярск — 2ГИС' .'{"contact_text":"+7 391 279-33-79","type":"phone","value":"+73912793379"}' .'{"contact_text":"+7 391 296-01-11","type":"phone","value":"+73912960111"}' .'{"contact_text":"+7 391 240-00-68","type":"phone","value":"+73912400068"}' .'{"type":"phone","value":"+73912793379"}'; // дубль первого $cards = (new DirectoryParser)->parse2gisCard($html, 'https://2gis.ru/krasnoyarsk/firm/222'); $digits = array_map(fn ($c) => preg_replace('/\D/', '', $c->number), $cards); expect($digits)->toContain('73912793379'); expect($digits)->toContain('73912960111'); expect($digits)->toContain('73912400068'); expect(array_unique($digits))->toHaveCount(3); }); it('parse2gisCard: достаёт описание «чем занимается» из og:description', function () { $html = 'AutoMoney, Красноярск — 2ГИС' .'' .'{"contact_text":"+7 913 539-65-46","type":"phone","value":"+79135396546"}'; $cards = (new DirectoryParser)->parse2gisCard($html, 'https://2gis.ru/krasnoyarsk/firm/333'); expect($cards)->not->toBeEmpty(); expect($cards[0]->description)->toContain('Займы под залог'); }); it('parse2gisCard: НЕ берёт служебную заглушку 2ГИС в описание (оценка/фото/отзывы)', function () { $html = 'AutoMoney, Красноярск — 2ГИС' .'' .'{"contact_text":"+7 913 539-65-46","type":"phone","value":"+79135396546"}'; $cards = (new DirectoryParser)->parse2gisCard($html, 'https://2gis.ru/krasnoyarsk/firm/xx'); expect($cards)->not->toBeEmpty(); expect($cards[0]->description)->toBeNull(); // заглушку не пишем }); it('parse2gisCard: рубрика из заголовка идёт в описание, когда своего описания нет', function () { // og-описания нет → «чем занимается» берём из рубрики (2-й кусок заголовка): «Имя, РУБРИКА, адрес…, Город». $html = 'Ломбарджини, ломбард, Взлётная улица, 6а, Красноярск — 2ГИС' .'{"url":"http://lombardzhini.ru","text":"x","code":"1","type":"website"}'; $cards = (new DirectoryParser)->parse2gisCard($html, 'https://2gis.ru/krasnoyarsk/firm/1'); expect($cards[0]->description)->toBe('ломбард'); }); it('parse2gisCard: 2-й кусок-адрес НЕ считается рубрикой (описание пустое)', function () { // «КрасЛомбард, улица Ладо Кецховели, 30, Красноярск» — 2-й кусок это АДРЕС, не рубрика → описания нет. $html = 'КрасЛомбард, улица Ладо Кецховели, 30, Красноярск — 2ГИС' .'{"url":"http://k.ru","text":"x","code":"1","type":"website"}'; $cards = (new DirectoryParser)->parse2gisCard($html, 'https://2gis.ru/krasnoyarsk/firm/2'); expect($cards[0]->description)->toBeNull(); }); it('parseYandexCard: рубрика из заголовка идёт в описание', function () { $html = 'Твои Займы, микрофинансовая организация, Ястынская ул., 19А, Красноярск — Яндекс Карты' .''; $cards = (new DirectoryParser)->parseYandexCard($html, 'https://yandex.ru/maps/org/tvoi_zaymy/1/'); expect($cards[0]->description)->toBe('микрофинансовая организация'); }); it('parse2gisCard: мусор-домены из ' .'' .'{"url":"http://realsite.рф","text":"realsite.рф","code":"1","type":"website","value":"http://link.2gis.ru/y"}' .'{"contact_text":"+7 391 200-00-00","type":"phone","value":"+73912000000"}'; $cards = (new DirectoryParser)->parse2gisCard($html, 'https://2gis.ru/krasnoyarsk/firm/444'); expect($cards[0]->siteUrl)->toContain('realsite'); expect($cards[0]->siteUrl)->not->toContain('top100'); expect($cards[0]->siteUrl)->not->toContain('mc.yandex'); }); it('parse2gisCard: телефонов нет, но сайт есть — одна карточка с пустым number', function () { $html = 'Тест, Красноярск — 2ГИС' .'{"url":"http://onlysite.ru","text":"onlysite.ru","code":"1","type":"website","value":"http://link.2gis.ru/z"}'; $cards = (new DirectoryParser)->parse2gisCard($html, 'https://2gis.ru/krasnoyarsk/firm/555'); expect($cards)->toHaveCount(1); expect($cards[0]->number)->toBe(''); expect($cards[0]->siteUrl)->toContain('onlysite.ru'); }); it('parse2gisCard: нет ни телефона, ни сайта — пустой массив', function () { $html = 'Тест — 2ГИС
нет контактов
'; $cards = (new DirectoryParser)->parse2gisCard($html, 'https://2gis.ru/krasnoyarsk/firm/666'); expect($cards)->toBe([]); }); it('parseYandexCard: достаёт ВСЕ три телефона из скрытого JSON, без дублей', function () { // Яндекс показывает только первый телефон в видимом блоке, // остальные прячет за раскрывашкой — но все три лежат в JSON на той же странице. $html = <<<'HTML' Автокредит24, Красноярск, Взлётная ул., 5 — Яндекс Карты
+7 (391) 279-33-79
HTML; $cards = (new DirectoryParser)->parseYandexCard($html, 'https://yandex.ru/maps/org/autocredit24/1/'); // Должны получить ровно 3 карточки (по одной на телефон) expect($cards)->toHaveCount(3); // Проверяем по цифрам (без +, скобок и т.п.) $allDigits = array_map(fn ($c) => preg_replace('/\D/', '', $c->number), $cards); expect($allDigits)->toContain('73912793379'); expect($allDigits)->toContain('73912960111'); expect($allDigits)->toContain('73912400068'); // Нет дублей expect(array_unique($allDigits))->toHaveCount(3); // Сайт присутствует у каждой карточки foreach ($cards as $card) { expect($card->siteUrl)->toContain('autocredit24.ru'); } }); it('parse2gisCard: НЕ берёт рекламный телефон-кнопку (caption/platforms), только настоящий контакт', function () { // Живой случай: на карточке «Ломбард Бодрый» 2ГИС показал рекламный блок «Связаться с // менеджером» — это кнопка-действие ЧУЖОЙ фирмы (Ломбард Айклауд). У неё caption/platforms и // НЕТ code/print_text. Её номер брать нельзя: иначе чужой телефон попадает в контакты Бодрого // и на «Предложениях» даёт ложное «объединить?». $html = 'Ломбард Бодрый, ломбард, Красноярск — 2ГИС' // настоящий контакт фирмы: с code (id) и print_text .'{"text":"+7 (391) 296-78-88","code":"70000001085640830","print_text":"+7 (391) 296-78-88","type":"phone","value":"+73912967888"}' // рекламная кнопка чужой фирмы: caption + platforms, без code/print_text .'{"caption":"Связаться с менеджером","name":"Связаться с менеджером","platforms":["ios","android","online"],"type":"phone","value":"+79237575575"}'; $cards = (new DirectoryParser)->parse2gisCard($html, 'https://2gis.ru/krasnoyarsk/firm/70000001085640828'); $digits = array_map(fn ($c) => preg_replace('/\D/', '', $c->number), $cards); expect($digits)->toContain('73912967888'); // настоящий телефон Бодрого — берём expect($digits)->not->toContain('79237575575'); // рекламный номер Айклауда — НЕ берём });